Android 中使用 Proguard 混淆 Java 代码
容易被反编译是 Java 、C# 这类解释型、托管型语言的通病,为了保障代码安全,通常采取的措施主要有两种:
核心逻辑采用难于被反编译的 native 语言(C / C++)编写,而 C# 通过 DllImport 等方式、Java 通过 JNI 都可调用 native 代码。
对代码进行混淆,C# 有 VS 自带的工具 Dotfuscator ,第三方工具有 DNGuard HVM 、IL Protected 等;Java 这方面工具也比较多,如 Jmangle 、JODE 等。
Proguard 是 SourceForge 上的一个开源项目,可用来混淆、压缩和优化 Java 字节码文件,Android 官方提供了对它的支持。
使用 Proguard 的方式很简单,只需要编写一个文本文件,然后在 project.properties
文件中的 proguard.config
字段声明其路径就 OK 了,详见 Android 官方文档。
处理后的 Java 字节码文件体积可以达到混淆和瘦身的效果,但是有些代码是不能混淆的,否则在打包时会报错:
系统组件及其子类,如
Activity
、Service
、BroadcastReceiver
、ContentProvider
;官方
Support
包下面的组件及其子类,如Fragment
、FragmentActivity
;native
方法,因为 JNI 要求方法名必须和 native 代码中保留完全一致;注解、枚举成员和
protected
成员;和数据解析相关的 JSON 、
Parcelable
、Serializable
子类,还有自定义的实体类,否则会出现解析错误;WebView
中定义的与 JS 交互的类,否则无法与 JS 进行数据交互;View
子类的构造方法;所有
R.java
中的成员,否则程序运行会找不到资源文件;
示例代码如下:
-verbose
#忽略警告:
-ignorewarnings
#不预校验:
-dontpreverify
#不使用混合的类名:
-dontusemixedcaseclassnames
#不要跳过非公共类库:
-dontskipnonpubliclibraryclasses
#优化:
-optimizationpasses 5
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保留注解:
-keepattributes *Annotation*
#避免使用泛型的位置混淆后出现类型转换错误:
-keepattributes Signature
#保留本地方法:
-keepclasseswithmembers class * {
native <methods>;
}
#保留枚举类型成员的方法:
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#保留protected方法:
-keep public class * {
public protected *;
}
#保留系统组件及其子类:
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.backup.BackupAgentHelper
-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 com.android.vending.licensing.ILicensingService
-keepclassmembers class * extends android.content.Context {
public void *(android.view.View);
public void *(android.view.MenuItem);
}
#去除support-v4包的警告,保留相关API:
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.support.v4.app.FragmentActivity
-keep public class android.support.v4.accessibilityservice.** { *; }
-keep public class android.support.v4.app.** { *; }
-keep public class android.support.v4.os.** { *; }
-keep public class android.support.v4.view.** { *; }
-keep public class android.support.v4.widget.** { *; }
#保留View子类读取XML的构造方法:
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#保留JSON、Parcelable、Serailizable相关API:
-keepclassmembers class * {
public <init>(org.json.JSONObject);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-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();
}
# 保留WebView中定义的与JS交互的类:
-keepattributes JavascriptInterface
-keep public class com.mypackage.MyClass$MyJavaScriptInterface
-keep public class * implements com.mypackage.MyClass$MyJavaScriptInterface
-keepclassmembers class com.mypackage.MyClass$MyJavaScriptInterface {
<methods>;
}
#去除调试日志,将所有Log.d()改为Log.i():
-assumenosideeffects class android.util.Log{
public static *** d(...);
public static *** i(...);
}
#保留资源文件
-keepclassmembers class **.R$* {
public static <fields>;
}
#保留实体类:
-keep class com.rincliu.library.entity.**{ *; }
#导入第三方库:
-libraryjars libs/android-support-v4.jar
如果使用了其他第三方类库,也会有相关成员不能混淆,具体可查看对应的官方文档说明,以下为示例:
#保留Google GSON相关API:
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.** { *;}
#保留微信相关API:
-keep class com.tencent.mm.sdk.openapi.WXMediaMessage {*;}
-keep class com.tencent.mm.sdk.openapi.** implements com.tencent.mm.sdk.openapi.WXMediaMessage$IMediaObject {*;}
#保留友盟相关API:
-keep public class com.umeng.fb.ui.ThreadView {
}