38

开源 | AabResGuard: AAB 资源混淆工具

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzI1MzYzMjE0MQ%3D%3D&%3Bmid=2247485425&%3Bidx=1&%3Bsn=77d0edcd8ccd174dd9901b603b1b2eac
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

AabResGuard是字节跳动抖音技术团队开源的一款针对 .aab 文件的资源混淆工具。

AabResGuard于 2019 年六月研发完成,于 2019 年七月底在 Tiktok、Vigo 等多个海外产品上线,为海外产品提供了资源保护和包大小优化的能力。

经过实践与验证, AabResGuard 上线后稳定运行,于是团队将其开源到社区。为了支持更多场景, AabResGuard 提供了 gradle plugin 和可以单独运行的 jar 包。除此之外,还提供了除资源混淆之外的一些额外特性。

Github 项目地址:

https://github.com/bytedance/AabResGuard

开发背景

什么是 AAB ?

AAB即 Android App Bundle ,是 Google 推出的 APK 动态打包,动态组件化的技术,通过一个 .aab 结尾的 bundle 文件组装一个最适合你手机机型的 APK 来为你的设备安装。

An Android App Bundle is a new upload format that includes all your app’s compiled code and resources, but defers APK generation and signing to Google Play.

简介:Android app bundle ( https://developer.android.com/guide/app-bundle/ )

为什么要对 AAB 文件进行资源混淆?

资源混淆的意义:保护资源和缩减包体积。

经过统计,APK 大小与安装转换率之间存在负相关关系。这种转换率的下降不仅是由于人们只是选择不安装,而是由于各种原因安装未完成。通过统计,APK 大小约为 10MB 的应用程序的下载完成率将比 APK 大小为 100MB 的应用程序 高约 30% (数据来源于 Google play internal data)。

受 Google play 政策的影响,2019 年八月底 Google play 上的应用必须包含 64 位 so 库,这一政策无疑会对包大小造成爆炸性增长,我们最终决定选用 Android app bundle 方案。

上了 Android app bundle 方案后,我们通过 AAB 导出了一份 APK 文件进行包大小的对比,结果发现,包的体积变得更大了,其中的差异主要集中在资源上。

目前绝大数 APP 都使用了微信的 「APK 资源混淆」方案 AndResGuard ( https://github.com/shwenzhang/AndResGuard ),通过缩减资源来达到减少 APK 的包体积的目的。

由于 .aab.apk 文件结构的差异,APK 的资源混淆方案是不适用于 AAB 的。

这部分资源混淆的收益我们不能放弃,于是产出了一份针对 .aab 文件的资源混淆工具 AabResGuard

收益

以下数据为 AabResGuardtiktok-9.4.0 版本上的收益,由于每个应用对资源的优化程度不同,所以该数据在不同的应用上的优化不同,以实际数据为准。

AAB 文件实际上只是一种压缩包的格式(只用于上传 Google play store),最终用户下载的时候会通过用户手机机型配置的不同,生成一个最适配该配置的 APK, 用户最终安装和下载的是 APK 文件

文件格式 资源压缩前 资源压缩后 资源压缩比 AAB 35.8MB 27.2MB 24% APK(Download size) 14.8MB 12.3MB 16.90%

不同手机的配置不同,所以收益体现不同,上表为(sdk16/arm64/480)的手机配置,由于 Google play store 对包体积会有二次压缩,所以实际的收益有所减少,具体线上数据的收益请参考 APK download size 的收益。

原理介绍

AAB 和 APK 文件结构的差异

*.aab 和  *.apk 文件的结构对比如下图所示:

7ZJz6bI.jpg!web

从图中可以看出, *.aab 和  *.apk 文件结构明显不同, *.aab 文件中的资源索引文件为  resources.pb ,而  *.apk 文件中的资源索引文件为  resources.arsc 文件,二者的结构不同,解析自然也不相同,并且  *.aab 中的文件包含  dynamic feature 目录,所以  *.aab 中需要混淆更多的文件内容。

AAB 文件的解析

AabResGuard是依赖于 bundletool 来完成 .aab 文件的解析、修改等相关操作的,而 bundletool 不同的版本之间差异较大,不同的版本之间可能会有一些兼容问题。

目前 AabResGuard 依赖了 bundletool-0.10.0 版本,如果通过 gradle 配置引入 AabResGuard ,可能会覆盖 AGP(Android gradle plugin) 本身依赖的 bundletool 版本,从而导致版本的兼容问题。

为了解决这个问题我们是通过使用 Shadow ( https://imperceptiblethoughts.com/shadow/ ) 对引入的其他库的 package 重定向并且解除了 AabResGuard-plugin 中对 bundletool 的传递依赖。

AVbmqaa.png!web

资源混淆

最小字符替换, AabResGuard 会对资源文件进行混淆,替换原始的资源名称、路径为最短字符,以达到缩减包体积和资源保护的作用。

nAryI3a.jpg!web

一个资源的组成有这么几部分:id、name、path 等,我们混淆的内容为:name、path,这二者在原始文件中默认是一一对应的(name 即为 path 的文件名称),但其实这二者并无关联,如果混淆后还是以 name 作为 path 的名称,无疑会造成空间的浪费。

IvURvqU.png!web

如果 res/drawable-xxhdpi 路径下只有一个文件的话,无疑会造成两个字符的空间浪费。

AabResGuard对每个文件夹下的文件和不同 type 的资源名称均采用单独混淆的方式,以保证每个文件夹下的文件和每种资源均为最短路径。

并且输出的 mapping 中保存了文件的资源 id,方便遇到问题后进行快速定位资源。

文件去重

AabResGuard会对包中的重复资源进行 md5 去重 ,md5 相同的资源文件只会保留一份,并且会重定向 resources.pb 中被去重的资源文件路径。

文件去重在 tiktok 上减小了 4050 个文件,减小文件大小 0.6MB,由于 tiktok 对资源还有其他方面的优化,所以部分资源大小本身较小,不同应用的收益不同,以实际收益为准。

文案过滤

工程中除了无用资源文件之外,还有一些字符串资源(包括语言)也是无效的,这部分资源也会占用包体积,这部分资源是可以进行移除的,通过更改 resources.pb 文件来移除这部分资源以达到缩减包体积的作用。

事实证明,资源中占比最大的还是字符串资源,通过对无用字符串的移除,这部分收益可观,在 tiktok 上减少字符串个数 3691 个,减少语言 37 种,最大收益可达 2.5M。

AabResGuard 的特性与使用

特性

  • 资源去重:对重复资源文件进行合并,缩减包体积。

  • 文件过滤:支持对 bundle 包中的文件进行过滤,目前只支持 MATE-INFO/lib/ 路径下的过滤。
  • 白名单:白名单中的资源,名称不予混淆。

  • 增量混淆:输入 mapping 文件,支持增量混淆。
  • 文案删除:输入按行分割的字符串文件,移除文案及翻译。

使用

  • 命令行工具:支持命令行一键输入输出。

  • Gradle plugin :支持 gradle plugin ,使用原始打包命令执行混淆。

Gradle plugin

build.gradle(root project) 中进行配置:

EnuqIru.png!web

build.gradle(application) 中配置:

BbaIBbE.jpg!web

aabResGuard plugin 侵入了 bundle 打包流程,可以直接执行原始打包命令进行混淆。

zMZ3u2a.png!web

通过 gradle 获取混淆后的 bundle 文件路径:

QV3Ujy2.png!web

命令行支持

AabResGuard提供了 jar 包,可以使用命令行直接执行。

EjI7Vf7.png!web

配置文件 config.xml ,白名单支持「正则表达式」:

a6Bn6nE.jpg!web

更多命令的使用,请移步命令行支持 ( https://github.com/bytedance/AabResGuard/blob/develop/wiki/en/COMMAND.md )。

产物

VfqaQzE.png!web

resources-mapping

用于记录资源混淆规则的日志文件,示例如下:

JZvy6jj.jpg!web
  • res dir mapping: 存储资源文件目录的混淆规则。格式:dir -> dir( res/ 根目录不可以被混淆)
  • res id mapping:存储资源名称的混淆规则。格式:resourceId : resourceName -> resourceName(增量混淆时,resourceId 不会被读入)

  • res entries path mapping:存储资源文件路径的混淆规则。格式:resourceId : path -> path(增量混淆时,resourceId 不会被读入)

-duplicated.txt

用于记录被去重的资源文件,示例如下:

rM7vuaj.jpg!web

展望与总结

QJFFNvQ.png!web

AabResGuard的可扩展性强,「资源混淆」、「资源去重」、「文件过滤」、「字符串过滤」等功能均可独立运行。并且框架的设计使 AabResGuard 不光是针对资源混淆的工具,更多的是提供了方便我们对 *.aab 文件进行解析、更新等操作。

如:某些情况下我们需要通过 AAB 导出一个全量的 APK 包,这种情况下导出的 APK 会包含所有的资源,但是我们希望只有一种维度的 so,我们可以过滤 32 位 so 来生成一个 64 位的 AAB 文件以达到目的。

如果因为某些特殊需求需要对 *.aab 文件进行二次修改的话,可以对 AabResGuard 进行扩展以快速达到目的。

参考资料

Android app bundle ( https://developer.android.com/guide/app-bundle )

AndResGuard ( https://github.com/shwenzhang/AndResGuard )

Aapt2 ( https://android.googlesource.com/platform/frameworks/base.git/+/master/tools/aapt2 )

Bundletool ( https://github.com/google/bundletool )

Shadow ( https://imperceptiblethoughts.com/shadow/ )

Shrinking APKs, growing installs ( https://medium.com/googleplaydev/shrinking-apks-growing-installs-5d3fcba23ce2 )

6nyEbmB.jpg!web

欢迎关注「字节跳动技术团队」

EbaUbuj.png!web 点击阅读原文,直达 GitHub!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK