使用apktool、aapt2、bundletool将apk转为aab(Android App Bundle)

开发中遇到的场景

  • 上一篇文章我们讲了AAPT2命令行使用总结,里面有个使用场景就是将apk转为aab文件,aab文件是应用上架Google play的指定包格式,下面我们就来实践下
  • 假如我们有这样一个场景需求,一个游戏或者应用接入了我们开发的聚合SDK,然后提供给我们一个apk包,我们拿到这个apk包可以使用打包工具来融合具体的渠道SDK或者插件,现在要出的这个包是上架海外的,那么就只有出aab包了。
  • 我们通过打包工具先把融合的apk包打出来,然后对这个apk做进一步的处理

实践过程用到的工具

使用命令行方式实现

  • 首先选择一个目录,将下载的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安装到对应的设备

    ava -jar bundletool-all-1.12.1.jar install-apks --apks=base.apks

提示:由于这个是我们使用apk自行进行生成aab的,中间处理过程可能会存在文件遗漏,特殊情况未处理等,肯定是没有AS生成的aab更可靠,还是建议使用AS生成的aab进行上架自己的应用

猜你喜欢

转载自blog.csdn.net/qq_19942717/article/details/127716913