APK构建过程-命令行编译

news2025/2/27 1:43:24

官方对APK构建过程的介绍

官方 - 构建流程介绍

apk构建流程-简版.png

典型 Android 应用模块的构建流程,按照以下常规步骤执行:

  1. 编译器将您的源代码转换成 DEX 文件(Dalvik 可执行文件,其中包括在 Android 设备上运行的字节码),并将其他所有内容转换成编译后的资源。
  2. 打包器将 DEX 文件和编译后的资源组合成 APK 或 AAB(具体取决于所选的 build 目标)。 必须先为 APK 或 AAB 签名,然后才能将应用安装到 Android 设备或分发到 Google Play 等商店。
  3. 打包器使用调试或发布密钥库为 APK 或 AAB 签名:
    • 如果您构建的是调试版应用(即专门用来测试和分析的应用),则打包器会使用调试密钥库为应用签名。Android Studio 会自动使用调试密钥库配置新项目。
    • 如果您构建的是打算对外发布的发布版应用,则打包器会使用发布密钥库(您需要进行配置)为应用签名。
    • 在 Android Studio 中为应用签名
  4. 在生成最终 APK 之前,打包器会使用 zipalign 工具对应用进行优化,以减少其在设备上运行时所占用的内存。

构建流程结束时,您将获得应用的调试版或发布版 APK/AAB,以用于部署、测试或向外部用户发布。

精通APK构建

APK构建-详版.png

APK的一般生成步骤

  1. 打包资源文件 aapt/aapt2
    • 生成R文件
    • 生成编译后的资源文件
  2. aidl生成java文件 aidl
  3. Java代码生成class文件 javac
  4. class文件生成dex文件 dx/d8/r8
  5. 打包(未签名)apk apkbuilder
  6. 签名apk jarsigner/apksigner
  7. 对齐apk zipalign

注:官方对上述部分命令行工具的使用有介绍:[ 官方指导:命令行工具 ]

1. 打包资源文件 aapt/aapt2

  • aapt/aapt2:ANDROID_SDK/build-tools/

见[ 官方指导:命令行工具-aapt2 ]

aapt package -f -m -J ./gen -S res -M AndroidManifest.xml -I D:\android.jar

-f 如果编译生成的文件已经存在,强制覆盖。
-m 使生成的包的目录存放在-J参数指定的目录
-J 指定生成的R.java 的输出目录路径
-S 指定res文件夹的路径
-I 指定某个版本平台的android.jar文件的路径
-A 指定assert文件夹的路径

aapt 入口为 frameworks/base/tools/aapt/Main.cpp ,其中对 assets文件夹路径、res文件夹路径、AndroidManifest文件等会采取不同的策略。

对assets目录下的资源不进行编译,会被原封不动的打入apk中,也就是说assets不会被压缩。

AndroidManifest.xml会被aapt编译成二进制。

res下的资源,大多会被编译成针对Android平台优化过的二进制文件。对drawable下的png默认会进行压缩处理(raw目录下除外)

资源文件(res/下的文件) ---AAPT---|---> R.java(资源索引表)
                                |---> resource.arsc 资源文件
                                |---> res文件(二进制&非二进制如res/raw和pic保持原样)
// 每个资源ID占4字节
public final class R {
    public static final class anim {
        public static int fade_in = 0x7f010001;
        public static int fade_out = 0x7f010002;
    }
}
// 第一位字节 0x7f 表示 packageID ,用来限定资源的来源。系统资源包是 0x01,SharedLibrary类型资源包是 0x00, 普通App包则是 0x7f; 
// 次一位字节 01 表示 TypeID,用来表示资源类型,如 drawable、layouts、anims、color、menu 等;
// 后2字节 0001/0002 表示 EntryID,指的是每一个资源在对应的 TypeID 中出现的顺序

resources.arsc 是一个App的资源索引表,可以理解为一个map映射表,map的key是 R.java 中的资源ID,而 value 就是其对应的资源所在路径,通过 R.java 文件和 resources.arsc 就可以在代码中找到对应的资源引用。

res/raw和assets的相同点:

  1. 两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。

res/raw和assets的不同点:

  1. res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类,通过文件名访问。
  2. res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹

2. aidl生成java文件 aidl

  • aidl:ANDROID_SDK/build-tools/

3. Java代码生成class文件 javac

  • javac:jdk/
javac -target 1.7 -bootclasspath D:\android-sdk-windows\platforms\android-8\android.jar -d bin src\demo\project\*.java gen\demo\project\R.java

