Android apk瘦身最佳实践(二):代码混淆和资源压缩

622 阅读3分钟
原文链接: www.jianshu.com

要尽可能减小 APK 文件,我们应该启用压缩来移除发布构建中未使用的代码和资源。

1. 使用 ProGuard 混淆代码

在 Android 中代码混淆和压缩都是通过 ProGuard 来实现的,ProGuard 会检测和移除代码中未使用的类、字段、方法和属性,除此外还可以优化字节码,移除未使用的代码指令,以及用短名称混淆类、字段和方法。

在 build.gradle 中,使用 minifyEnabled 属性来开启代码混淆:

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
    ...
}

2. 使用 shrinkResources 压缩资源

在 build.gradle 中使用 shrinkResources 属性来开启资源压缩,它在构建 apk 时可以移除那些没有引用到的资源文件,通常它必须与 minifyEnabled 属性一起使用:

release {
    shrinkResources true
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'),
            'proguard-rules.pro'
}

需要注意的是,开启该属性设置后,它并不会移除 values/ 文件夹中定义的资源,例如:字符串、颜色、样式等等。

3. 混淆压缩对比

为了鉴定一下代码混淆与资源压缩到底有多大作用,我们随便找个简单的 app 工程来实验一下。

minifyEnabled shrinkResources apk大小
false false 4,285,579 字节,约4.3M
true false 3,781,347 字节,约3.8M
true true 3,779,525 字节,约3.8M
false true 无法编译

从中我们可以得到一些结论:

  1. 开启代码混淆和资源压缩后,apk 大小减少了约0.5M,一个小工程都尚且如此,在一个比较庞大的工程中开启这俩选项,压缩的大小还是很可观的。
  2. 开启资源压缩与不开启相比,只减少了约2000多字节的大小,可见大头还是靠代码混淆,资源压缩只能起到锦上添花的作用。
  3. 关闭代码混淆开启资源压缩,你会发现无法编译,Android Studio 会提示你这俩必须配对使用,要开启资源压缩必须得开启代码混淆。

4. 资源压缩会保留文件名不保留内容

我们再做个测试,在应用的资源中放一张png图片姑且命名为 test.png,放一个layout布局文件命名为test.xml,并且确保这2个资源文件没有任何代码会引用,我们开启代码混淆和资源压缩打包生成apk文件。

生成apk文件后,直接将apk包拖到 Android Studio 中,可以查看apk包的相关信息,细心一点的话你会发现几个有趣的现象:

  1. 在图片资源文件夹中,仍然可以看到名为 test.png 的图片,但是你打开看到的是一个 1*1 的图片;
  2. 在 layout 文件夹中,仍然可以看到名为 test.xml 的文件,打开看到的是一个空的xml文件,没有任何xml节点信息;

也就是说,资源压缩后,并不是直接删除了没有用到的资源文件,而是生成了对应的占位文件,这些占位文件都是空文件,相比原文件大小可以忽略不计。这样做的原因是:每个资源文件都对应 R.class 里的一个资源 id ,资源 id 的映射关系会打包在 resources.arsc 文件里,如果直接删除了资源文件,则可能需要同时修改 resources.arsc 里的资源映射表,这样是很繁琐的过程,而用占位文件来替换则避免了这种情况。