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…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
