APK瘦身-混淆代码

https://wx4.sinaimg.cn/mw690/c0755e72gy1ff8eyorepbj21jk0rcgvf.jpg

在文章中,你会发现适用于几乎所有应用程序的建议。全部都是关于如何保持你的代码库的清洁、检查依赖关系和一些帮助你完成上如任务的工具。

缩小Dex代码

你需要做的第一件事就是去开启 built-in 压缩(minifier)。它会试图删掉无用的类文件、类成员,同时也会对一些标识名称使用更短的名字。上述的所有操作能让最终的代码更精简,但是精简后的代码会让调试变得比较麻烦,所以我建议你只在release版中开启代码压缩的开关。

第二行以 ProGuard rules 格式为压缩提供了配置文件。第一个配置文件(Sdk/tools/proguard/proguard-android.txt)被包含在SDK中,并且包含了一些适用于每个Android工程的默认配置。通过查看这些规则能够帮助你熟悉Proguard的配置语法。例如,下面的配置能够使View 子类的任何get和set方法不被混淆(换句话说就是阻止被删除或者重命名)。

如果幸运的话,你的应用使用默认的配置就能够工作。在构建缓解,AAPT也会生成必要的规则来保证你在Manifest文件中声明的Activity等组件、在XML文件中的View组件不被混淆。第三方的依赖库需要通过 consumer ProGuard files提供它们的混淆配置,尽管有时候它们紧紧在它们的网站上提供必要的ProGuard规则。那种情况时,你将需要拷贝这些规则到你的app/proguard-rules.pro文件中。

有时候情况会比较不幸,当你的应用被开启压缩后,你的应用要么无法编译,要么是在运行时通过抛出因为压缩而删除了某些类而导致的ClassNotFoundException异常来中断。想要修复这个问题,你需要在你的app文件下创建proguard-rules.pro文件然后提供避免编译警告(观察log中信息)的规则。你也需要确保保留原本会被混淆的,但运行时需要使用的类和成员,这通常是你通过反射调用的代码。

一个比较特殊的情况是在XML中自定义属性通过字符串的形式使用了一个类命。例如设置RecyclerView 的layoutManager:

这种情况下,AAPT将不能推断出这个类的使用情景并未其生成必要的ProGuard规则。修复这个bug,你应该在ProGuard的配置中放置下面一行规则来保证GridLayoutManager类和它的公有、受保护的方法不被删除和重命名。

检查你写的配置规则是否拥有期待的效果,你可以通过ClassyShark](https://medium.com/google-developers/smallerapk-part-2-minifying-code-554560d2ed40#0643){:rel=”nofollow”}.等工具检查在apk中的classes.dex 。彻底测试你应用是非常重要的!事实上没有崩溃不代表你的混淆配置是正确的。为了防止崩溃,你必须测试你应用中的每个流程。

将混淆的映射文件上传至Play

分析被用户设备上混淆代码抛出的异常过去会有些不方便。通常你需要从Play开发者控制台拷贝堆栈信息并且使用自己电脑上的工具和在编译时生成的混淆映射文件还原原始的类名和方法名。

image

Play开发者控制台现在可以选择同时上传映射文件和APK,然后直接在Crash、ANRs面板上显示混淆解析后的堆栈信息。请记住,你上传的映射文件必须时你的编译release版APK产生的那个mapping文件。

提示:你可以在你项目的这个路径下找到mapping.txt文件:<module>/build/outputs/mapping/mapping.txt

第三方库的混淆配置

如果你正在构建一个AAR格式的第三方库被用于在其它需要混淆的项目中,你应该使用consumerProguardFiles选项来将混淆配置与AAR一起打包。这样,任何使用你的库的人都无需在开起混淆后为你的库手动添加混淆规则。当然你也需要确保为通过手动编译你的库的情况提供必要的混淆信息。

build.gradle

对Google Play服务使用细粒度依赖关系

https://wx2.sinaimg.cn/mw690/c0755e72gy1ff8fpkl8b9j20nh0a1gmt.jpg

当你在你的项目中使用Google Play服务时,记住选择使用更细粒度的依赖。这意味着当你只需要例如广告、GCM、等几个特性时,不需要去拉取整个库。你可以在developers.google.com上使用有Gradle依赖信息的表格。顺便说一句,混淆规则已经被加在Play服务中,因此如果你构建时开启了混淆它们应该也可以正常工作。

追踪依赖关系

开发Android应用一个很棒的事情是当你有一个问题时,很可能别人已经解决了它。随着你的项目的增长,你通常会获取越来越多的外部依赖来提高开发的速度。最常见的可能就是为了向下兼容的Android Support库、 Play服务、图片加载框架、HTTP客户端和其它各种各样的SDK。

开发者经常询问我,我该使用哪个图片加载框架?对少依赖对于我的项目是足够多的?对于这些问题没有确定的答案。如果你真的需要一个可以帮你解决问题的库(并且你明白优缺点)就可以使用它。重要的是有能够帮你评估这个库对于你的项目大小产生多少影响的合适工具,所以你可以做更明智的决定。

传递库依赖关系

当你认为你紧紧添加了一个非常小的工具类库后突然你的Dex大小爆炸,你的方法数超出预期。这可能是因为有在build.gradle文件中无法正常看到的传递依赖。幸运的是,有一些工具能够帮助你:

*:dependencies* 命令能够展示你项目中每个库的概括和它的依赖关系。版本号旁边的星号(*)表示这个特定的依赖关系在之前已经被提及过,因此它无论如何都会被添加到你的项目中,除非你删除所有其它的实例。

提示:如果你使用产品渠道的功能并且你在某些类型的应用上使用依赖(例如,广告SDK只会在免费版上使用),你能够使用你的渠道名称作为依赖的前缀,例如:dependencies { freeCompile ‘…’ }

用ClassyShark检查Dex文件

有时候为了防止开发人员的版本冲突,一个库通常直接通过代码来饮用其依赖的代码而不是通过改变包名(这里可能指通过gradle、maven等方式引用)。这也意味着你不会在Gradle依赖树中直接看见这种类型的依赖关系。

如果你希望能够更好的查看被打包进APK中的类和包名,你可以使用ClassyShark 去检查你的Dex文件。它对于测试你的混淆规则是否在最终的APK上有预期的效果也是非常棒的。

https://wx4.sinaimg.cn/sq612/c0755e72gy1ff8gx097uyj20m80hjq9k.jpg

注意:一个很赞的特性,ClassyShark会显示每个包的方法数,这样有助于帮助你去了解多Dex文件。



image           image
image           image
章节列表