AndResGuard 源码解析
AndResGuard 简介
AndResGuard 是一个开源工具,作用是帮助缩小 APK 大小。它的原理类似 Java Proguard,但是只针对资源。他会将原本冗长的资源路径变短,例如将 res/drawable/wechat 变为 r/d/a,同时支持压缩资源文件。
AndResGuard 不涉及编译过程,只需输入一个apk(无论签名与否,debug版,release版均可,在处理过程中会直接将原签名删除),可得到一个实现资源混淆后的apk(若在配置文件中输入签名信息,可自动重签名并对齐,得到可直接发布的apk)以及对应资源ID的mapping文件。
用法如下:
|
|
源码分析
主流程分析
下面开始分析 AndResGuard 的源码。克隆整个工程的源码,看根目录下的 AndResGuard 模块:
AndResGuard 是作为一个 gradle 插件提供给大家使用的。作为一个 gradle 插件,它的入口在 META-INF/gradle-plugins/AndResGuard.properties 里的 com.tencent.gradle.AndResGuardPlugin 类里。
AndResGuardPlugin 是使用 groovy 语言编写的。首先会执行 AndResGuardPlugin 的 apply 方法,此方法调用的 createTask 方法有两行代码:
|
|
可知 android 打包任务完成后会执行 AndResGuardTask 任务。
AndResGuardTask 的 run 方法 -> Main.gradleRun(inputParam) -> resourceProguard() ,resourceProguard 方法如下:
|
|
decodeResource 方法,它调用了 ApkDecoder 的 decode() 方法:
|
|
解析 resources.arsc
resources.arsc 文件结构图如下:
源码中总共进行了两次解析。
第一次解析
RawARSCDecoder.decode(apkFile.getDirectory().getFileInput(“resources.arsc”))
调用链如下: RawARSCDecoder#readTable() -> RawARSCDecoder#readTablePackage() -> RawARSCDecoder#readLibraryType() -> RawARSCDecoder#readTableTypeSpec() -> RawARSCDecoder#readConfig() ->RawARSCDecoder#readEntry() -> RawARSCDecoder#putTypeSpecNameStrings .
putTypeSpecNameStrings 方法会把 各种资源对应的原始资源名称保存到集合 mExistTypeNames 中。mExistTypeNames 的 key 为 资源类型,value 为该类型对应的资源名称列表。设置该集合的目的是避免混淆后的名称与混淆前的名称出现相同的情况。
第二次解析
ResPackage[] pkgs = ARSCDecoder.decode(apkFile.getDirectory().getFileInput(“resources.arsc”), this)
在 decoder.readTable() 方法里看一下解析过程:
|
|
readPackage() -> readTableTypeSpec() -> readConfig() -> readEntry()
解析具体的资源项 readEntry 中调用了 readValue() 方法:
|
|
重新生成 resources.arsc
解析完成之后会重新生成 resources.arsc 文件,看一下 writeTable 方法:
|
|
writePackage() ->
|
|
对于 writeSpecNameStringBlock 方法,该方法的第 3 个参数 Map
|
|
重新签名打包
该部分工作在 buildApk(decoder, apkFile, outputFile, signatureType, minSDKVersoin) 方法里完成。重新打包完成后,需要重新签名,以 APK 签名方案 v2 签名为例:
|
|