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…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...
2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版
1.题目描述 2.思路 当前的元素可以重复使用。 (1)确定回溯算法函数的参数和返回值(一般是void类型) (2)因为是用递归实现的,所以我们要确定终止条件 (3)单层搜索逻辑 二…...