-target <版本>           生成特定 VM 版本的类文件
-bootclasspath <路径>    覆盖引导类文件的位置
-d <目录>                指定存放生成的类文件的位置
-sourcepath <路径>       指定查找输入源文件的位置

Javac 入口为 com.sun.tools.javac.main.JavaCompiler 类,主要逻辑集中在 compile() 和 compile2() 方法中

4. class文件生成dex文件 dx/d8/r8

  • dx:ANDROID_SDK/build-tools/
    • 最老、仅支持编译dex(dexing)
  • d8:ANDROID_SDK/build-tools/(高版本sdk才提供)
    • 较新,用于替代dx,支持编译dex(dexing)与脱糖(desugaring)
  • r8:/Applications/Android Studio.app/Contents/plugins/android/lib/r8.jar
    • 最新,相当于 ProGuard + d8,支持缩减(shrinking)、编译dex(dexing)与脱糖(desugaring)
    • sdk未提供r8.jar,网上也没有下载,需自行下载源码编译jar包,但有点麻烦,可在Android Studio/plugin/目录中找到

注:关于dex生成的发展史,可以参考我的另一篇文章:[通过命令行进行R8混淆]

dx用法
dx --dex --output=D:\ProjectDemo\bin\classes.dex D:\ProjectDemo\bin

--output=<要生成的classes.dex路径> <要处理的class文件的路径>
d8用法

见[ 官方指导:命令行工具-d8 ]

# debug mode
$ java -jar build/libs/d8.jar --output out input.jar
# release mode
$ java -jar build/libs/d8.jar --release --output out input.jar
# example: java -jar build/libs/d8.jar --release --output . --pg-conf ./proguard-project.txt ./input.jar
r8用法
$ java -jar build/libs/r8.jar --release --output out --pg-conf proguard.cfg input.jar

ANDROID_SDK中提供的有些jar包由于没有指定入口类main方法,不能直接通过 -jar 执行,可通过 -cp 显式的指定入口,举例:

java -cp r8.jar com.android.tools.r8.R8 --help

5. 打包(未签名)apk apkbuilder

  • apkbuilder:
    • 较老SDK:ANDROID_SDK/tools/
    • 较新SDK:ANDROID_SDK/tools/lib/sdklib.jar

apkbuilder只是一个脚本,实际上调用的是 ANDROID_SDK/tools/ 下的jar包中的 com.android.build.ApkBuilderMain 类。
这个jar包在低版本SDK中是哪个我没注意看过。而高版本SDK中已经不提供 apkbuilder 了,但 ANDROID_SDK/tools/lib/sdklib.jar 中有ApkBuilderMain类,可以使用(未指定Main方法入口,调用时需显式的指定:java -cp sdklib.jar com.android.build.ApkBuilderMain --help)。

apkbuilder D:\ProjectDemo\bin\projectdemo.apk -v -u -z D:\ProjectDemo\bin\resources.ap_ -f D:\ProjectDemo\bin\classes.dex -rf D:\ProjectDemo\src 

-v Verbose 显示过程信息
-u 创建一个无签名的包
-z 指定apk资源路径
-f 指定dex文件路径
-rf 指定源码路径

6. 签名apk jarsigner/apksigner

  • jarsigner:v1签名,jdk/bin/,参考 [jarsigner指导文档]
  • apksigner:v2签名,ANDROID_SDK/build-tools/
jarsigner用法
jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore mykeystore.key -storepass STORE_PASS MY_APP.apk KEY_ALIAS

-verbose    签名/验证时输出详细信息
-keystore   密钥库位置
-storepass  用于密钥库完整性的口令
-keypass    专用密钥的口令(如果不同)
-signedjar  已签名的 JAR 文件的名称 (第一个apk是签名之后的文件, 第二个apk是需要签名的文件)
apksigner用法

见[ 官方指导:命令行工具-apksigner ]

  • apksigner:ANDROID_SDK/build-tools/
apksigner sign --ks **.keystore --ks-key-alias [别名] --ks-pass pass:[别名密码] --key-pass pass:[证书密码] --out [签名后文件存放路径] [未签名的文件路径]

// 私钥和证书必须提供,有两种方式:
--ks:指定密钥库文件(即.keystore/.jks,私钥和证书被存放其中)
--key 和 --cert:分别指定私钥和证书,私钥必须使用 PKCS #8 格式(.pk8),证书必须使用 X.509 格式(x509.pem)。

7. 对齐apk zipalign

见[ 官方指导:命令行工具-zipalign ]

  • zipalign:ANDROID_SDK/build-tools/
  • 若使用v1签名,zipalign 必须在签名后进行
  • 若使用v2签名,zipalign 必须在签名前进行
