Android 打包流程

一、Android 打包流程

1、apk 内部组成

打包后的apk是一个压缩包,解压之后,内容如下:

image
  • res文件夹为编译之后的资源文件
  • resources.arsc是aapt(Android assets packaging tools) 生成的资源索引表。这个文件记录了所有的应用程序资源目录的信息,包括每一个资源名称、类型、值、ID以及所配置的维度信息。这个资源索引表在给定资源ID和设备配置信息的情况下,能够在应用程序的资源目录中快速地找到最匹配的资源。
  • AndroidManifest.xml 是编译之后的AndroidManifest文件(二进制)
  • lib为 app需要的so文件
  • classes.dex Android平台上的可执行文件,Android虚拟机Dalvik支持的字节码文件格式。
  • 签名文件夹

三个签名证书(MANIFEST.MF、CERT.SF、CERT.RSA)。MANIFEST.MF文件是对每个文件的SHA-256-Digest;CERT.SF是对MANIFEST.MF的二次SHA-256-Digest摘要;CERT.RSA这个文件保存了签名和公钥证书。

详细可参考apk签名原理

2、apk打包流程

apk打包流程.png

无论我们怎么配置gradle文件去自定义打包,但是都是要走上图所画的七个流程。七个深绿色的椭圆代表了七个不可或缺的打包步骤,并且每一个步骤都一个打包工具

1、使用aapt工具将res资源文件生成R.java文件
2、使用aidl工具将aidl文件生成对应java文件
3、使用javac命令编译工程源代码和上面两步生成的文件,生成class文件
4、通过dex工具将class文件和第三方jar包打成dex文件
5、用res下编译过的二进制文件,以及assets中的原始资源文件,以及dex文件,通过apkbuilder工具打包成apk文件
6、通过jarsigner对apk进行签名
7、利用zipalign工具对apk进行字节对齐优化操作

所用到的工具:

工具名称 功能介绍 在操作系统中的路径
aapt Android资源打包工具 ${ANDROID_SDK_HOME}/build-tools/30.0.0/aapt
aidl Android接口描述语言转化为.java文件的工具 ${ANDROID_SDK_HOME}/build-tools/30.0.0/aidl
javac java Compiler java代码转class文件 ${JDK_HOME}/javac或/usr/bin/javac
dex 转化.class文件为Davik VM能识别的.dex文件 ${ANDROID_SDK_HOME}/build-tools/30.0.0/dx
apkbuilder 生成apk包 ???没有找到
jarsigner .jar文件的签名工具 ${JDK_HOME}/jarsigner或/usr/bin/jarsigner
zipalign 字节码对齐工具 ${ANDROID_SDK_HOME}/tools/zipalign

彩蛋

zipalign 字节对齐:

zipalign 主要工作是将apk包进行对齐处理。使apk包中的所有资源文件,起始偏移为4字节的整数倍,这样通过mmap内存映射访问apk时的速度会更快。

为什么要以4字节整数倍为起始偏移?

在文件对齐后, 就可以使用mmap来直接读写apk文件


- 正常的IO读写需要借助内核态的页缓存, 也就是 磁盘 ->内核页缓存 ->用户主存

- mmap借助映射可以跳过内核页缓存, 只需要磁盘 ->用户主存

Linux是以page为单位管理内存的,mmap也是以page为单位建立映射的,因此offset必须是按page size对齐的(不对齐的话就会映射失败)。

offset对齐是用户自己保证的,length对齐是靠内核来保证的。

mmap映射

三、gradle task

上面涉及到的Android打包流程是以gradle task链的形式串联起来的。
下面看一下常见的task

  1. task ':app:preBuild'
预构建,准备构建,在项目根目录下生成build文件夹,在app目录下生成build文件夹
  1. task ':app:preReleaseBuild'
预构建,生成/app/build/intermediates/prebuild/release目录,Release是构建类型
  1. task ':app:compileReleaseAidl'
编译aidl相关文件,通过aidl工具把.aidl文件编译成.java文件 ,生成的结果在/app/build/generated/source/aidl/release目录
  1. task ':app:compileReleaseRenderscript'
