Android aab转apk还原aab超过150MB 解决方案

前言:

各位同学的大家好,最近要上架google 遇到的一些问题 所以整理一下。这个解决方案是37互娱的同学提供的我也只是重新整理下 希望大家不要说我抄袭

背景

当前海外主要渠道是谷歌的Google Play,而根据Google Play的政策,2021年8月起,就需要使用Android App Bundle(aab)格式了。
而且谷歌对包体大小也做了限制,超过150MB的包无法上传,如果只上传小包,那么玩家在进入游戏时必然需要等待较长时间的游戏资源加载,影响转化。而如果想在安装时就附带游戏资源,突破150MB的限制,则需要接入谷歌提供的Play Asset Delivery功能。
更多的介绍可以回顾我们之前的文章。
Android apk和aab互相转换

问题

根据上述背景,海外游戏使用aab+pad的搭配必然是大势所趋了。而当研发接入pad功能后,就只能产出aab包了,因为pad是依赖于aab格式的。而旧有的切包流程是针对apk包的,不再适用于当前业务了,所以我们要怎样对aab+pad包进行切包,升级sdk代码?且看下文分解。

基本思路

我们先看看旧的针对APK的切包流程
这个流程里面最核心的是融合代码的过程,里面是包含了许多前辈的(工时)心血的,我们肯定不希望(加班)重新再写一次,如果能复用这部分的代码就好了。
那么怎样才能最大限度的利用已有的功能呢?

如果我们能够先把aab转成apk,那样就可以完全复用旧的逻辑,等到apk切包成功后,我们再将apk转回aab,岂不是完美?新的流程如下
那按计划,我们只需要做两件事情:

把研发输出的aab+pad转成apk

把切包后的apk转成aab+pad

计划很完美,接下来只需要按计划行事
aab+pad转apk
接入了pad的aab格式
首先我们先了解下aab+pad的文件组成,单纯的aab格式可以参考之前的文章政策工具类-谷歌Android App Bundle(aab)政策海外发行,而当接入了pad后,aab内的文件又会怎样呢?
按官方文档Android App Bundle 格式的介绍,pad的资源包是存在区别于主体代码文件夹(base/)的独立文件夹内的。
上图中紫色的部分就是pad的资源包。
asset_pack_1/ 和 asset_pack_2/ :对于需要大量图形处理的大型应用或游戏,您可以将资产模块化处理为资源包。……如需详细了解如何将资源包添加到您的 app bundle,请参阅 Play Asset Delivery 概览。
百闻不如一见,有了理论基础,我们直接找个aab+pad的包解压看看~
解压某个接入了pad的游戏的aab包,我们得到了

├── base/
    ├── dex/
    ├── .../
├── base_assets/
    ├── assets/
    ├── assets.pb
    ├── manifest/
        ├── AndroidManifest.xml
├── BundleConfig.pb
├── META-INF/
image.png

复制代码

其中base/,BundleConfig.pb,META-INF/都是老熟人了,那么毫无疑问,剩下的base_assets/就是研发接入的pad资源包了,实际上这个文件夹的名称取决于研发接入时的文件夹名称,是可变,我们在切包时需要考虑这个因素。
aab转apks
虽然计划是aab转apk,但是实际上aab并不能直接转apk,而是需要先转成apks文件。
处理aab文件,谷歌提供了一个专用的工具bundletool,详细的使用方法大家可以自行google,不再叙述。
那我们aab转apks自然也是要用到这个工具,具体是使用build-apks指令。
不过需要注意的是,aab转apks,一般情况是针对特定设备转换的,这时候不适用于该设备的资源就不会放进apks中,而我们的目的是进行切包,肯定是需要所有资源的,那么就需要用到build-apks指令的--mode=universal参数了,参数的具体含义和作用大家自行阅读文档。
所以完整指令是

java -jar bundletool.jar build-apks --mode=universal --bundle=my_app.aab --output=my_app.apks

然后我们就得到了一个apks文件。
apks转apk
apks实际上就是一个压缩包,可以直接解压,百闻不如一见,我们直接解压上述命令得到的apks文件看看,里面究竟有什么。

├── toc.pb
├── universal.apk

直接转命令

java -jar bundletool-all-1.6.1.jar build-apks \
--mode=universal \
--bundle=base.aab \
--output=test.apks \
--ks=luojian37.jks \
--ks-pass=pass:****** \
--ks-key-alias=****** \
--key-pass=pass:******