// 对齐
zipalign -p -f -v 4 infile.apk outfile.apk
// 确认existing.apk的对齐方式
zipalign -c -v 4 existing.apk

-c	仅检查对齐情况(不会修改文件)。
-f	覆盖现有输出文件。
-h	显示工具帮助。
-p	使未压缩的 .so 文件对齐页面。
-v	详细输出。
-z	使用 Zopfli 重新压缩。

zipalign是一个zip归档文件对齐工具,它将zip(apk也是zip文件)中的所有未压缩文件相对于文件开头对齐(偏移为4字节的整数倍),这样就可以通过内存映射(mmap)访问这些文件,而无需在 RAM 中复制这些数据,既高效又减少了应用的内存使用

CPU在处理内存数据时,并非一次提取一个memory cell,通常是提取一组相邻内存单元。在32-bit machine,CPU一次从内存中读取4个连续的memory cell(4-byte) 。4 byte chunk(4字节流) 为一个读取周期。比如,读取一个int型 数据时,需要一个读取周期(int 占4 byte),读取Double型,则需要2个读取周期。

zipalign对齐图解

注:上图是以c代码为例,c语言中 1char = 1byte,而在java中 1char=2byte。

附加:smali工具

baksmali:将dex编译为smali
java -jar baksmali-1.3.2.jar -o classout/ classes.dex
smali:将smali反编译成dex
java -jar smali-1.3.2.jar classout/ -o classes.dex

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/40137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【强化学习论文合集】专栏介绍(订阅前必读)

导读&#xff1a;什么是强化学习&#xff1f; 强化学习&#xff08;Reinforcement Learning, RL&#xff09;&#xff0c;又称再励学习、评价学习或增强学习&#xff0c;是机器学习的范式和方法论之一&#xff0c;用于描述和解决智能体&#xff08;agent&#xff09;在与环境的…

AtCoder Beginner Contest 263 G.Erasing Prime Pairs(二分图最大匹配-网络流)

题目 黑板上有n(n<100)个不同的数&#xff0c;第i个数ai(1<ai<1e7)出现了bi(1<1e9)次&#xff0c; 你每次可以选择当前黑板上存在的两个数x、y&#xff0c;满足xy是质数&#xff0c;擦掉这两个数&#xff0c; 求可以擦掉的最大次数 思路来源 AtCoder Beginner…

[LeetCode周赛复盘] 第 321 场周赛20221127

[LeetCode周赛复盘] 第 321 场周赛20221127 一、本周周赛总结二、 [Easy] 6245. 找出中枢整数1. 题目描述2. 思路分析3. 代码实现三、[Medium]6246. 追加字符以获得子序列1. 题目描述2. 思路分析3. 代码实现四、[Medium] 6247. 从链表中移除节点1. 题目描述2. 思路分析3. 代码实…

Docker-compose详解和LNMP搭建实战

目录 一、Docker-compose简介 1.前言 2.概述 二、Docker-compose安装 三、YAML文件格式及编写注意事项 1.简介 2.使用方法 四、Docker Compose 常用命令 五、Docker Compose 配置常用字段 六、Docker-compose搭建LNMP实战 一、Docker-compose简介 1.前言 我们知道使…

深度学习与总结JVM专辑(三):垃圾回收器—G1(图文+代码)

垃圾收集器G1前言概述停顿时间模型内存布局传统内存布局过时了G1实现的几个关键细节问题铺垫知识&#xff1a;跨代引用铺垫知识&#xff1a;记忆集&#xff0c;卡表&#xff0c;卡页铺垫知识&#xff1a;写屏障插眼往下看G1内存模型分区Region卡片Card堆Heap分代模型分代垃圾收…

网站分享:7个非常好用的电子书网站

❤️作者主页&#xff1a;IT技术分享社区 ❤️作者简介&#xff1a;大家好,我是IT技术分享社区的博主&#xff0c;从事C#、Java开发九年&#xff0c;对数据库、 C#、 Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉&#xff1a; 数据库领域优质创作者&#x1f3c6;&…

Steam下载MOD至本地文件夹

Steam下载MOD至本地文件夹1 所需app和web2 具体步骤2.1 安装SteamCMD2.2 登录SteamCMD2.3 打开网页端的Steam并搜索你想要的MOD2.4 点击你需要的MOD&#xff0c;并复制链接2.5 将链接放入 https://steamworkshopdownloader.io/2.6 把下载代码放入SteamCMD由于各种原因&#xff…

OpenVINO--初步学习笔记

