http://scz.617.cn/android/201608250928.txt
对apk签名是Android开发入门时就会碰上的问题,我从个人经历谈谈,不做全覆盖式 总结,只谈某些上下文里的坑。
我用Android Studio 2.1.2开发了一个apk,在此过程中,debug版的签名完全不用操心,我没深究在哪个环节由谁替我签了,我只知道debug版直接去模拟器上安装运行成功,那肯定是签过名了。
用AS生成release版时,用keytool生成JKS格式的keystore:
$ keytool -genkeypair -keystore ApkKeystore -alias Apk -keyalg RSA -validity 36500
签名过程是AS完成的,没有显式使用其他命令行工具。
用Apktool修改apk,重新编译打包得到:
com.anything.something_20160824-release-unsigned.apk
然后涉及重新签名,此时我想继续使用前述keystore中的数据,有两种方案。
keytool、jarsigner都是JDK中的工具,用AS的话,JDK肯定是安装了的。
$ jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore ApkKeystore -signedjar com.anything.something_20160824-release-unaligned.apk com.anything.something_20160824-release-unsigned.apk Apk
JDK 1.7之后"-signedjar"时,必须指定"-digestalg SHA1 -sigalg MD5withRSA"。老版JDK默认使用这两种算法,新版不是。
最初我不知道有这个坑,没有指定"-digestalg SHA1 -sigalg MD5withRSA",结果安装时提示:
INSTALL_PARSE_FAILED_NO_CERTIFICATES
但"jarsigner -verify"表明已签名。深究后就是现在看到的这样操作。
$ jarsigner -verify com.anything.something_20160824-release-unaligned.apk
jar 已验证。
优化:
$ zipalign -v 4 com.anything.something_20160824-release-unaligned.apk com.anything.something_20160824-release.apk
zipalign是Android SDK中的工具。
这个比较流行,但这玩意不是Android SDK中的工具,也不是AS自带的,得从Android 源码中获取,比如:
./Android/4.2.1_r1.2/build/tools/signapk/SignApk.java ./Android/4.2.1_r1.2/out/4.2.1_r1.2/host/linux-x86/framework/signapk.jar
前面说过,我想继续使用keystore中的数据,而很多文章演示的是openssl直接生成证书文件、私钥文件。这中间的关键变成,如何从keystore中导出为signapk.jar所认格式的证书文件、私钥文件。
从JKS转换成PKCS#12格式:
$ keytool -importkeystore -srckeystore ApkKeystore -srcalias Apk -destkeystore Apk.p12 -srcstoretype JKS -deststoretype PKCS12
导出证书:
$ openssl pkcs12 -in Apk.p12 -out Apk.crt -nokeys
导出私钥:
$ openssl pkcs12 -in Apk.p12 -out Apk.pem -nodes -nocerts
将私钥转成PKCS#8格式:
$ openssl pkcs8 -topk8 -inform PEM -outform DER -in Apk.pem -out Apk.pk8 -nocrypt
对apk签名:
$ java -jar signapk.jar Apk.crt Apk.pk8 com.anything.something_20160824-release-unsigned.apk com.anything.something_20160824-release-unaligned-2.apk
优化:
$ zipalign -v 4 com.anything.something_20160824-release-unaligned-2.apk com.anything.something_20160824-release-2.apk
在我的上下文里,显然jarsigner是最佳选择。两种重签名方案分别得到:
com.anything.something_20160824-release.apk com.anything.something_20160824-release-2.apk
adb安装app测试:
$ adb -s <device> install -r -s com.anything.something_20160824-release.apk
$ adb -s <device> install -r -s com.anything.something_20160824-release-2.apk
$ adb -s <device> uninstall com.anything.something
这里碰上个跟本文标题无关的困惑,不知为何,对于模拟器-s会失败,我分配了1GB 的SD卡,安装时仍然提示:
INSTALL_FAILED_CONTAINER_ERROR