终于来到了这一个章节,其实这个是之前一个小的“梦想”,但是真正到实现它的时候,感觉还蛮简单的,但是做完一件事总会有一些成就感,所以,我们今天就来完成这个事情,如果你还不知道 Dex 文件和资源文件怎么生成,请参考我前面几篇文章
聊聊 APK —— 直接运行 Dex
聊聊 APK —— Dex 热修复与 Classpath
聊聊 APK —— aapt 编译资源
创建工程
首先,我们构造工程,昨天的工程如果还在的话就很简单,我们写一个MainActivity.java
,如下
请无视这个波浪线,因为我没设置 classpath,这里的代码纯靠记忆手打=。=,导入包想了半天。
我们就新加了一个MainActivity.java
,然后新建了一个build
目录,供一会生成classes
文件用。同时,为了MainActivity
能使用,我们需要在AndroidManifest.xml
中对MainActivity
进行声明,然后要为 App 提供一个 Icon。因此,经过改造后,我们目录如下。
重新编译资源
我们因为新加了资源,修改了 AndroidManifest.xml,这时候需要重新调用aapt2 compile
和aapt2 link
,但是之前我们编译过activity_main.xml
,所以不需要编译,我们只需要编译drawable/ic_launcher
就行了,命令如下:
aapt2 compile src/main/res/drawable/ic_launcher.png -o compiled
compiled 目录下,就会出现drawable_ic_launcher.png.flat
这个文件了,这时候重新调用 link。
aapt2 link -o resources.ap_ \
-I $ANDROID_HOME/platforms/android-28/android.jar \
compiled/layout_activity_main.xml.flat \
compiled/drawable_ic_launcher.png.flat \
--java src/main/java \
--manifest src/main/AndroidManifest.xml
开始编译
好了,这样我们就开始使用javac
编译了。首先我们要知道,java工具链中是没有 android sdk 的,所以我们需要在编译的时候导入 classpath。
文件准备好了之后,编译命令如下:
javac -d build -cp $ANDROID_HOME/platforms/android-28/android.jar src/main/java*.java
其中-d
表示输出目录,-cp
表示 classpath,后面跟着输入文件,src/main/java 目录下面所有的 java 文件。
我们打开 build 目录
可以看见我们的 class 文件就出来了。里面有 MainActivity、R,还有 R 的内部类 R$layout,我们开始执行 dex 转换
dx 化
执行命令:
dx --dex --output=classes.dex build
我们在当前目录下就得到了一个 classes.dex 文件。
生成 APK 之前的检查
接下来其实我们代码上的准备工作基本做完了,在进行最后几步之前,我们再来温习一下一个正常 apk 的结构
- classes.dex
- 资源文件
- resources.arsc
- 签名摘要
- 可选的 assets 等
那么我们还剩下签名没做,这个暂时可以等一下,我们先把前面3个合起来,这个很简单,首先对我们利用 aapt 构造出来的ap_
文件,复制一份,重命名成 apk 文件
cp resources.ap_ app-debug.apk
拿到了一个 apk(其实是zip文件),然后把 classes.dex 加进去。
zip -ur app-debug.apk classes.dex
输出
adding: classes.dex (deflated 47%)
其实现在我们的 app-debug-unsigned.apk 是做完了。可以安装试一下,但是输出如下:
adb: failed to install app-debug.apk: Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES: Failed to collect certificates from /data/app/vmdl110235550.tmp/base.apk: Attempt to get length of null array]
签名 apk
啊噢,没有证书信息,我们其实可以用android debug key
进行签名,这样最简单,我们可以看一下怎么签名呢,我们要用到apksigner
这个工具,首先输出下帮助
apksigner --help
得到如下信息:
USAGE: apksigner <command> [options]
apksigner --version
apksigner --help
EXAMPLE:
apksigner sign --ks release.jks app.apk
apksigner verify --verbose app.apk
apksigner is a tool for signing Android APK files and for checking whether
signatures of APK files will verify on Android devices.
COMMANDS
sign Sign the provided APK
verify Check whether the provided APK is expected to verify on
Android
version Show this tool's version number and exit
help Show this usage page and exit
它可以进行签名,也可以进行验证。OK,这时候使用 linux/macOS 的同学就很简单了,android 的 debug.keystore 默认在 ~/.android/debug.keystore 下,密码是 android。 那么我们调用如下命令:
apksigner sign -ks ~/.android/debug.keystore app-debug-unsigned.apk
这时候会让我们输入密码,我们输入android
即可。
Keystore password for signer #1:
这时候,你的 apk 名字还是app-debug-unsigned.apk
,其实已经签名了,我们可以检查一下:
apksigner verify --verbose app-debug-unsigned.apk
看到如下输出:
Verifies
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
Number of signers: 1
好了,签名成功。
再次安装 APK
到了激动人心的时候了,这时候我们调用安装
安装成功!
再看手机桌面上,有我们的图标了:
大胆点击它!
本文由 Gemini Wen 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Dec 19, 2020 at 10:26 am