英特尔发布的针对AI工作负载的一款部署神器当模型训练结束后&#xff0c;上线部署时&#xff0c;就会遇到各种问题&#xff0c;比如&#xff0c;模型性能是否满足线上要求&#xff0c;模型如何嵌入到原有工程系统&#xff0c;推理线程的并发路数是否满足&#xff0c;这些问题决…

java项目_第164期ssm定西扶贫惠农推介系统-_java毕业设计_计算机毕业设计

java项目_第164期ssm定西扶贫惠农推介系统-_java毕业设计_计算机毕业设计 【源码请到资源专栏下载】 今天分享的项目是《ssm定西扶贫惠农推介系统》 该项目分为2个角色&#xff0c;管理员和用户。 用户可以浏览前台,包含功能有&#xff1a; 首页、扶贫计划、惠农福利、优秀农民…

【C++】vector的介绍和使用

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;vector 的…

【课设/毕业设计】电力系统潮流计算(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

相控阵天线(九):平面阵列天线综合(不可分离型切比雪夫分布、圆口径泰勒综合、可分离型分布)

目录简介不可分离型分布不可分离型切比雪夫圆口径泰勒综合可分离型分布可分离切比雪夫综合可分离泰勒综合简介 按行、列排列的可分离型矩形平面阵&#xff0c;其阵因子是两个正交排列的直线阵阵因子的乘积。可分离的平面阵方向图在两个主面内是满足预期副瓣电平的&#xff0c;…

SpringMVC学习笔记(一)

目录 一、什么是SpringMVC ? 二、Spring MVC项目的连接(用户 和 程序 的 映射) 三、获取参数的功能的实现 传递较少数量的参数&#xff1a; 通过对象传递大量参数&#xff1a; 获取表单参数&#xff1a; 获取Json对象 上传文件&#xff1a; &#x1f514;一点补充 一、…

家用 NAS 服务器搭建 | 前篇

1、前言 最近一段时间都在折腾家用 NAS 服务器&#xff0c;NAS 系统从最开始选择安装开源的 OMV&#xff08;OpenMediaVault&#xff09;、万由U-NAS&#xff0c;最终决定使用黑群晖。硬件也是一步步从旧笔记本、拆旧笔记本改nas样式、最终也是到万由410机箱。 家庭nas服务器可…

unity rtsp 视频渲染(一)

unity unity 可以说是一个不错的工具&#xff0c;建立三维的场景非常方便&#xff0c;下面我们建立一个三维的场景&#xff0c;并且在三维的场景中和场景外分别建立系统去播放视频。所谓场景内就是在三维中播放视频&#xff0c;场景外就是在三维场景前表面的二维平面中播放视频…

Go-Excelize API源码阅读(三十六)——SetSheetRow、InsertPageBreak

Go-Excelize API源码阅读&#xff08;三十六&#xff09;——SetSheetRow、InsertPageBreak 开源摘星计划&#xff08;WeOpen Star&#xff09; 是由腾源会 2022 年推出的全新项目&#xff0c;旨在为开源人提供成长激励&#xff0c;为开源项目提供成长支持&#xff0c;助力开发…

公司信息系统架构建设规划

企业的信息化建设的基础是构建企业的信息系统架构&#xff08;也可称之为信息化架构&#xff09;&#xff0c;信息系统架构又由应用架构、数据架构、技术架构和治理架构4部分组成&#xff0c;本建议书主要以技术架构、应用架构以及技术架构为对象加以说明。 4.1公司信息系统架…

《MongoDB》Mongo Shell中基本操作-ObjectId和文档创建详解

前端博主&#xff0c;热衷各种前端向的骚操作&#xff0c;经常想到哪就写到哪&#xff0c;如果有感兴趣的技术和前端效果可以留言&#xff5e;博主看到后会去代替大家踩坑的&#xff5e; 主页: oliver尹的主页 格言: 跌倒了爬起来就好&#xff5e; 来个关注吧&#xff0c;点个赞…

R语言对用电负荷时间序列数据进行K-medoids聚类建模和GAM回归

通过对用电负荷的消费者进行聚类&#xff0c;我们可以提取典型的负荷曲线&#xff0c;提高后续用电量预测的准确性&#xff0c;检测异常或监控整个智能电网&#xff08;Laurinec等人&#xff08;2016&#xff09;&#xff0c;Laurinec和Luck&#xff08; 2016&#xff09;&…

JavaScript正则表达式加密

正则表达式可以加密吗&#xff1f; 是的&#xff0c;可以。起码可以确定的是在JavaScript编程中是可以的。 正则表达式加密有什么用&#xff1f; 可以隐藏一些重要的、私密的字符串内容&#xff0c;使代码的逻辑、秘密不容易被人窥探。 正则表达式加密示例 例如&#xff1…