每周一博

APK打包过程

2019-01-11  本文已影响32人  健身营养爱好者

前言

HI,欢迎来到裴智飞的《每周一博》。今天是一月第二周,我给大家介绍下APK的打包过程。这篇文章是在上一篇《APK结构介绍》的基础上进行实践,先上一张详细的打包流程图。

详细打包图

接下来我们用工具手动打包一个Android项目。

1. 配置环境变量

我们用到的工具在build-tools目录下的不同版本中。

AAPT_HOME=/Users/peizhifei/Library/Android/sdk/build-tools/27.0.3/
export AAPT_HOME
export PATH=$PATH:$AAPT_HOME

创建一个测试项目,然后拷贝/Users/peizhifei/Library/Android/sdk/platforms/android-27/android.jar到项目根目录

2. 创建辅助目录

进入项目下面,生成gen存放R文件,build放过程文件,out放输出文件。

cd app/src/main/
mkdir -p app/src/main/{gen,build,out}

3. 生成R文件

要使用aapt工具,输入Manifest和res和android.jar来生成R文件。

aapt p -f  -M ./app/src/main/AndroidManifest.xml  
-I  android.jar -S ./app/src/main/res/ -J ./app/src/main/gen/  -m

aapt命令参数含义:
-f : #如果编译出来的文件已经存在,强制覆盖
-M : AndroidManifest.xml 的路径
-I : android.jar的路径
-S : 资源文件res 文件夹路径
-J :生成 R.java 的输出目录
-m : 让生成包的目录放在 -J 参数指定的目录
成功后可以再gen文件下会生成相应的R.java文件。

4. 编译aidl文件

通过aidl工具就可以将aidl文件编译成java文件。

aidl -Iapp/src app/src/main/aidl/com/example/peizhifei/myapplication/IMyAidlInterface.aidl

注意-Iapp/src之间是没有空格的。

5. 编译生成class文件

这一步就是用javac将项目中所有的java文件编译成class文件。

