Android 混淆

Android 混淆:

  • 混淆的意义
  • 如何开启混淆
  • 混淆的规则
  • 常用的混淆模板
  • 拆分混淆文件

一. 混淆的意义

代码混淆(Obfuscated code)亦称花指令,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式的行为,可以加大反编译的成本。

二. 如何开启混淆

A. eclipse中开启混淆
1. 首先将project.properties中打开(去掉注释符“#”)
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

其中,${sdk.dir}/tools/proguard/proguard-android.txt为Android SDK中提供的基本混淆规则。

2. 修改proguard-project.txt

proguard-project.txt是基于项目的混淆规则,需要我们根据项目的具体情况进行添加。
混淆规则可以查看后面的详细说明,此处提供一个简单的示例

3. 注意事项

Project所在的目录不可用有空格或者一些特殊字符(如“(”)等出现,否则混淆会出错。

4. 导出APK文件
B. Android Studio中开启混淆
1. 编辑项目app目录下的build.gradle文件。
buildTypes {
    debug {
        minifyEnabled false     // 混淆
        zipAlignEnabled true    // Zipalign优化
        shrinkResources true    // 移除无用的resource文件
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  // 加载默认混淆配置文件
        signingConfig signingConfigs.debug // 签名
    }
    release {
        minifyEnabled true      // 混淆
        zipAlignEnabled true    // Zipalign优化
        shrinkResources true    // 移除无用的resource文件
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  // 加载默认混淆配置文件
        signingConfig signingConfigs.relealse  // 签名
    }
}
2. 修改编辑proguard-rules.pro文件

三. 混淆的规则

混淆会用无意义的短变量去重命名类、变量、方法,但是对于外部的一些引用是通过名字找到对应的方法和类。混淆过后通过原来的名字去找混淆后的名字,是找不到对应方法和类,就会出异常报错。所以有些情况是不能进行混淆的。

  • 自定义控件不进行混淆
  • 枚举类不被混淆
  • 反射类不进行混淆
  • 实体类不被混淆
  • JS调用的Java方法
  • 四大组件不进行混淆
  • JNI中调用类不进行混淆
  • Layout布局使用的View构造函数、android:onClick等
  • Parcelable 的子类和 Creator 静态成员变量不混淆
  • 第三方开源库或者引用其他第三方的SDK包不进行混淆
混淆的常见配置
  • Proguard关键字
序号 Proguard关键字 描述
1 dontwarn dontwarn是一个和keep可以说是形影不离,尤其是处理引入的library时
2 keep 保留类和类中的成员,防止被混淆或移除
3 keepnames 保留类和类中的成员,防止被混淆,成员没有被引用会被移除
4 keepclassmembers 只保留类中的成员,防止被混淆或移除
5 keepclassmembernames 只保留类中的成员,防止被混淆,成员没有引用会被移除
6 keepclasseswithmembers 保留类和类中的成员,防止被混淆或移除,保留指明的成员
7 keepclasseswithmembernames 保留类和类中的成员,防止被混淆,保留指明的成员,成员没有引用会被移除

如:

1.保留某个包下面的类以及子包
-keep public class com.example.demo.**
2. 保留所有类中使用otto的public方法
# Otto
-keepclassmembers class ** {
    @com.squareup.otto.Subscribe public *;
    @com.squareup.otto.Produce public *;
}
3. 保留Contants类的BOOK_NAME属性
-keepclassmembers class com.example.demo.Constants {
     public static java.lang.String BOOK_NAME;
}
4. dontwarn

引入的library可能存在一些无法找到的引用和其他问题,在build时可能会发出警告,如果我们不进行处理,通常会导致build中止.因此为了保证build继续,我们需要使用dontwarn处理这些我们无法解决的library的警告.

#比如关闭Twitter sdk的警告,我们可以这样做
-dontwarn com.twitter.sdk.**
  • Proguard通配符
序号 Proguard关键字 描述
1 匹配类中的所有字段
2 匹配类中所有的方法
3 匹配类中所有的构造函数
4 * 匹配任意长度字符,不包含包名分隔符(.)
5 ** 匹配任意长度字符,包含包名分隔符(.)
6 *** 匹配任意参数类型

四. 混淆模板

A. 基本模板
1. 系统默认混淆文件
# 设置混淆的压缩比率 0 ~ 7
-optimizationpasses 5  
# 混淆时不使用大小写混合,混淆后的类名为小写
-dontusemixedcaseclassnames  
# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
# 指定不去忽略非公共库的成员
-dontskipnonpubliclibraryclassmembers 
# 混淆时不做预校验
-dontpreverify           
# 混淆时不记录日志
-verbose             
# 忽略警告
-ignorewarning          
# 代码优化
-dontshrink  
# 不优化输入的类文件                
-dontoptimize 
# 保留注解不混淆             
-keepattributes *Annotation*,InnerClasses
# 避免混淆泛型
-keepattributes Signature  
# 保留代码行号,方便异常信息的追踪
-keepattributes SourceFile,LineNumberTable  
# 混淆采用的算法
-optimizations !code/simplification/cast,!field/*,!class/merging/*  

# dump.txt文件列出apk包内所有class的内部结构
-dump class_files.txt        
# seeds.txt文件列出未混淆的类和成员
-printseeds seeds.txt
# usage.txt文件列出从apk中删除的代码
-printusage unused.txt
# mapping.txt文件列出混淆前后的映射
-printmapping mapping.txt
2.不需混淆的Android类
-keep public class * extends android.app.Fragment
-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.content.BroadcastReceiver
-keep public class * extends android.preference.Preference
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.annotation.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
-keep class android.support.** {*;}
3. support-v4包
-dontwarn android.support.v4.**
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v4.** { *; }
4. support-v7包
-dontwarn android.support.v7.**
-keep class android.support.v7.internal.** { *; }
-keep interface android.support.v7.internal.** { *; }
-keep class android.support.v7.** { *; }
5. support design
-dontwarn android.support.design.**
-keep class android.support.design.** { *; }
-keep interface android.support.design.** { *; }
-keep public class android.support.design.R$* { *; }
6. 避免混淆自定义控件类的 get/set 方法和构造函数
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public (android.content.Context);
    public (android.content.Context, android.util.AttributeSet);
    public (android.content.Context, android.util.AttributeSet, int);
}
7. 关闭 Log日志
-assumenosideeffects class android.util.Log {
    public static *** d(...);
    public static *** v(...);
    public static *** i(...);
    public static *** e(...);
    public static *** w(...);
}

-dontoptimize不要配置,不然将会关闭优化,导致日志语句不会被优化掉。

8. 避免资源混淆
-keep class **.R$* {*;}
9. 避免layout中onclick方法(android:οnclick=“onClick”)混淆
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
10. 避免回调函数 onXXEvent 混淆
-keepclassmembers class * {
    void *(*Event);
}
11. 避免混淆枚举类
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
12. Natvie 方法不混淆
-keepclasseswithmembernames class * {
    native ;
}
13. 避免Parcelable混淆
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
14. 避免Serializable接口的子类中指定的某些成员变量和方法混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient ;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
15. WebView混淆配置
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
    public *;
}
-keepclassmembers class * extends android.webkit.webViewClient {
    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
    public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.webViewClient {
    public void *(android.webkit.webView, jav.lang.String);
}
B. 常用混淆模板
1. ButterKnife混淆配置
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
    @butterknife.* ;
}
-keepclasseswithmembernames class * {
    @butterknife.* ;
}
2. OkHttp3混淆配置
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**
3. Retrofit2混淆配置
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
4. RxJava、RxAndroid混淆配置
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
   long producerIndex;
   long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
5. Glide混淆配置
  • Glide 3
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}
  • Glide 4
-keep public class * implements com.bumptech.glide.module.AppGlideModule
-keep public class * implements com.bumptech.glide.module.LibraryGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}
6. Picasso混淆配置
-keep class com.parse.*{ *; }
-dontwarn com.parse.**
-dontwarn com.squareup.picasso.**
-keepclasseswithmembernames class * {
    native ;
}
7. Fresco混淆配置
# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
-keep,allowobfuscation @interface com.facebook.soloader.DoNotOptimize

# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
    @com.facebook.common.internal.DoNotStrip *;
}

# Do not strip any method/class that is annotated with @DoNotOptimize
-keep @com.facebook.soloader.DoNotOptimize class *
-keepclassmembers class * {
    @com.facebook.soloader.DoNotOptimize *;
}

# Keep native methods
-keepclassmembers class * {
    native ;
}

-dontwarn okio.**
-dontwarn com.squareup.okhttp.**
-dontwarn okhttp3.**
-dontwarn javax.annotation.**
-dontwarn com.android.volley.toolbox.**
-dontwarn com.facebook.infer.**
8. Fastjson混淆配置
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.**{*; }
9. Gson混淆配置
-keep class com.google.gson.** {*;}
-keep class com.google.**{*;}
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
10. GreenDao混淆配置
  • GreenDAO 2
-keep class de.greenrobot.dao.** {*;}
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
    public static Java.lang.String TABLENAME;
}
-keep class **$Properties
  • GreenDAO 3
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
 
# If you do not use SQLCipher:
-dontwarn org.greenrobot.greendao.database.**
# If you do not use Rx:
-dontwarn rx.**
11. 百度定位混淆配置
-keep class vi.com.gdi.** { *; }
-keep public class com.baidu.** {*;}
-keep public class com.mobclick.** {*;}
-dontwarn com.baidu.mapapi.utils.*
-dontwarn com.baidu.platform.comapi.b.*
-dontwarn com.baidu.platform.comapi.map.*
12. 百度地图混淆配置
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-dontwarn com.baidu.**
13. 高徳地图混淆配置
-dontwarn com.amap.api.**
-dontwarn com.a.a.**
-dontwarn com.autonavi.**
-keep class com.amap.api.**  {*;}
-keep class com.autonavi.**  {*;}
-keep class com.a.a.**  {*;}
14. Bugly混淆配置
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
15. EventBus混淆配置
  • EventBus 2
-keepclassmembers class ** {
    public void onEvent*(***);
}

# Only required if you use AsyncExecutor
-keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent {
    (java.lang.Throwable);
}
  • EventBus 3
-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe ;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    (java.lang.Throwable);
}
16. 个推
#-dontwarn com.igexin.**
-keep class com.igexin.**{*;}

五. 拆分混淆文件

当项目功能迭代越来越多、代码量越来越多,引用的第二方库、第三方库都越来越多,导致proguard-rules.pro 越来越臃肿,而且随着开发人员增多导致proguard-rules.pro 文件里面的配置越来越混乱。
因此可以将proguard-rules.pro混淆文件进行拆分整理,大概拆分为以下3个文件:系统默认混淆文件、第三方混淆文件、module单独混淆文件 。
最后将这些混淆文件一起放入项目的app下。

buildTypes {
    debug {
        minifyEnabled false     // 混淆
        zipAlignEnabled true    // Zipalign优化
        shrinkResources true    // 移除无用的resource文件
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-system-mormal.pro', 'proguard-module.pro', 'proguard-third-party.pro'  // 加载默认混淆配置文件
        signingConfig signingConfigs.debug // 签名
    }
    release {
        minifyEnabled true      // 混淆
        zipAlignEnabled true    // Zipalign优化
        shrinkResources true    // 移除无用的resource文件
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-system-mormal.pro', 'proguard-module.pro', 'proguard-third-party.pro'  // 加载默认混淆配置文件
        signingConfig signingConfigs.relealse  // 签名
    }
}

你可能感兴趣的:(Android)