掌握 Android Proguard 配置使用之一 总览

1. Android Proguard 作用

ProGuard 会检测和移除封装应用中未使用的类、字段、方法和属性,包括自带代码库中的未使用项(这使其成为以变通方式解决 64k 引用限制的有用工具)。

ProGuard 还可优化字节码,移除未使用的代码指令,以及用短名称混淆其余的类、字段和方法。混淆过的代码可令您的 APK 难以被逆向工程,这在应用使用许可验证等安全敏感性功能时特别有用。


官网地址:https://www.guardsquare.com/en/mobile-application-protection


基本定义:

ProGuard is a Java class file shrinker, optimizer, obfuscator, and preverifier. The shrinking step detects and removes unused classes, fields, methods, and attributes. The optimization step analyzes and optimizes the bytecode of the methods. The obfuscation step renames the remaining classes, fields, and methods using short meaningless names. These first steps make the code base smaller, more efficient, and harder to reverse-engineer. The final preverification step adds preverification information to the classes, which is required for Java Micro Edition or which improves the start-up time for Java 6.


主要就是shrinker(压缩), optimizer(优化),obfuscator(混淆),preverifier(预校验)。

  • shrink: 检测并移除没有用到的类,变量,方法和属性;
  • optimize: 优化代码, 没有用到的参数会被删除,一些方法可能会变成内联代码。
  • obfuscate: 使用短且无明确意义的类名,变量名,方法名。入口类的名字保持不变。
  • preverify: 预校验代码是否符合规范
2. 实际产物

每次构建时 ProGuard 都会输出下列文件:

dump.txt
说明 APK 中所有类文件的内部结构。
mapping.txt
提供原始与混淆过的类、方法和字段名称之间的转换。
seeds.txt
列出未进行混淆的类和成员。
usage.txt
列出从 APK 移除的代码。

文件位置:  主工程\build\outputs\mapping\release


3.  Android 官网推荐配置

位置:   \sdk\tools\proguard\

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html

-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose

# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize and preverify steps (and performs some
# of these optimizations on its own).
-dontoptimize
-dontpreverify
# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.

-keepattributes *Annotation*
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
    native <methods>;
}

# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version.  We know about them, and they are safe.
-dontwarn android.support.**

# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep

-keep @android.support.annotation.Keep class * {*;}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <methods>;
}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <fields>;
}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <init>(...);
}

4. 基本使用

build.gradle 中配置

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

其中 minifyEnabled 用来控制是否启用混淆,配置完,编辑proguard-rules.pro这个文件即可。


5.基本语法

# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/liuqiang/Development/android-sdk-macosx/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}


#-ignorewarnings                     # 忽略警告,避免打包时某些警告出现
-optimizationpasses 5               # 指定代码的压缩级别
-dontusemixedcaseclassnames         # 是否使用大小写混合 混淆时不会产生形形色色的类名
-dontskipnonpubliclibraryclasses    # 是否混淆第三方jar
-dontpreverify                      # 混淆时是否做预校验
-verbose                            # 混淆时是否记录日志
-dontoptimize                       # 不优化输入的类文件

-keepattributes *Annotation*, SourceFile, InnerClasses, LineNumberTable, Signature, EnclosingMethod
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*    #优化 混淆时采用的算法

-keep public class * extends android.app.Activity    # 未指定成员,仅仅保持类名不被混淆
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.app.View
-keep public class * extends android.app.IntentService
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.hardware.display.DisplayManager
-keep public class * extends android.os.UserManager
-keep public class com.android.vending.licensing.ILicensingService
-keep public class * extends android.app.Fragment

-keep public class * extends android.support.v4.widget
-keep public class * extends android.support.v4.**    #  *匹配任意字符不包括.  **匹配任意字符
-keep interface android.support.v4.app.** { *; }    #{ *;}    表示一个类中的所有的东西
-keep class android.support.v4.** { *; }        # 保持一个完整的包不被混淆
-keep class android.os.**{*;}

-keep class **.R$* { *; }
-keep class **.R{ *; }

