UE4安卓打aab包时,同时存在“gradle”、“arm64/gradle”两个Gradle工程的原因
两个Gradle工程的现象
在出安卓aab包时,观察到存在以下两个Gradle工程:
1、Intermediate\Android\arm64\gradle (称为arm64的Gradle)
2、Intermediate\Android\gradle(称为根下的Gradle)

它们存在一些小的差异。下面是“为何有两个Gradle工程”的结论。
原因
1、假设指定了若干种架构,那么就会有多个子目录。在我们的例子中,仅存在 arm64目录。(以及根部的 gradle目录,这是你所知道的)
2、如果“差异不大”,UE4就会统一采用 gradle目录来打aab,来作为所有架构的aab。我们的例子中,就属于这种情况。代码里叫做“bCombinedBundleOK”,即统一打根部gradle来打出aab。
3、下面情况属于“差异大”:
● arm64目录缺乏它的gradle目录。代码搜“Source directory missing”
● arm64目录/Gradle目录的 “AndroidManifest.xml”在某些属性上存在差异,细节太细不用管。代码搜“AndroidManifest.xml files differ too much”
● arm64目录/Gradle目录的 “gradle.properties”在某些属性上存在差异,细节太细不用管。代码搜“Gradle projects differ too much”
● 有更加多的未知差异。代码搜“Gradle projects differ too much”
4、上面四种情况对应的日志都没搜到,说明 bCombinedBundleOK (差异不大)
结论:最终打出aab时,确实没用上 arm64 架构目录。打包只使用了gradle目录。
代码示意图