里面只有两个文件,toc.pb虽然我们不知道这是什么,但是pb文件一般都是提供配置信息,直接忽略,剩下的universal.apk文件就是我们需要的,包含了所有资源和代码的apk了。
拿到apk后,我们就可以使用旧流程进行切包,对apk内的代码进行升级了,之后我们就可以拿到切包后的apk文件。
至此,我们就按计划完成了第一步了,进度50%,一切顺利。
apk转aab
更加顺利的是,apk转aab我们之前的文章政策工具类-谷歌Android App Bundle(aab)政策海外发行已经有所介绍,按照文章介绍,最后我们就可以得到了一个aab包。难道我们已经成功了吗?
先别高兴得太早,滚动条的位置已经透露了事情没有那么简单。
aab+pad切包,pad的功能才是关键,所以我们还需要验证pad功能是否正常,我们解压转换得到的aab包,就会发现,pad功能对应的文件夹(上文中的base_assets)消失了。那么这个文件夹是什么时候丢失的呢?
我们仔细想想,apk是不支持pad功能的,所以应该是在aab转apks时,bundletool把pad的资源也合并进apk中了,而在--mode=universal中也有相关描述

注意:bundletool 仅包含功能模块,这些模块在通用 APK 中的对应清单中指定 。如需了解详情,请参阅功能模块清单。
bundletool会把功能模块包含进apk中,所以pad在转换的过程当中已经被合并进apk了。这意味着得到的aab包是不包含pad功能的,那就不能突破150M的限制了,所以还是不能上传到谷歌后台。

问题分析
所以我们现在的问题是,apk转aab的时候,pad资源丢失了,那么我们能不能在apk转aab时,把pad资源补回来呢?
根据之前的文章,政策工具类-apk转aab+pad中的生成aab+pad的包部分,我们知道,只要我们能提供pad的资源压缩包,那么就可以把pad重新打进aab中,所以我们的流程图调整如下

问题不大,我们只需要稍微调整计划,把需要做的事情变为:

从研发输出的aab+pad中提取pad压缩包
把研发输出的aab+pad转成apk
把切包后的apk转成base压缩包
把base压缩包和pad压缩包转化aab包

0x01 提取pad压缩包
上文已经提到,接入了pad的aab包目录结构如下

├── base/
    ├── dex/
    ├── .../
├── base_assets/
    ├── assets/
    ├── assets.pb
    ├── manifest/
        ├── AndroidManifest.xml
├── BundleConfig.pb
├── META-INF/

其中base_assets/目录就是pad资源,在它里面
assets/目录,一般就是游戏的资源,会直接合并到apk的assets中,保留。
assets.pb,pb文件是配置信息文件,由bundletool生成,压缩包内不需要,直接删除。
manifest/AndroidManifest.xml,为pad编译后的配置信息,决定了pad的下发规则,我们不需要更改研发决定的pad下发规则,所以保留即可。

按上所述,我们直接把pad目录下的assets/和manifest/压缩得到pad压缩包,留作后续步骤使用。压缩包的目录结构应如下
// pad.zip,名称随意,下文统一称pad.zip

├── assets/
├── manifest/
    ├── AndroidManifest.xml
  • 0x02 aab+pad转成apk

和上文完全一致,不再重复。

  • 0x03 apk转成base.zip

我们还是参考政策工具类-谷歌Android App Bundle(aab)政策海外发行, 不过这次我们只需要base.zip,所以只需要执行到压缩资源这一步即可。
这里我们还是讲一下那个脚本怎么生成的 因为手动很多人也不愿意去动
我们找到 bundletool.py 文件


image.png

然后把这里delete操作注释起来


image.png

在build_aab_tool\temp_20220621151158\modules 目录下面会有这个base.zip
image.png

细心的朋友应该已经发现,这里使用的apk包还是和之前一样,是包含了pad资源的,但是现在pad的内容在之前已经被压缩到pad.zip中了,所以如果还是全量资源放进base.zip中,那么在转换aab,合并base.zip和pad.zip时就会出现资源冲突的问题。
所以我们需要在编译资源前,把pad中的资源从apk的反编译目录中移除掉,所以我们得到的base.zip是不包含pad资源的。
  • 0x04 产出包含pad的aab

最后,我们顺利得到包含主要代码的base.zip和包含pad资源的pad.zip,就可以通过以下命令输出aab了

java -jar bundletool-all-1.6.1.jar build-bundle --modules=base.zip,install_time_asset_pack.zip --output=my.aab

如果一切顺利的话,那么我们就可以再次得到一个aab包,最后我们再次验证下有没有翻车。
验证
解压aab包可以发现pad的目录还存在,另外我们还可以
java -jar bundletool.jar validate --bundle my.aab
复制代码
如果打包后pad正常,那么输出的结果中会包含以下内容(base_assets为pad模块的名称,不同游戏会不同)

Asset packs:
    Asset pack: base_assets

最后总结:
本文介绍了aab+pad的切包流程的分析过程,以及所需要注意的细节,再次感谢37互娱的同学提供方案,我也是做个整理。希望文章能帮助到各位同学。以后我还会贡献更多有用的代码分享给大家。各位同学如果觉得文章还不错 ,麻烦给关注和star,小弟在这里

你可能感兴趣的:(Android aab转apk还原aab超过150MB 解决方案)