前言
我们在开发Android应用的时候,可能很少研究整个Apk生成的过程,一般如AS或者Eclipse的开发工具,在运行的时候会自动帮我们将代码与资源文件打包并签名,生成相应的apk文件,不知道大家有没有好奇整个apk的编译、打包过程呢,下面通过这篇文章,一块来了解一下一个Android的工程文件是怎么从代码、资源文件变成最终的apk文件的。
命令行演示Android工程项目资源的编译打包流程
参考官方文档的流程图,下面我们通过命令行手动的模拟一下整个流程:
本篇文章的环境
首先我的操作系统是基于Windows系统,JDK版本最终使用的是1.6(以上会出现异常),sdk-tools版本是21。
相关工具地址
创建Android工程文件
进入tools文件夹:
cd D:\eclipse\sdk\tools
命令行:
[android.bat] --target [target_id] --name [project_name] --path [project_path] --package [package_name] --activity[activity_name]
这些参数代表的意思:
占位符 | 描述 | 本文示例 |
---|---|---|
target_id | sdk版本 | 每个人电脑上面根据安装的版本不同,id对应的版本也不同,我电脑上的的8,即API21 |
project_name | 工程名称 | resource2apk |
project_path | 工程路径 | D:\优快云\ |
package_name | 包名 | com.csdn.lhy |
activity_name | 创建Activity的名称 | MainActivity |
D:\eclipse\sdk\tools\android.bat create project --target 8 --name source2apk --path D:\优快云\ --package com.csdn.lhy --activity MainActivity
运行结果如下,可以看到在相应的目录下,已经创建了该工程,注意此时是没有gen目录的,也就是说此时还没有生成R文件。
生成R.java
接下来,我们通过命令行处理相应的资源文件,来生成R文件。
命令行:
[aapt.exe] -f -m -J [gen_folder_path] -S [res_path] -I [android.jar_path] -M [manifest_path]
占位符 | 描述 | 本文示例 |
---|---|---|
aapt.exe | aapt工具路径 | D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe |
gen_folder_path | gen目录路径 | D:\优快云\gen |
res_path | res资源文件路径 | D:\优快云\res |
android.jar_path | 覆盖引导类文件的位置 | D:\eclipse\sdk\platforms\android-21\android.jar |
manifest_path | AndroidManifest.xml文件位置 | D:\优快云\AndroidManifest.xml |
D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe
D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe package -f -m -J D:\优快云\gen -S D:\优快云\res -I D:\eclipse\sdk\platforms\android-21\android.jar -M D:\优快云\AndroidManifest.xml
执行之后看到如下,在相应的gen目录下面,生成了R.java文件,注意到第一次这个命令行执行失败,需要人工创建一下gen目录,第二次执行成功,打开R文件,看到里面已经生成了相应的代码。
编译.java2.class
编译java文件生成class ,不要忘记R.java文件
注意:-bootclasspath
是必须要设置的, 它表示覆盖引导类文件的位置,如果不设置会报错,命令行如下:
javac -target [jdk_version] -bootclasspath [android.jar_path] -d [.java_path]
占位符 | 描述 | 本文示例 |
---|---|---|
jdk_version | jdk的版本 | 1.6 |
android.jar_path | 覆盖引导类文件的位置 | D:\eclipse\sdk\platforms\android-21\android.jar |
.java_path | .java文件的位置 | 即src文件下的.java以及gen目录下的R.java |
javac -target 1.6 -bootclasspath D:\eclipse\sdk\platforms\android-21\android.jar -d D:\优快云\bin D:\优快云\src\com\csdn\lhy\*.java D:\优快云\gen\com\csdn\lhy\R.java
运行成功的话,如下图所示,在bin目录下生成了相应的.class文件,注意不要忽略了R.java。
我们通过JD-GUI打开看一下,发现可以正常的反编译回来。
.class2.dex
class打包成dex,需要注意的是,dx工具最好使用创建项目中的sdk版本中的,与bootclasspath所用版本一致,命令行如下:
[dx.bat] --dex --output=[dex_path] [classes_path]
占位符 | 描述 | 本文示例 |
---|---|---|
dx.bat | dx工具的位置 | D:\eclipse\sdk\build-tools\build-tools-21.1.1\dx.bat |
dex_path | 打包后dex文件的生成路径 | D:\优快云\bin\classes.dex |
classes_path | 当前的.class字节码文件路径 | D:\优快云\bin\ |
D:\eclipse\sdk\build-tools\build-tools-21.1.1\dx.bat
D:\eclipse\sdk\build-tools\build-tools-21.1.1\dx.bat --dex --output= D:\优快云\bin\classes.dex D:\优快云\bin\
运行成功之后,结果如下图,我们发现在bin目录下已经生成了相应的dex文件:
打包资源文件
打包资源文件,将资源文件打包成resources.ap_文件,命令行如下:
[aapt.exe] package -f -m -S [res_path] -I [android.jar_path] -M[manifest_path] -F[resources.ap_]
占位符 | 描述 | 本文示例 |
---|---|---|
aapt.exe | aapt.exe路径 | D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe |
res_path | 项目中res资源文件位置 | D:\eclipse\sdk\platforms\android-21\android.jar |
android.jar_path | 覆盖引导类文件的位置 | D:\优快云\bin\ |
manifest_path | AndroidManifest.xml文件路径 | D:\优快云\AndroidManifest.xml |
resources.ap_ | 打包资源文件生成的resources.ap_文件路径 | D:\优快云\bin\resources.ap_ |
D:\eclipse\sdk\build-tools\build-tools-21.1.1\aapt.exe package -f -m -S D:\优快云\res -I D:\eclipse\sdk\platforms\android-21\android.jar -M D:\优快云\AndroidManifest.xml -F D:\优快云\bin\resources.ap_
运行结果如下:
生成未签名的apk
最终打包apk,需要使用apkbuilder.bat 必须放到tools文件夹下面:
[apkbuilder.bat] [unsigned_apk_path] -v -u -z [resources.ap_] -f [classes.dex] -rf [src_path]
占位符 | 描述 | 本文示例 |
---|---|---|
apkbuilder.bat | apkbuilder.bat路径 | D:\eclipse\sdk\tools\apkbuilder.bat |
unsigned_apk_path | 生成的未签名apk文件路径 | D:\优快云\bin\final.apk |
resources.ap_ | 打包资源文件生成的resources.ap_文件路径 | D:\优快云\bin\resources.ap_ |
classes.dex | classes.dex文件路径 | D:\优快云\bin\classes.dex |
src_path | src文件夹路径 | D:\优快云\src |
D:\eclipse\apkbuilder.bat
D:\eclipse\sdk\tools\apkbuilder.bat D:\优快云\bin\final.apk -v -u -z D:\优快云\bin\resources.ap_ -f D:\优快云\bin\classes.dex -rf D:\优快云\src
我们可以看到运行成功后,在相应的文件下生成了未签名的apk文件。
生成签名秘钥
创建密匙,会在当前C:\Users\用户名\
文件下下生成相应的签名证书文件:
keytool -genkey -alias release -keyalg RSA -validity 20000 -keystore release.keystore
apk签名
jarsigner -verbose -keystore [keystore_path] -storepass [password] -keypass [password] android -signedjar [signed_apk] [unsigned_apk] release
占位符 | 描述 | 本文示例 |
---|---|---|
keystore_path | 签名证书路径 | C:\Users\memphise\release.keystore |
password | 签名中自己设定的密码 | 我设置的是android |
signed_apk | 最终生成的签名之后的apk文件路径 | D:\优快云\bin\resource2jar-signed.apk |
unsigned_apk | 需要签名的apk文件路径 | D:\优快云\bin\final.apk |
jarsigner -verbose -keystore C:\Users\memphise\release.keystore -storepass android -keypass android -signedjar D:\优快云\bin\resource2jar-signed.apk D:\优快云\bin\final.apk release
运行结果如图,在bin目录下,生成了刚才签名的apk文件。
我们在模拟器上安装一下,可以看到运行成功,Hello World
异常总结
在将class文件打包成dex文件时候遇到:
com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
这是由于jdk版本与dx工具版本不一致的问题,解决方案参考了stackoverflow ,原本我的JDK版本是1.8,这里打包的时候就遇到了这个问题,最终降级到1.6之后解决了这个问题。
至于Eclipse,AS等工具,使用1.6版本以上的JDK仍然可以打包成功,有哪位大神可以告知一下么?