【Android】ProGuard的使用

2016-11-17  本文已影响0人  Wavky

Merit

Demerit

Discussion on Smart App Updates:

Why are the updates still in MBs?! Understandable for major updates, but I'm hoping when an app has only bug fixes, it would be a very, very small update.

It's because of the way code gets compiled. When devs compile their Java code into an APK, they also use a tool called "Proguard," which is used to optimize and obfuscate their code. It's what makes it harder for other people to just decompile apps and steal work, and also slims down APKs and makes them run slightly faster. Unfortunately, Proguard obfuscates code differently depending on what changes you've made. While a developer might only change a line, the obfuscated and optimized version might actually have changed quite a bit.

see:

ProGuard配置

常规启用

导入 ProGuard 规则文件:

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

minifyEnabled true 表示使用 ProGuard 进行混淆

shrinkResources true 表示精简未使用的资源文件(不包括 values),基于代码精简化后的结果进行引用判断(包括动态计算获取资源ID等隐式资源调用)

getDefaultProguardFile 表示在以下 SDK 位置读取指定的默认配置:

Android SDK -> Android SDK Location /tools/proguard/

该配置包含绝大部分默认必备选项,并自动移除未使用代码,但涉及以下情况的代码,需要通过 -keep 配置或 @Keep 注解,手动声明进行保留:

ProGuard 会自动重命名类、方法、字段等,通过反射等方式,在运行时动态引用类型、字段、资源时需要特别注意,根据需要手动声明保留:

proguard-android.txt 内置实现以下部分的处理:

每次编译时,ProGuard 会输出以下文件:

※ 以上文件存储到该目录:
<module-name>/build/outputs/mapping/release/

注意

在使用 Instant Run 时,ProGuard 会被自动临时禁用。(Android Studio 2.0 & minSdkVersion >= 21)

productFlavors 与 buildTypes 中指定的 proguardFiles、proguardFile 会同时叠加生效,并且 buildTypes > productFlavors

build.gradle 配置了 consumerProguardFiles 项的第三方库,其引用的规则文件会自动引入到当前项目。

如果一个包中有需要不混淆的内容,则整个包名都不会被混淆。

proguard-android.txt 使用了 dontoptimize,优化不启用,-assumenosideeffects 不会生效。可使用 proguard-android-optimize.txt 替代。

移除重复资源

Gradle 方面会强制自动合并重复的资源项(同名+同类型+同限定属性),不受 ProGuard 的配置影响。

重复资源项按序扫描以下目录,并选择保留最后扫描到的重复项:

  1. 项目库依赖目录
  2. 当前资源主目录,通常指向为:src/main/res/
  3. Build flavor 配置目录
  4. Build type 配置目录

合并重复资源时,Gradle 会生成 resources.txt 文件,列出资源的依赖关系,及被移除的资源列表。
该文件在:<module-name>/build/outputs/mapping/release/ 目录中

常用规则

-keepattributes Signature 保留泛型类型信息
-keepattributes SourceFile,LineNumberTable 保留文件名、行号,用于崩溃反馈
-keep class com.xxx.** { *; } 保留第三方类库源码

移除Log代码 需要启用Optimization(不使用 -dontoptimize)
-assumenosideeffects class android.util.Log {
     public static *** d(...);
}
参考:

ProGuard 过程

Shrink -> Optimize -> Obfuscate -> Preverify

保留规则

以下规则不对类成员执行 Shrink 自动移除

以下规则在 Shrink 过程执行完毕后生效

可选的附件条件

-printseeds [filename]:打印被上述 keep 规则匹配保留的类及类成员,或输出到指定文件

※1 仅指定类,不指定成员时,仅对类名本身生效
※2 指定的类成员,仅对其名称生效,不影响其相关逻辑代码的后续优化、适配过程

类、成员指定条件

# 指定类型(必选)
[@annotationtype] [[!]public|final|abstract|@ ...] [!]interface|class|enum classname
    [extends|implements [@annotationtype] classname]

# 指定成员(可选)
[{
    [@annotationtype] [[!]public|private|protected|static|volatile|transient ...] <fields> | (fieldtype fieldname);

    [@annotationtype] [[!]public|private|protected|static|synchronized|native|abstract|strictfp ...] <methods> | <init>(argumenttype,...) | classname(argumenttype,...) | (returntype methodname(argumenttype,...));
    
    [@annotationtype] [[!]public|private|protected|static ... ] *;
    
    ...
}]
通用指定
指定类型(必选)
类型名通配符

※ 单以 * 标记类型名,表示匹配所有类型名,不考虑包地址

指定成员(可选)
成员名通配符
成员类型描述语句中的类型通配符

※1 基本类型可用 %*** 匹配
※2 数组类型仅可使用 *** 匹配

参考:ProGuard Usage

DexGuard

ProGuard 的进阶版替换方案,除基本代码混淆优化外,更提供了算式混淆、控制流混淆、本地代码混淆、反射回调、类型加密、本地库加密、字符串加密、资源混淆加密、证书检查、debug和模拟器检测等高阶保护过程,可有效阻止apktool完整反编译过程,收费,至少350欧。

参考:DexGuard Features

上一篇 下一篇

猜你喜欢

热点阅读