编译渲染脚本
  1. task ':app:checkReleaseManifest'
检查清单AndroidManifest.xml,生成/app/build/intermediates/check-manifest/release目录
  1. task ':app:generateReleaseBuildConfig'
在/app/build/generated/source/buildConfig/release目录生成BuildConfig.java,构建配置类中有应用ID、构建类型、版本名称等
  1. task ':app:prepareLintJar'
准备检查.jar文件
  1. task ':app:mainApkListPersistenceRelease'
主要的apk列表持久化
  1. task ':app:generateReleaseResValues'
在/app/build/generated/res/resValues/release目录,生成/app/src/main/res/values目录相应的资源值
  1. task ':app:generateReleaseResources'
生成资源,即生成color,string,style等resources
  1. task ':app:mergeReleaseResources'
合并资源,即合并color,string,style等resources到values.xml
  1. task ':app:createReleaseCompatibleScreenManifests'
创建兼容屏幕清单,
  1. task ':app:processReleaseManifest'
处理清单,生成处理后的/app/build/intermediates/manifests/full/release/AndroidManifest.xml
  1. task ':app:splitsDiscoveryTaskRelease'
分裂发现任务
  1. task ':app:processReleaseResources'

  1. task ':app:javaPreCompileRelease'
预编译.java文件
  1. task ':app:compileReleaseJavaWithJavac'
使用javac编译.java文件,
  1. task ':app:compileReleaseNdk
通过ndk编译.c或.cpp等相关文件
  1. task ':app:generateReleaseAssets'
生成资产assets
  1. task ':app:mergeReleaseAssets'
合并资产assets
  1. task ':app:transformClassesWithDexBuilderForRelease'
使用dex构建器转换.class文件,在/app/build/intermediates/transforms/dexBuilder/release目录生成R.dex,BuildConfig.dex,MainActivity.dex等.dex文件
  1. task ':app:transformDexArchiveWithExternalLibsDexMergerForRelease'
使用外部库dex合并器转换.dex归档文件,在/app/build/intermediates/transforms/externalLibsDexMerger/release目录生成classes.dex文

  1. task ':app:transformDexArchiveWithDexMergerForRelease'
使用dex合并器转换.dex归档文件,
在/app/build/intermediates/transforms/dexMerger/release目录生成classes.dex文件
  1. task ':app:mergeReleaseJniLibFolders'
合并jniLibs文件夹
  1. task ':app:transformNativeLibsWithMergeJniLibsForRelease'
转换本地库文件,合并jni库文件
  1. task ':app:transformNativeLibsWithStripDebugSymbolForRelease'
转换本地库文件,剥离调试符号
  1. task ':app:processReleaseJavaRes'
处理Java资源,
  1. task ':app:transformResourcesWithMergeJavaResForRelease'
转换资源,合并Java资源,生成resources.arsc
  1. task ':app:validateSigningRelease'
验证签名
  1. task ':app:packageRelease'
打包,在/app/build/intermediates/incremental/packageRelease目录生成相关文件
  1. task ':app:assembleRelease'
聚集,组合,最终生成/app/build/outputs/apk/release/app-release.apk

四、了解了apk的打包流程后,我们可以额外做哪些事情?

我可以想到的:

  • 编写注解和注解处理器,利用apt过程,为我们生成辅助代码
  • 在第4步,通过自定义Transform Task,在class文件转换成dex文件前,对class文件做一些处理
    如:利用ASM 动态的修改字节码文件,帮忙我们实现我们需要的功能。


    image

Transform API

Starting with 1.5.0-beta1, the Gradle plugin includes a Transform API allowing 3rd party plugins to manipulate compiled class files before they are converted to dex files.
  • hook 其他的task,造成干扰,以达成我们需要的效果。
    如VirtualApk中 插件apk打包过程中 对插件依赖资源的做去重操作;修改appt生成的R.java和Resources.arsc文件的ID起始位。

参考文章

https://www.jianshu.com/p/a134d00e81ab

https://www.jianshu.com/p/fffb81688dc5

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容