#实现了android.os.Parcelable接口类的任何类,以及其内部定义的Creator内部类类型的public final静态成员变量,都不能被混淆和删除
-keep class * implements android.os.Parcelable {    # 保持Parcelable不被混淆
  public static final android.os.Parcelable$Creator *;
}

-keepclasseswithmembernames class * {     # 保持 native 方法不被混淆
    native ;
}

-keepclasseswithmembers class * {         # 保持自定义控件类不被混淆
    public (android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {         # 保持自定义控件类不被混淆
    public (android.content.Context, android.util.AttributeSet, int);
}

-keepclasseswithmembers class * {
  public (android.content.Context, android.util.AttributeSet, int, int);
}

-keepclassmembers class * extends android.app.Activity { #保持类成员
   public void *(android.view.View);
}

-keepclassmembers class * extends android.content.Context {
  public void *(android.view.View);
  public void *(android.view.MenuItem);
}

-keepclassmembers enum * {                  # 保持枚举 enum 类不被混淆
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
  static final long serialVersionUID;
  private static final java.io.ObjectStreamField[] serialPersistentFields;
  private void writeObject(java.io.ObjectOutputStream);
  private void readObject(java.io.ObjectInputStream);
  java.lang.Object writeReplace();
  java.lang.Object readResolve();
}

-libraryjars   libs/treecore.jar   #缺省proguard 会检查每一个引用是否正确,但是第三方库里面往往有些不会用到的类,没有正确引用。如果不配置的话,系统就会报错。
-dontwarn android.support.v4.**
-dontwarn android.os.**

##############################--------以上是Android基本配置----------##############################

# 实体类不混淆(自己项目实体类不被混淆,因为Gson中用到了反射)
#-keep class com.xxxx.model.** { *; }

## for sharedSDK
-keep class android.net.http.SslError
-keep class android.webkit.**{*;}
-keep class cn.sharesdk.**{*;}
-keep class com.sina.**{*;}
-keep class m.framework.**{*;}

6. 注意事项

自定义要保留的代码

对于某些情况,默认 ProGuard配置文件 (proguard-android.txt)足以满足需要,ProGuard会移除所有(并且只会移除)未使用的代码。不过,ProGuard难以对许多情况进行正确分析,可能会移除应用真正需要的代码。举例来说,它可能错误移除代码的情况包括:

当应用引用的类只来自 AndroidManifest.xml 文件时

当应用调用的方法来自 Java原生接口 (JNI)

当应用在运行时(例如使用反射或自检)操作代码时

测试应用应该能够发现因不当移除而导致的错误,但您还可通过查看 <module-name>/build/outputs/mapping/release/ 中保存的 usage.txt 输出文件来检查移除了哪些代码。

要修正错误并强制 ProGuard保留特定代码,请在 ProGuard配置文件中添加一行 -keep 代码。例如:

-keep public class MyClass

您还可以向您想保留的代码添加 @Keep 注解。在类上添加 @Keep 可原样保留整个类。在方法或字段上添加它可完整保留方法/字段(及其名称)以及类名称。请注意,只有在使用注解支持库时,才能使用此注解。

在使用 -keep 选项时,有许多事项需要考虑;如需了解有关自定义配置文件的详细信息,请阅读 ProGuard手册

附地址https://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/introduction.html


7. 关于第三方库

通常使用的第三方库,都会提供混淆示例,建议直接拷贝官方文档。
# OkHttp3
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**

# Okio
-dontwarn com.squareup.**  
-dontwarn okio.**  
-keep public class org.codehaus.* { *; }  
-keep public class java.nio.* { *; }

# 友盟统计分析
-keepclassmembers class * { public <init>(org.json.JSONObject); }
-keepclassmembers enum com.umeng.analytics.** {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}


8 . 利弊
混淆可以有效的保护代码安全,同时也可以降低代码体积,官方数据是降低10%的代码量,并具有更快的执行效率。
不过,经常会出现类找不到等问题,所以使用时,要格外注意有些类避免混淆。尤其是涉及到反射的时候,要注意少踩坑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值