关键代码与日志
请打开UEDeployAndroid.cs:MakeApk() 方法,针对上图的一些代码,做下面的解释:
1、UnrealBuildTool.UEDeployAndroid.MakeApk()
打aab|apks 或打apk的入口函数。
2、foreach (Tuple<string, string, string> build in BuildList)
在我的项目案例中,只有 arm64 。接下来的若干代码要点,处在该循环中,实际上只跑了一次(即arm64)。
3、(在循环中)
string UE4BuildPath = Path.Combine(IntermediateAndroidPath, Arch.Substring(1).Replace("-", "_"));
// 这个值是:{项目}\Intermediate\Android\arm64
4、(在循环中)
// check to see if libUE4.so needs to be copied
if (BuildListComboTotal > 1 || FilesAreDifferent(SourceSOName, FinalSOName))
{ // 没有执行Log.TraceInformation("\nCopying new .so {0} file to jni folder...", SourceSOName);Directory.CreateDirectory(JniDir);// copy the binary to the standard .so locationFile.Copy(SourceSOName, FinalSOName, true);Log.TraceWarning("// *Gradle* SourceSOName {0} copy to ->> FinalSOName {1}", SourceSOName, FinalSOName);// SourceSOName D:\项目\Binaries\Android\项目-Android-Test-arm64.so 拷贝给:// D:\项目\Intermediate\Android\arm64\jni\arm64-v8a\libUE4.so ✔// 案例中,没有拷贝,被增量跳过了。File.SetLastWriteTimeUtc(FinalSOName, File.GetLastWriteTimeUtc(SourceSOName));
}// remove any read only flags
FileInfo DestFileInfo = new FileInfo(FinalSOName);
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
File.SetLastWriteTimeUtc(FinalSOName, File.GetLastWriteTimeUtc(SourceSOName));Log.TraceWarning("// *Gradle* SourceSOName {0} DestApkName {1}, FinalSOName {2}", SourceSOName, DestApkName, FinalSOName);
// 实际是:2024-10-28 21:17:08:726 : WARNING:
// // *Gradle* SourceSOName D:\项目\Binaries\Android\项目-Android-Test-arm64.so
// DestApkName D:\项目\Binaries\Android\项目-Android-Test-arm64.apk,
// FinalSOName D:\项目/Intermediate\Android\arm64/jni/arm64-v8a/libUE4.so
拷贝libUE4.so,这是一个重要的符号表文件。
5、 (在循环中)
File.Copy(Path.Combine(UE4BuildPath, "AndroidManifest.xml"), GradleManifest, true);
// 应该是指: 项目\Intermediate\Android\arm64/AndroidManifest.xml 拷贝给 项目\Intermediate\Android\arm64\gradle\app\src\main\AndroidManifest.xml
AndroidManifest.xml 是什么?下面是AI的解答:
`AndroidManifest.xml` 文件是 Android 应用程序项目中的一个关键配置文件。它位于应用项目的根目录下,并定义了应用的元数据、组件、所需权限、硬件和软件功能需求等信息。以下是 `AndroidManifest.xml` 文件通常包含的内容:
1. **包名** (`package`): 应用程序的唯一标识符,通常是反向的域名格式。
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
```
2. **应用标签** (`<application>`): 这是 `AndroidManifest.xml` 的主要部分,包含应用的所有组件和属性。
- **应用名称** (`android:label`): 显示给用户的应用名称。
- **应用图标** (`android:icon`): 应用的图标资源。
- **主题** (`android:theme`): 应用的主题样式。
3. **活动** (`<activity>`): 应用中的一个界面屏幕,通常用于与用户交互。
- **意图过滤器** (`<intent-filter>`): 定义了哪些意图可以启动该活动,例如默认启动的 `MAIN` 动作和 `LAUNCHER` 类别。
4. **服务** (`<service>`): 执行后台操作的组件。
5. **广播接收器** (`<receiver>`): 用于响应系统级广播的组件。
6、(在循环中)
CleanCopyDirectory(Path.Combine(UE4BuildPath, "assets"), Path.Combine(UE4BuildGradleMainPath, "assets")); // D:\项目\Intermediate\Android\arm64 /assets 等 拷贝给 项目\Intermediate\Android\arm64 / gradle/src/mainCleanCopyDirectory(Path.Combine(UE4BuildPath, "res"), Path.Combine(UE4BuildGradleMainPath, "res"));CleanCopyDirectory(Path.Combine(UE4BuildPath, "src"), Path.Combine(UE4BuildGradleMainPath, "java")); // Path.Combine(UE4BuildGradleAppPath, "src", "main");
Intermediate\Android\arm64/assets (res,src) 等 拷贝给
Intermediate\Android\arm64/gradle/src/main/assets (res,java)
7、
foreach (string Filename in SourceFiles) // 这些文件是 D:\项目\Intermediate\Android\arm64\gradle 中的文件
{ ……Log.TraceWarning("// *Gradle* (4016), Filenam: {0}", Filename); // 几乎遍历了每一个arm64里的文件 D:\项目\Intermediate\Android\arm64\gradle\app\src\main\libs\x86_64\libtgpa.soif (!File.Exists(DestFilename)){ File.Copy(Filename, DestFilename);}// 其中// Source是 Intermediate/Android\arm64\gradle 中的文件// Dest是 Intermediate/Android\gradle 中的同名文件if (Filename.EndsWith("AndroidManifest.xml")){... 某些关键点的比对,省略bCombinedBundleOK = false; // 若确认差异很大,就认定为“不可CombindBundle”Log.TraceInformation("AndroidManifest.xml files differ too much to combine for single AAB: '{0}' != '{1}'", Filename, DestFilename);break;}…… gradle.properties的比对,同上,若差异很大,可能认定为“不可CombindBundle”。…… 其它原因差异很大,可能认定为“不可CombindBundle”。省略……
}
从 arm64\gradle 复制文件给 根gradle。并判断是否“差异大”。
8、
if (bCombinedBundleOK)
{UnrealBuildTool.UEDeployAndroid.CreateRunGradle()
创建 rungradle.batRunCommandLineProgramWithExceptionAndFiltering()
打印 Making .aab with Gradle..
调用Gradle打包} else { 略 }
在我的项目案例中,根gradle和arm64/gradle “差异不大”,将会打在根gradle文件夹。
相关文章:
UE4安卓打aab包时,同时存在“gradle”、“arm64/gradle”两个Gradle工程的原因
两个Gradle工程的现象 在出安卓aab包时,观察到存在以下两个Gradle工程: 1、Intermediate\Android\arm64\gradle (称为arm64的Gradle) 2、Intermediate\Android\gradle(称为根下的Gradle) 它们存在一些小…...
淘宝API接口( item_get- 淘宝商品详情查询)
淘宝商品详情查询 API(item_detail)主要用于获取淘宝商品的详细信息,以下是相关介绍: 请求参数: num_iid:必填参数,代表商品的唯一标识 ID。通过该 ID 可以准确地指定要查询的商品。例如&#…...
Soanrquber集成Gitlab 之 gitlab用户配置和身份验证
集成Gitlab : gitlab用户配置和身份验证 说明: 使得Sonarquber的用户登录与Gitlab的用户登录/认证模块同步 什么是 SonarQube? SonarQube 是一个开源的代码质量管理平台,用于持续检查和分析代码的质量和安全性。它提供了多种功…...
沪深A股上市公司数据报告分析
数据分析报 目录 数据分析报告 1.引言 1.1 背景介绍 1.2 报告目的 1.3 报告范围 1.4 关键术语定义 2. 数据收集与预处理 2.1 数据来源概述 2.2 数据收集过程 2.3 数据预处理步骤 3. 数据可视化 3.1分析地区对公司数量的影响 3.2分析行业分类是否影响公…...
Elasticsearch Search Template 搜索模板
Elasticsearch Search Template 所谓 search template 搜索模板其实就是: 预先定义好查询语句 DSL 的结构并预留参数搜索的时再传入参数值渲染出完整的 DSL ,最后进行搜索 使用搜索模板可以将 DSL 从应用程序中解耦出来,并且可以更加灵活的…...
2024年10月-2025年5月 Oracle 19c OCM 考试安排
2024年10月-2025年5月 Oracle 19c OCM 考试安排: 北京考场: 上海考场: 更新时间:2024年10月25日 Oracle 19c OCM往期学员成绩展示: Oracle 19c OCM认证证书(电子版)...
VMware虚拟机安装KailLinux系统
目录 简介 系统镜像下载 配置虚拟机 安装系统镜像 切换中文界面 后置内容 修改root密码 ssh服务 对互联网的热爱,尝试安装另一套Linux系统。 简介 Kali Linux是一个专为网络安全和渗透测试设计的Linux发行版,它包含了大量安全相关的工具和软件…...
G2 基于生成对抗网络(GAN)人脸图像生成
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 基于生成对抗网络(GAN)人脸图像生成 这周将构建并训练一个生成对抗网络(GAN)来生成人脸图像。 GAN 原理概述 …...
R学习笔记-单因素重复测量方差分析
R语言之重复测量方差分析——ezANOVA的使用与解析 - 知乎 单因素重复测量方差分析(One-Way Repeated Measures ANOVA)——R软件实现 - 梦特医数通 ### 清空environment rm(list ls()) ### 加载包 if (!require("tidyverse")) install.packages("tidyverse&quo…...
HTML练习题:彼岸的花(web)
展示效果: 代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>彼岸の花</title><style…...
(蓝桥杯C/C++)——常用库函数
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 一、 二分查找 1.二分查找的前提 2.binary_ search函数 3.lower_bound和upper_bound 二、排序 1.sort概念 2.sort的用法 3.自定义比较函数 三、全排列 1.next p…...
GPT-Sovits-2-微调模型
1. 大致步骤 上一步整理完数据集后,此步输入数据, 微调2个模型VITS和GPT,位置在 <<1-GPT-SoVITS-tts>>下的<<1B-微调训练>> 页面的两个按钮分别执行两个文件: <./GPT_SoVITS/s2_train.py> 这一步微调VITS的预训练模型…...
【数据结构 | PTA】懂蛇语
懂蛇语 在《一年一度喜剧大赛》第二季中有一部作品叫《警察和我之蛇我其谁》,其中“毒蛇帮”内部用了一种加密语言,称为“蛇语”。蛇语的规则是,在说一句话 A 时,首先提取 A 的每个字的首字母,然后把整句话替换为另一…...
Python——自动化发送邮件
在数字化时代,电子邮件是商务沟通和个人联络的重要工具。自动化邮件发送可以节省时间,提高效率。Python,作为一种强大且灵活的编程语言,提供了多种库来支持邮件的自动化发送。本文将详细介绍如何使用Python的smtplib和email库来编…...
MTKLauncher_布局页面分析
文章目录 前言遇到的困难点针对性解决困难 需求相关资料Launcher3 源码 目录简单介绍Launcher3 简介及页面布局分析UI整体架构数据加载布局加载布局加载核心思想device_profiles.xml 加载InvariantDeviceProfileinitGrid(context, gridName)getPredefinedDeviceProfilesinvDist…...
C#实现隐藏和显示任务栏
实现步骤 为了能够控制Windows任务栏,我们需要利用Windows API提供的功能。具体来说,我们会使用到user32.dll中的两个函数:FindWindow和ShowWindow。这两个函数可以帮助我们找到任务栏窗口,并对其执行显示或隐藏的操作 引入命名空…...
基于springboot+vue实现的公司财务管理系统(源码+L文+ppt)4-102
基于springbootvue实现的公司财务管理系统(源码L文ppt)4-102 摘要 本系统是基于SpringBoot框架开发的公司财务管理系统,该系统包含固定资产管理、资产申领管理、资产采购管理、员工工资管理等功能。公司财务管理系统是一种帮助公司进行有效资金管理、会…...
rnn/lstm
tip:本人比较小白,看到july大佬的文章受益匪浅,现在其文章基础上加上自己的归纳、理解,以及gpt的答疑,如果有侵权会删。 july大佬文章来源:如何从RNN起步,一步一步通俗理解LSTM_rnn lstm-CSDN博…...
袋鼠云产品功能更新报告12期|让数据资产管理更高效
本期,我们更新和优化了数据资产平台相关功能,为您提供更高效的产品能力。以下为第12期袋鼠云产品功能更新报告,请继续阅读。 一、【元数据】重点更新 |01 元数据管理优化,支持配置表生命周期 之前系统中缺少一个可以…...
MATLAB——入门知识
内容源于b站清风数学建模 目录 1.帮助文档 2.注释 3.特殊字符 4.设置MATLAB数值显示格式 4.1.临时更改 4.2.永久改 5.常用函数 6.易错点 1.帮助文档 doc sum help sum edit sum 2.注释 ctrl R/T 3.特殊字符 4.设置MATLAB数值显示格式 4.1.临时更改 format lon…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
GraphQL 实战篇:Apollo Client 配置与缓存
GraphQL 实战篇:Apollo Client 配置与缓存 上一篇:GraphQL 入门篇:基础查询语法 依旧和上一篇的笔记一样,主实操,没啥过多的细节讲解,代码具体在: https://github.com/GoldenaArcher/graphql…...
C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...
