Android代码混淆使用

Apk文件被反编译出来能被获取到里面的代码。对于这种情况,我们可以对项目代码进行混淆,随机生成难理解的类名,方法名,让代码难以阅读,加大功能被盗取的难度。混淆可以起到压缩Apk,混淆文件,预检,优化的作用。

1. 使用方式,在gradle文件中设置minifyEnabled为true即可开启混淆

    buildTypes {
        release {
            minifyEnabled ture  //是否开启代码混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

混淆内容在proguard-android.txt或者proguard-rules.pro文件中写。

2. 混淆设置参数

-optimizationpasses 4 代码混淆的压缩比例,值介于0-7

-dontusemixedcaseclassnames 混淆后类型都为小写

-dontskipnonpubliclibraryclasses 不去忽略非公共的库类

-dontoptimize 不优化输入的类文件

-dontpreverify 不做预校验的操作

-ignorewarnings 忽略警告

-verbose 混淆时是否记录日志

-keepattributes Annotation 保护注解

-printmapping proguardMapping.txt 生成原类名和混淆后的类名的映射文件mapping文件

-optimizations !code/simplification/cast,!field/,!class/merging/ 指定混淆是采用的算法

3. 保持不被混淆的设置

保持某个包下所有类不混淆
-keep class 你的实体类所在的包.** { *; }
四大组件、View体系等不混淆
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Fragment
-keep public class * extends android.support.multidex.MultiDexApplication
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep class android.support.** {*;}
-keep public class * extends android.support.v4.**

-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

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

-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}
保持 native 方法不被混淆
-keepclasseswithmembernames class * {  
    native <methods>;
}
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();
}
保持枚举enum类不被混淆
-keepclassmembers enum * {  
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {   
    public static final android.os.Parcelable$Creator *;
}
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);
}
support design
-dontwarn android.support.design.**
-keep class android.support.design.** { *; }
-keep interface android.support.design.** { *; }
-keep public class android.support.design.R$* { *; }
然后就是项目中使用到的第三方包不混淆,下面有示例。

4. 完整混淆示例:

#---------------------------------基本指令区-----------------------

-optimizationpasses 5  #指定代码的压缩级别
-dontpreverify  #预校验
-verbose  #指定日志级别
-dontskipnonpubliclibraryclassmembers
-dontusemixedcaseclassnames  #包名不混合大小写
-ignorewarnings  #忽略警告
-printmapping proguardMapping.txt  #生成原类名和混淆后的类名的映射文件
-optimizations !code/simplification/cast,!field/*,!class/merging/*  #混淆时所采用的算法
-keepattributes *Annotation*,InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable


#---------------------------------默认保留区------------------------

#四大组件、View体系等
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Fragment
-keep public class * extends android.support.multidex.MultiDexApplication
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep class android.support.** {*;}

-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

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

-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

#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();
}

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

-keepclassmembers class * {
    void *(*Event);
}

#enum
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keepclasseswithmembernames class * {
    native <methods>;
}

-keepclassmembers class * {
   public <init> (org.json.JSONObject);
}

-keepclasseswithmembernames class * {
    native <methods>;
}

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

#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);
}

# support design
-dontwarn android.support.design.**
-keep class android.support.design.** { *; }
-keep interface android.support.design.** { *; }
-keep public class android.support.design.R$* { *; }


#---------------------------------第三方包示例-------------------------

#okhttp3.x
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**
-dontwarn com.squareup.okhttp.**
-keep class com.squareup.okhttp.{*;}
-dontwarn javax.annotation.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
-dontwarn org.codehaus.mojo.animal_sniffer.*
-dontwarn okhttp3.internal.platform.ConscryptPlatform

#retrofit
-dontwarn retrofit.**
-keep class retrofit.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-dontwarn okio.**

#Rxjava RxAndroid
-dontwarn rx.*
-dontwarn sun.misc.**

#Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

#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.** { *; }

#Lambda表达式
-keep class java.lang.invoke.** {*;}
-dontwarn java.lang.invoke.**

#高徳地图
#3D 地图
-keepclass com.amap.api.mapcore.**{*;}
-keepclass com.amap.api.maps.**{*;}
-keepclass com.autonavi.amap.mapcore.*{*;}
#定位
-keepclass com.amap.api.location.**{*;}
-keepclass com.loc.**{*;}
-keepclass com.amap.api.fence.**{*;}
-keepclass com.autonavi.aps.amapapi.model.**{*;}
# 搜索
-keepclass com.amap.api.services.**{*;}
# 2D地图
-keepclass com.amap.api.maps2d.**{*;}
-keepclass com.amap.api.mapcore2d.**{*;}
# 导航
-keepclass com.amap.api.navi.**{*;}
-keepclass com.autonavi.**{*;}


#ButterKnife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
    @butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
    @butterknife.* <methods>;
}

#eventbus 3.0
-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}

#ARouter组件化
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}

自己试着用一个简单的项目加入混淆,打个包试试效果吧。

混淆sdk和避免混淆部分类实战:

1.在proguard-rules.pro文件下配置混淆参数和-keep的类或者包:

# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
#指定代码的压缩级别
-optimizationpasses 5
-allowaccessmodification
# 优化 不优化输入的类文件
-dontoptimize
# 预校验
-dontpreverify
# 包名不混合大小写
-dontusemixedcaseclassnames
# 混淆时是否记录日志
-verbose
# 保护注解
-keepattributes *Annotation*
# 忽略警告
-ignorewarnings

-printconfiguration build/intermediates/proguard-files/full-r8-config.txt

# 保持哪些类不被混淆
#保持sdk中需要暴露功能的包下所有类不被混淆
-keep class com.libo.networkmonitor.api.**{*;}
-keep class com.libo.networkmonitor.impl.NetWorkListener

2.设置release模式下开启混淆:

    buildTypes {
        release {
            minifyEnabled true
            proguardFiles 'proguard-rules.pro'
        }
        debug {
            minifyEnabled false
            proguardFiles 'proguard-rules.pro'
        }
    }

3.打出sdk的aar包,并进行引用查看混淆情况:


可以看到,打出来的aar包,keep的类可以看到原写法,因为上面NetworkMonitor的类避免了混淆可以看得到,其余被混淆的类变成了看不出来的字母。

Mapping文件使用

列出了原始的类,方法和字段名与混淆后代码间的映射。这个文件很重要,当你从release版本中收到一个bug报告时,混淆后的文件看不出问题,可以用它来翻译被混淆的代码。
mapping目录在 \app\build\outputs\mapping\release
示例:


或者将mapping文件上传到监测平台,报出问题就能直接阅读了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容