android apk瘦身(2) R8编译器:压缩代码、压缩资源、优化代码
1.官方文档
https://developer.android.com/studio/build/shrink-code
当您使用 Android Studio 3.4 或 Android Gradle 插件 3.4.0 及更高版本时,R8 是默认编译器,用于将项目的 Java 字节码转换为在 Android 平台上运行的 DEX 格式。同时还提供以下功能(默认关闭):
- 压缩代码 : 从应用及其库依赖项中检测并安全地移除不使用的类、字段、方法和属性
- 压缩资源 : 从封装应用中移除不使用的资源,包括应用库依赖项中不使用的资源。
- 混淆代码 : 缩短类和成员的名字,从而减小 DEX 文件的大小.
- 优化代码 : 检查并重写代码,深层次优化代码。
2.压缩代码
2.1 开启
R8 首先会根据组合的配置文件集确定应用代码的所有入口点。这些入口点包括 Android 平台可用来打开应用的 Activity 或服务的所有类。从每个入口点开始,R8 会检查应用的代码来构建一张图表,列出应用在运行时可能会访问的所有方法、成员变量和其他类。系统会将与该图表没有关联的代码视为执行不到的代码,并可能会从应用中移除该代码。
在对应模块的build.gradle内 minifyEnabled true 开启。
1 android { 2 compileSdkVersion 30 3 buildToolsVersion '30.0.2' 4 ... 5 buildTypes { 6 debug { 7 minifyEnabled false 8 } 9 release { 10 minifyEnabled true 11 12 } 13 } 14 }
2.2 保留代码
在项目的Proguard配置文件中使用 -keep 可保留不被压缩或混淆的代码。如:
1 # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory, 2 # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) 3 -keep class * extends com.google.gson.TypeAdapter 4 -keep class * implements com.google.gson.TypeAdapterFactory 5 -keep class * implements com.google.gson.JsonSerializer 6 -keep class * implements com.google.gson.JsonDeserializer 7 8 # Prevent R8 from leaving Data object members always null 9 -keepclassmembers,allowobfuscation class * { 10 @com.google.gson.annotations.SerializedName <fields>; 11 }
3.压缩资源
3.1 开启
在对应模块的build.gradle内 shrinkResources true 开启。
压缩资源必需在与压缩代码 开启后,才有效。只有在移除所有不使用的代码后,才能准确定位所有未使用的资源。
1 android { 2 compileSdkVersion 30 3 buildToolsVersion '30.0.2' 4 ... 5 buildTypes { 6 debug { 7 minifyEnabled false 8 shrinkResources false 9 } 10 release { 11 minifyEnabled true 12 shrinkResources true 13 14 } 15 } 16 }
开启后,构建apk时,编译器移除不使用的资源,包括应用库依赖项中不使用的资源。
3.2 保留资源
在res/raw/下新建xml文件,其中可定义要保留或者丢弃的资源文件。如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources xmlns:tools="http://schemas.android.com/tools" 3 tools:keep="@layout/l_used*_c,@color/svg_color_selector" 4 tools:shrinkMode="strict" 5 tools:discard="@layout/unused2" 6 />
tools:keep
属性中指定要保留的资源tools:discard
属性中指定要舍弃的资源
tools:shrinkMode 压缩模式,可取值为[ strict ,safe ] :
- scrict 严格按照keep和discard指定的资源留或舍。
- safe:保守的删除未引用资源,如代码中用 Resources.getIdentifier() 引用的资源,会保留。如下:
1 val name = String.format("img_%1d", angle + 1) 2 val res = resources.getIdentifier(name, "drawable", packageName)
- 多个资源文件中 以逗号分隔
- 可以使用通配符*。
- 这个xml文件可以有多份
3.3 优化记录文件
Gradle 会在 <module-name>/build/outputs/mapping/release/
(ProGuard 输出文件所在的文件夹)中创建一个名为 resources.txt
的诊断文件。此文件包含一些详细信息,比如,哪些资源引用了其他资源,哪些资源在使用,哪些资源被移除。
3.4 在项目源码中删除无用资源
这个要谨慎
在android studio中选择菜单项
- Refactor -> Remove unused Resources...
- Preveiew 查看有哪些未使用
- Do Refactor 确认删除
4.去掉多余语言资源文件
4.1 默认
android studio 工具默认会为@strings/xxx 内的字符资源 生成116个版本。
使用 resConfigs 可指定只用到的版本,去掉其它的。
1 android { 2 compileSdkVersion 30 3 buildToolsVersion '30.0.2' 4 defaultConfig { 5 applicationId "com.jiankangyangfan.nurse" 6 minSdkVersion 19 7 targetSdkVersion 30 8 ... 9 resConfigs "zh-rCH","zh-rHK","zh-rTW" 10 } 11 ... 12 }
resConfigs 的取值可以通过一个未压缩的包中查看(上图中红色框内),然后选择目标版本。(奇怪红框部分并没有发现一个叫"en"的版本)
4.2 语言配置的第1种写法
[ 语种码 - 语言区域码(前缀用小写字母 r) ]
en
fr
en-rUS
fr-rFR
fr-rCA
具体参见: 语种码 ISO 639-1 语言区域码:ISO 3166-1-alpha-2
4.2 语言配置第二种写法(Android 7.0引入)
[ b +
语种码 + 其他子标记 ]
b+en
b+en+US
b+es+419
具体参见: BCP 47 语言标记
5.混淆代码:缩小dex文件
混淆处理不会从应用中移除代码,但如果应用的 DEX 文件将许多类、方法和字段编入索引,那么混淆处理将可以显著缩减应用的大小。
R8 在每次运行时都会创建一个 mapping.txt
文件,其中列出了经过混淆处理的类、方法和字段的名称与原始名称的映射关系。
此映射文件还包含用于将行号映射回原始源文件行号的信息。此文件保存在 <module-name>/build/outputs/mapping/<build-type>/
目录中。每次发布新版本时都要注意保存一个该文件的副本.
在 proguard-rules.pro 中加入以下代码可以还原行号 、 输出R8优化记录、输出混淆时被保留的入口类。
1 -keepattributes LineNumberTable,SourceFile 2 -printconfiguration ./build/tmp/full-r8-config.txt 3 -printseeds ./build/tmp/seeds.txt
-keepattributes LineNumberTable,SourceFile
用来保留源文件和行号信息。可用来还原混淆。
- -printconfiguration ./build/tmp/full-r8-config.txt 把混淆记录写入到文件full-r8-config.txt中。
- -printseeds ./build/tmp/seeds.txt 把混淆入口类输出到seeds.txt中。
6.优化代码
R8 可深层次优化代码,在项目的 gradle.properties
文件中添加以下代码来启用深度优化功能:
android.enableR8.fullMode=true
开启后可能引起不确定bug或者崩溃,谨慎开启。
具体的优化选项在:
7.R8配置文件
R8根据ProGuard配置文件决定优化策略,一个项目中可能有多个模块,每个模块都可以自定义对应的R8配置文件。它们是累加的。一个模块中的配置可能影响到其它模块。
来源 | 位置 |
Android Studio | <module-dir>/proguard-rules.pro |
Android Gradle 插件 |
proguard-android-optimize.txt 由 Android Gradle 插件在编译时生成。 |
库依赖项 |
AAR 库:
JAR 库:
|
Android 资源打包工具 2 (AAPT2) |
使用
|
自定义配置文件 |
默认情况下,当您使用 Android Studio 创建新模块时,IDE 会创建 |
8.资源混淆
微信的资源混淆参考 :