APK打包过程

前言

HI,欢迎来到《每周一博》。今天是一月第一周,也是2019年的第一周,今天我给大家介绍下APK的结构。

APK其实就是个压缩文件,我们把后缀改成ZIP之后解压就可以看到里面的内容主要有如下部分:

1.AndroidManifest.xml
该文件是每个应用都必须包含的,它描述了应用的名字,版本,权限,引用的库文件等等信息。APK中的AndroidManifest.xml是二进制文件,直接打开是乱码,需要反编译。

2.META-INF目录
META-INF目录下存放的是签名信息,用来保证apk包的完整性和系统的安全。打包时会对所有要打包的文件做一个校验计算,并把计算结果放在META-INF目录下。这就保证了apk包里的文件不能被随意替换。比如拿到一个apk包后,如果想要替换里面的一幅图片,一段代码, 或一段版权信息,想直接解压缩,替换再重新打包,基本是不可能的。如此一来就给病毒感染和恶意修改增加了难度,有助于保护系统的安全。

3.classes.dex文件
classes.dex是java源码编译后生成的java字节码文件。安卓的虚拟机解析的是dex文件而不是class。dex文件中各个类能够共享数据,在一定程度上降低了冗余,也使得文件结构更加经凑,节省体积。

4.resources.arsc
resources.arsc是编译后的二进制资源文件,它是一个映射表,映射着资源和id,通过R文件中的id就可以找到对应的资源。

5.res目录
res目录存放资源文件,包括图片,字符串等等,像layout,drawable中的xml文件也都是经过编译的,直接打开是乱码,需要使用apktools才能查看。

6.lib目录
lib目录下存放的是一些so文件,如果代码中没有so就没有该目录。

7.assets目录
assets目录下是一些配置文件,也可以是资源,这里的xml文件不会经过编译,如果代码中没有assets也不会有该目录。

编译APK主要有如下几步:

  1. 根据资源文件和AndroidManifest.xml生成R.java文件
  2. 编译AIDL,生成对应的java文件,没有则跳过
  3. 编译工程源码(主项目和库),同时上边生成的R文件和AIDL生成的Java文件也会被编译生成相应的class文件
  4. 将class文件打包生成dex文件
  5. 将资源文件打包,生成初始的apk
  6. 将生成的dex文件加入到apk中生成未签名的包
  7. 对apk进行签名
  8. 将签名后的apk进行对齐处理,目的是减少程序运行时对内存的占用

这里有几个图可以帮助理解下。

粗略打包图
详细打包图

本文介绍了APK的基本结构,下周会介绍APK的具体打包过程,感谢大家的阅读,我们下周再见。

前言

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的打包过程,实际操作演示了一下,感谢大家的阅读,我们下周再见。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 1.使用aapt打包res资源文件,生成R.java,resources.arsc(资源映射信息)以及其他re​s...
    舌尖上的Android阅读 718评论 0 0
  • 概述Apk其实是一个压缩包,当解压后,其内部主要就是资源文件和classes.dex。这个classes.dex文...
    breaktian阅读 650评论 0 1
  • 在《Android软件安全与逆向分析》书中看到android apk的打包过程,觉得比较有意思,因此根据书中内容整...
    chichichichi阅读 2,629评论 0 4
  • Android 官方配置构建介绍aapt命令介绍参考老罗的文章 再来一张详细的图 aapt打包过程 1. 解析An...
    第八区阅读 442评论 0 2
  • Apk的打包,大致就是把代码打成包、把资源打成包、最后对整个Apk文件做一下安全处理和优化操作,Andriod提供...
    蓝灰_q阅读 395评论 0 2