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或者崩溃,谨慎开启。

具体的优化选项在: 

  https://jakewharton.com/blog

7.R8配置文件

R8根据ProGuard配置文件决定优化策略,一个项目中可能有多个模块,每个模块都可以自定义对应的R8配置文件。它们是累加的。一个模块中的配置可能影响到其它模块。

 来源 位置
Android Studio <module-dir>/proguard-rules.pro
Android Gradle 插件

proguard-android-optimize.txt    由 Android Gradle 插件在编译时生成。

库依赖项

AAR 库:

  • <library-dir>/proguard.txt

JAR 库:

  • <library-dir>/META-INF/proguard/
Android 资源打包工具 2 (AAPT2)

使用 minifyEnabled true 构建项目后:

  <module-dir>/build/intermediates/proguard-rules/debug/aapt_rules.txt

自定义配置文件

默认情况下,当您使用 Android Studio 创建新模块时,IDE 会创建 

  <module-dir>/proguard-rules.pro,以便您添加自己的规则。

 

8.资源混淆

  微信的资源混淆参考 : 

  https://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=208135658&idx=1&sn=ac9bd6b4927e9e82f9fa14e396183a8f#rd

 

posted @ 2019-11-28 09:59  f9q  阅读(1377)  评论(0编辑  收藏  举报