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文件上传到监测平台,报出问题就能直接阅读了。