今天自己做测试的时候发现,debug包可以正常运行,但是release包就各种问题,找不到类或者方法不存在等,甚至直接crash,后来发现原来是代码混淆导致的。Android工程在打release包的时候,一般都会把代码混淆开关打开,也就是builde.gradle里面的minifyEnabled值置为true。代码混淆可以有效防止apk被反编译。
代码混淆有一定的语法规范。这里是截的别人的总结的图:
还有一张我自己写了注释的我的demo里面的混淆文件,这份文件具有通用性,如果需要自己增加一些自己的类或者第三类库的混淆,都可以按照格式来增加。
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">#指定代码的压缩级别
-optimizationpasses 5
#包名不混合大小写
-dontusemixedcaseclassnames
#混淆第三方jar包的类名
-dontskipnonpubliclibraryclasses
#混淆第三方jar包的类的属性、方法和变量名
-dontskipnonpubliclibraryclassmembers
#忽略警告
-ignorewarnings
#混淆时预校验
-dontpreverify
#混淆时记录日志
-verbose
#使用映射增加混淆
-applymapping proguard_mapping.txt
#不优化输入类文件
-dontoptimize
#混淆时采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#-optimizations method/inlining/*
#优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification
#保留注解
-keepattributes *Annotation*
#保留泛型
-keepattributes Signature
#保留抛出异常的时候正确的行号
-keepattributes SourceFile,LineNumberTable
#一些继承android组件的类需要保留
-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.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
#序列化的类需要保留
-keep class * implements java.io.Serializable
#序列化的类的属性和方法需要保留
-keepclassmembers class * implements java.io.Serializable {
static long serialVersionUID;
static java.io.ObjectStreamField[] serialPersistentFields;
void writeObject(java.io.ObjectOutputStream);
void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#本地方法都需要保留
-keepclasseswithmembernames class * {
native <methods>;
}
#自定义view的构造函数需要保留
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
#自定义view的构造函数需要保留
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#资源文件需要保留
-keepclassmembers class **.R$* {
public static <fields>;
}
-keep class sun.misc.Unsafe {*;}
#activity里面的match这个case的方法需要保留
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
#枚举类里面的这两个方法需要保留
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#android序列化的类需要保留
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepclassmembers class ** {
public void on*Event(...);
}
-dontwarn org.eclipse.jdt.annotation.**
-dontnote ct.**
#====== 以下为app中定义的类或者第三方库中用到的类 (ashercai 2014-8-8) ============================
# 规则:
# 1) 第三方库,如果已经混淆过,建议全部保留
# 2) 第三方库,如果包含动态库,建议全部保留
# 3) App的类,如果用到动态库,建议保留包 (如果明确动态库中没有创建Java对象或访问Java类成员,可混淆)
# 4) App的类,如果用到了反射,需检查代码,将涉及的类和成员保留
# 5) App的类,定义为@JavascriptInterface的成员,需要保留
#=============================================================================================
#需要保留的类和方法等类似写法
-keep class com.sun.innocentsun.utils.** {*;}
-keepclassmembers class com.sun.innocentsun.activity.MainActivity { public <methods>; }</span></span></span>
使用混淆容易找不到类或者方法的异常,这时就需要自己把这些地方手动添加到混淆文件里面,尤其是列出来的一些通用不能混淆的地方,需要明确保留才行,比如:activity里面的button的监听,混淆的话就会发现找不到,所以要保留,如下:
<span style="font-size:18px;">#activity里面的match这个case的方法需要保留
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}</span>