最近刚刚忙完公司项目,比较轻松一点,抽个时间总结一下Android打包apk相关的知识点,也从网上看了一些前辈的资料,但是感觉看一遍印象不会特别深刻,所以决定写篇文章加深一下记忆,以希望能帮助一批想了解相关信息的同志们... ... 那就开始吧。
一、Ant原始命令行打包流程。
首先总结一下apk打包的一个大致流程,方便后边大家理解。大致分为三步:1.打包生成.dex文件。2.打包生成resouse.zip文件。3.生成.apk文件并签名。每一步中又包含了一些详细的操作步骤,下面一起来看一下。
一.打包生成.dex文件。
我们如果想要生成.dex文件,必须通过工具将一些资源与java代码生成.class文件,其中包含一些资源文件、所有java代码文件、aidl文件等。首先需要在环境变量中配置好我们将要用到的工具,包括JDK、SDK、ANT,配置方法在这里就不多说了,网上一查一大片。然后我们先要用到SDK包下的一个aapt()工具,这个工具后面还会被用到一次,工具在/SDK/build-tools/目录下,我们先用它生成应用的R.java文件。先cd到当前目录下然后输入输入aapt工具相关命令行及相关参数,如下:
aapt package -f -m -J C:\Users\jason\Desktop\ -S D:\lylsoft\android\androidstudio\opensource\MyButterKnifeDemo\app\src\main\res -M D:\lylsoft\android\androidstudio\opensource\MyButterKnifeDemo\app\src\main\AndroidManifest.xml -I D:\lylsoft\android\androidstudio\sdk\platforms\android-24\android.jar
-f 如果编译生成的文件已经存在,强制覆盖。
-m 使生成的包的目录存放在-J参数指定的目录
-J 指定生成的R.java 的输出目录路径(存放在桌面的gen)
-S 指定目标项目res文件夹的路径
-M 指定目标项目AndroidManifest.xml文件的路径
-I 指定某个版本平台的android.jar文件的路径
回车执行,便会在我的桌面上生成如下目录结构及R.java文件
第二小步是处理aidl文件,
aidl -ID:/JavaTest/Demos/src D:/JavaTest/Demos/src/com/example/android/apis/app/IRemoteService.aidl
"-I"与"D:/JavaTest/***"之间是没有空格的。执行此条命令后,生成的.java会与.aidl文件在同一目录下。
对于没有使用到aidl的Android工程,这一步可以跳过。这一步使用到的工具为aidl,位于android-sdk\platform-tools目录下,aidl工具解析接口定义文件(aidl为android interface definition language的首字母缩写,即android接口描述语言)并生成相应的java代码供程序调用,源码位于Android源码的frameworks\base\tools\aidl目录下。
第三小步通过javac命令将所有的.java文件编译成.class文件包括上边生成的R.java文件。
javac -target 1.8 -bootclasspath D:\lylsoft\android\androidstudio\sdk\platforms\android-24\android.jar -d C:\Users\jason\Desktop\com\demo\jason\mybutterknifedemo -sourcepath D:\lylsoft\android\androidstudio\opensource\MyButterKnifeDemo\app\src C:\Users\jason\Desktop\com\demo\jason\mybutterknifedemo\R.java
执行完上述命令后在桌面上的文件夹中就会出现如下目录
参数含义如下:
-target
-bootclasspath <路径> 覆盖引导类文件的位值
-d <目录> 指定存放生成的类文件的位置
-sourcepath <路径> 指定查找输入源文件的位置(这里包含两个地方一个是src,一个是桌面gen生成的R.java)
第四小步就是生成我们的.dex文件了,这个相对简单,主要用到SDK/build-tools中的dx工具。命令如下:
dx --dex --output=\Users\jason\Desktop\com\demo\jason\mybutterknifedemo\classes.dex C:\Users\jason\Desktop\com\demo\jason\mybutterknifedemo\com\demo\jason\mybutterknifedemo
这样我们的第一步生成.dex文件就算是完成了,下边就开始我们的第二步 打包生成Resource.zip
二.打包生成Resource.zip文件。
在这里就第二次用到了我们sdk中的aapt工具了,命令如下:
aapt package -f -M AndroidManifest.xml -S D:\lylsoft\android\androidstudio\opensource\MyButterKnifeDemo\app\src\main\res -I D:\lylsoft\android\androidstudio\sdk\platforms\android-24\android.jar -A D:\lylsoft\android\androidstudio\opensource\MyButterKnifeDemo\app\src\main -F C:\Users\jason\Desktop\com\demo\jason\mybutterknifedemo\Resource.zip
参数介绍如下,跟生成R.java文件差不多:
-f 如果编译生成的文件已经存在,强制覆盖。
-m 使生成的包的目录存放在-J参数指定的目录
-S 指定res文件夹的路径
-I 指定某个版本平台的android.jar文件的路径
-A 指定assert文件夹的路径
-F 指定输出文件完整路径。
回车执行,我们的Resource.zip文件夹就算是生成了,这个名字是可以指定的。这一步比较简单,没有太多要说的。接着往下看。第三步就是生成我们的.apk文件了,这里的.apk文件是没有签名没有优化的.apk文件。
二.生成.apk文件并签名优化。
这里需要组合我们上边生成的两大文件,即.dex文件和Resource.zip文件。这里主要使用apkbuilder脚本,其实是个批处理文件,不过android 3.0后已经被删除,但网上还是可以找到这个脚本的,直接拷贝放到/SDK/tools下即可。其实里面执行的就是sdklib.jar。
apkbuilder C:\Users\jason\Desktop\com\demo\jason\mybutterknifedemo\demo.apk -v -u -z C:\Users\jason\Desktop\com\demo\jason\mybutterknifedemo\Resource.zip -f C:\Users\jason\Desktop\com\demo\jason\mybutterknifedemo\classes.dex
参数含义如下:
第一个参数是存放打包后的文件完整路径
-v Verbose 显示过程信息
-u 创建一个无签名的包
-z 指定apk资源路径
-f 指定dex文件路径
回车执行:在我们指定的路径下就会生成我们没有优化签名的apk文件,如下图:打包的工具为apkbuilder,它位于android-sdk\tools目录下,apkbuilder为一个脚本文件,实际调用的是android-sdk\tools\lib\sdklib.jar文件中的com.android.sdklib.build.apkbuilderMain类。它的实现代码位于android系统源码的sdk\sdkmanager\libs\sdklib\src\com\android\sdklib\build\akpbuilderMain.java文件,代码构建了一个apkbuilder类,然后以包含resources.arec的文件为基础生成apk文件,这个文件一般为ap_结尾的文件,接着调用addSourceFolder()函数添加的资源,addSourceFolder()会调用processFileForResource()函数往apk文件中添加资源,处理的内容包括res目录与assets目录中的文件,添加完整源后调用addResourcesFromJar()函数往apk文件中写入依赖库,接着调用addNativeLibraries()函数添加工程libs目录下的Native库(通过androidDNK编译生成的so或bin文件),最后条用sealApk()关闭apk文件。
接下来就是给我们的demo.apk进行签名了,用到了jarsigner命令,java的签名工具,如下:
jarsigner -verbose -keystore C:\Users\jason\Desktop\demo.keystore -storepass android -keypass android -signedjar C:\Users\jason\Desktop\com\demo\jason\mybutterknifedemo\demo.apk C:\Users\jason\Desktop\com\demo\jason\demo.apk demo1
各个参数的意义如下:
-verbose 签名/验证时输出详细信息
-keystore 密钥库路径
-storepass 用于密钥库完整性的口令(密码)
-keypass 专用密钥的口令(密码)
-signedjar 已签名的 apk 文件的名称 (第一个apk是签名之后的文件, 第二个apk是需要签名的文件)
回车执行,稍等片刻,在我们指定的文件架下就会生成我们已经打包好的apk文件了,这个已经是签名好的apk文件了。下一步就是用zipalign对我们的apk进行优化了,我们可以通过zipalign对apk进行检测。如下:
zipalign -c -v 4 C:\Users\jason\Desktop\com\demo\jason\demo.apk
-c 表示进行zipalign优化检测
-v 输出过程信息
如果我们没有优化过我们的apk文件,则会认证失败,会看到Verification FAILED的相关信息。然后我们就可以优化我们的apk文件了。如下:
zipalign -f -v 4 C:\Users\jason\Desktop\com\demo\jason\demo.apk C:\Users\jason\Desktop\com\demo\jason\demo1.apk
-f 如果文件已经存在,强制覆盖
-v 输出详细信息
- 需要zipalign优化的apk 优化后的apk名称以及存放位置
运行完成后我们的指定文件架下就出现了我们已经优化好的apk文件了。如下图
我们这次执行我们的检测命令发现最后验证成功了(打印出Verification succesful)。
zipalign工具位于android-sdk\tools目录,源码位于android系统源码的build\tools\zipalign,它的主要工作是将apk包进行对齐处理,使apk包中的所有资源文件距离文件起始偏移为4字节整数倍,这样通过内存映射访问Apk文件时的速度会更快,验证apk文件是否对齐过的工作由ZipAlign.cpp文件的verify()函数完成,处理对齐的工作则由process()函数完成。
好了以上就是我们用纯命令行的方式打包一个apk文件的过程,是不是感觉很麻烦,我们一般在开发者没人这么搞,写这么多,主要是自己屡一下打包逻辑,同时帮助大家总结一下,让大家都知道整个apk是如何创建成功并进行签名优化的,其中用到了哪些工具。过程中也从巨人的肩膀上割了块肉过来,希望对大家有帮助,谢谢!