开发中遇到的场景
- 上一篇文章我们讲了AAPT2命令行使用总结,里面有个使用场景就是将apk转为aab文件,aab文件是应用上架Google play的指定包格式,下面我们就来实践下
- 假如我们有这样一个场景需求,一个游戏或者应用接入了我们开发的聚合SDK,然后提供给我们一个apk包,我们拿到这个apk包可以使用打包工具来融合具体的渠道SDK或者插件,现在要出的这个包是上架海外的,那么就只有出aab包了。
- 我们通过打包工具先把融合的apk包打出来,然后对这个apk做进一步的处理
实践过程用到的工具
- apktool,反编译回编译apk的工具,下载地址:Apktool - A tool for reverse engineering 3rd party, closed, binary Android apps.
- bundletool,一种命令行工具,用于自行构建 app bundle 和 SDK Bundle,下载地址:Releases · google/bundletool · GitHub
- aapt2,是一种构建工具,解析资源、为资源编制索引,并将资源编译为针对 Android 平台进行过优化的二进制格式,在安装的SDK目录
android_sdk/build-tools/version/下找到aapt2,也可以最新的版本,比如下载3.2.0-alpha18-4804415版本,其他版本替换地址里面的版本就可以了
:https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/8.0.0-alpha07-9193536/aapt2-8.0.0-alpha07-9193536-windows.jar - android.jar,android提供的SDK开发包,在
android_sdk
/platforms/version
/下可以找到 - jarsigner,签名工具,安装的JDK bin目录下,配置了jdk的环境变量可以直接运行命令行
- 请安装好JDK并配置环境变量方便cmd窗口执行命令
使用命令行方式实现
- 首先选择一个目录,将下载的apktool、aapt2、bundletool、android.jar等工具拷贝到这个目录,方便我们执行命令,并准备一个打包好的apk也放到改目录,比如我新建的目录D:\workspace\LCQ\apk-aab:
- 接下来我们在文件地址栏里面输入cmd,按回车键,进入cmd命令界面
- 使用apktool命令将app-release.apk这个包进行反编译,执行命令
java -jar apktool_2.6.1.jar d app-release.apk -s -o decode_apk
我们重点关注反编译后的res文件夹,res里面的资源文件需要我们使用aapt2进行编译,生成符合Google的协议缓冲区格式要求的文件
-
我们使用aapt2的compile命令来编译res文件夹
aapt2 compile --dir decode_apk\res -o compiled_resources.zip
可以看到生成的zip压缩包里面都是.flat或arsc.flat后缀的二进制文件
-
我们再使用aapt2的链接命令生成一个base.apk
aapt2 link --proto-format -o base.apk -I android.jar --manifest decode_apk\AndroidManifest.xml -R compiled_resources.zip --auto-add-overlay
我们将这个base.apk文件进行解压,新建一个manifest文件夹,将AndroidManifest.xml文件移动到里面去,然后将apktool反编译生成的目录(decode_apk)里面的assets、lib拷贝到base,将.dex后缀的所有文件拷贝到module/dex,将unknown、kotlin拷贝到module/root,最终的目录就长这样了
-
然后我们选中module下的所有文件和目录,压缩成.zip文件,如图
请确保压缩后的zip文件打开后没有把base目录压缩进去,我们把压缩好的base.zip拷贝到bundletool同目录下,
-
在我们进行拷贝的时候一定要注意,不要将反编译生成的目录和aapt2链接生成解压的base目录资源搞错了,否则bundletool 命令会报失败的,比如InvalidProtocolBufferException异常
[BT:1.12.1] Error: com.google.protobuf.InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag. java.io.UncheckedIOException: com.google.protobuf.InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag. at com.android.tools.build.bundletool.model.BundleModule$Builder.addEntry(BundleModule.java:418) at com.android.tools.build.bundletool.model.BundleModule$Builder.addEntries(BundleModule.java:399) at com.android.tools.build.bundletool.model.utils.BundleModuleParser.parseBundleModuleInternal(BundleModuleParser.java:66) at com.android.tools.build.bundletool.model.utils.BundleModuleParser.parseAppBundleModule(BundleModuleParser.java:41) at com.android.tools.build.bundletool.validation.BundleModulesValidator.lambda$validate$0(BundleModulesValidator.java:75) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) at java.base/java.util.Collections$2.tryAdvance(Collections.java:4747) at java.base/java.util.Collections$2.forEachRemaining(Collections.java:4755) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) at com.android.tools.build.bundletool.validation.BundleModulesValidator.validate(BundleModulesValidator.java:76) at com.android.tools.build.bundletool.commands.BuildBundleCommand.execute(BuildBundleCommand.java:231) at com.android.tools.build.bundletool.BundleToolMain.main(BundleToolMain.java:78) at com.android.tools.build.bundletool.BundleToolMain.main(BundleToolMain.java:54) Caused by: com.google.protobuf.InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag. at com.google.protobuf.InvalidProtocolBufferException.invalidEndTag(InvalidProtocolBufferException.java:129) at com.google.protobuf.CodedInputStream$StreamDecoder.checkLastTagWas(CodedInputStream.java:2124) at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:217) at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:232) at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:237) at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:48) at com.google.protobuf.GeneratedMessageV3.parseWithIOException(GeneratedMessageV3.java:339) at com.android.aapt.Resources$XmlNode.parseFrom(Resources.java:44493) at com.android.tools.build.bundletool.model.BundleModule$SpecialModuleEntry$1.addToModule(BundleModule.java:459) at com.android.tools.build.bundletool.model.BundleModule$Builder.addEntry(BundleModule.java:416) ... 16 more
-
接下来我们就使用bundletool命令来生成aab文件了,执行命令
java -jar bundletool-all-1.12.1.jar build-bundle --modules=base.zip --output=module.aab
可以看到aab文件以及生成了,现在这个是无法使用bundletool工具直接进行安装测试的,因为还没有进行签名,aab的签名只能用jarsigner,不能使用apksigner
-
使用jarsigner命令对base.aab进行签名
jarsigner -digestalg SHA1 -sigalg SHA1withRSA -keystore 你的签名文件.jks -storepass 秘钥文件密码 -keypass 秘钥密码 base.aab 别名
-
可以看到签名成功了,生成了META-INF目录,里面有签名信息文件
这个签名后的base.aab文件就可以用来测试上传google play 了
-
如果要测试aab文件的话,也需要使用bundletool的命令行,我们先让adb连接上设备,生成设备信息json文件
java -jar bundletool-all-1.12.1.jar get-device-spec --output=./device-spec.json
-
然后生成apks
java -jar bundletool-all-1.12.1.jar build-apks --bundle=base.aab --output=abase.apks --overwrite --ks=你的签名文件.jks --ks-pass=pass:"111111" --ks-key-alias=别名--key-pass=pass:"111111"
-
然后将apks安装到对应的设备文章来源:https://www.toymoban.com/news/detail-427077.html
ava -jar bundletool-all-1.12.1.jar install-apks --apks=base.apks
提示:由于这个是我们使用apk自行进行生成aab的,中间处理过程可能会存在文件遗漏,特殊情况未处理等,肯定是没有AS生成的aab更可靠,还是建议使用AS生成的aab进行上架自己的应用文章来源地址https://www.toymoban.com/news/detail-427077.html
到了这里,关于使用apktool、aapt2、bundletool将apk转为aab(Android App Bundle)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!