javac -source 1.8 -target 1.8 -encoding UTF-8 
-bootclasspath android.jar -d app/src/main/build/ 
app/src/main/java/com/example/peizhifei/myapplication/*.java 
app/src/main/gen/com/example/peizhifei/myapplication/*.java 
app/src/main/aidl/com/example/peizhifei/myapplication/*.java

命令参数含义如下:
-encoding :编码方式,这里设置UTF-8;
-bootclasspath :引导类文件的路径,这里需要使用到android.jar中的Android API;
-d :生成的class文件存放路径;
这里指定了所有的java文件,包括源码的,aidl编译的java文件,gen里面的R文件,结果存在在build下面。

6. 将class文件生成dex文件

dex文件是Android虚拟机可运行文件,可以使用dx工具生成。

dx --dex --output=app/src/main/build/classes.dex app/src/main/build/

输入是所有的class文件,输出在build下面,如果方法数超过Integer.Max多会出现多个dex文件。

7. 生成资源映射表

资源索引表resources记录了从资源id到文件路径的转换关系,当应用通过R文件使用资源时,会先从resources中拿到文件路径,然后通过AssetManager进行访问。

aapt package -f -M app/src/main/AndroidManifest.xml 
-I android.jar -S app/src/main/res/ -A app/src/main/assets 
-F app/src/main/out/resources

这里依然用到了aapt工具,如果有assets文件需要加进来。成功后会在out目录下看到resources文件。

8. 生成资源APK和编译后的xml文件

这一步要编译xml文件为二进制文件,同时生成资源APK。

aapt package -f -M app/src/main/AndroidManifest.xml 
-I android.jar -S app/src/main/res/ -A app/src/main/assets 
-F app/src/main/out/res.apk

这里只是输出结果变成了APK,成功的话在out目录下会看到res.apk。

9. 把代码打入到APK里

上一步已经生成了资源APK,但没有代码,这一步我们把dex文件和resources打入到APK中。早期是直接使用apkbuilder工具直接打包,但是目前sdk将该工具移除了。其实apkbuilder最终调用的是sdklib.jar中的com.android.sdklib.build.ApkBuilderMain类来做事情的,所以这里直接通过 java <class地址> 使用ApkBuilderMain这个类,把resources和classes.dex加入到apk文件中。

java -classpath /Users/peizhifei/Library/Android/sdk/tools/lib/sdklib.jar
com.android.sdklib.build.ApkBuilderMain
app/src/main/out/res.apk -v -u -z 
app/src/main/out/resources -f 
app/src/main/build/classes.dex 

成功的话可以打开res.apk,看到dex文件已经打进去了。

10. 签名APK

apk安装必须要签名,我们使用jarsigner给apk手动签名,为了方便可以使用debug签名。

jarsigner -verbose -keystore ~/.android/debug.keystore 
-storepass android -keypass android 
app/src/main/out/res.apk androiddebugkey

jarsigner的命令格式是这样的;

jarsigner -verbose -keystore <签名.keystore> -signedjar <签名ed.apk> <未签名.apk> <别名>  

11. 对齐优化

至此APK就已经生成了,可以安装在手机上了,但是正常项目还是需要进行对齐优化的,能加快apk解压速度,需要用到zipalign工具。

zipalign -f 4 app/src/main/out/res.apk app/src/main/out/res_ zipalign.apk

成功后对齐的apk就是out目录下res_ zipalign.apk。

12. 安装并启动

这里可以安装APK到手机并启动主界面

adb install -r app/src/main/out/res2.apk
adb shell am start -n
com.example.peizhifei.myapplication/.MainActivity

这里用了强制安装,这样就能覆盖安装。

到此我们就大概实现了apk的打包过程,当然在实际项目中,要比上边的流程更复杂写,包括多module依赖,so文件引用,代码混淆等。

最后把所有这些命令都可以统一放到一个shell脚本里去执行。
为了路径简短,我把android.jar放到了app/src/main/下面,并进入到该目录,避免每次输入app/src/main/。

#进入项目目录
cd app/src/main/

#创建辅助目录
mkdir -p {gen,build,out}

#生成R文件
aapt p -f  -M AndroidManifest.xml  -I  android.jar -S  res -J gen  -m

#编译aidl文件
aidl -Iapp/src aidl/com/example/peizhifei/myapplication/IMyAidlInterface.aidl

#编译得到class文件
javac -source 1.8 -target 1.8 -encoding UTF-8 -bootclasspath android.jar -d build java/com/example/peizhifei/myapplication/*.java gen/com/example/peizhifei/myapplication/*.java aidl/com/example/peizhifei/myapplication/*.java

#缺一步混淆

#将class文件生成dex文件
dx --dex --output=build/classes.dex build/

#生成资源映射表
aapt package -f -M AndroidManifest.xml -I android.jar -S res -A assets -F out/resources

#生成资源和二进制文件
aapt package -f -M AndroidManifest.xml -I android.jar -S res -A assets -F out/res.apk

#把代码打入到资源里
java -classpath /Users/peizhifei/Library/Android/sdk/tools/lib/sdklib.jar com.android.sdklib.build.ApkBuilderMain out/res.apk -v -u -z out/resources -f build/classes.dex

#签名APK
jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android out/res.apk androiddebugkey

#对齐优化
zipalign -f 4 out/res.apk out/res_zipalign.apk

#强制安装
adb install -r out/res_zipalign.apk

#启动主界面
adb shell am start -n com.example.peizhifei.myapplication/.MainActivity

直接执行该脚本,手机上就会启动主界面,简单总结一下。

aapt是一个重要的工具,来生成R.java文件和resource.arsc。assets是不需要做任何处理的,res/raw只需分配id后与assets一起直接打包到应用程序中,其它xml文件则会被编译成二进制文件。编译过程中,会把xml中的字符串进行收集去重,形成字符串资源池,元素中用到字符串的地方将被替换成相应的索引。另外标签属性值都会转换为资源id,进一步减少文件大小。二进制格式的xml把标签属性值转换为资源id后,避免了字符串解析,从而提高了解析速度。

另外就是生成资源APK后需要把代码打入到APK里面,然后对APK做一些优化处理即可。其实这个演示更多是为了加深对编译过程的理解,比如插件化处理资源就会从aapt入手解决资源冲突,汉化可以考虑修改resource.arsc并进行二次打包等。

本文介绍了APK的打包过程,实际操作演示了一下,感谢大家的阅读,我们下周再见。

上一篇 下一篇

猜你喜欢

热点阅读