因为项目源码安全需要,最近研究了下proguard混淆源码,在这里做一些分享。以下分享基于Android Studio。
如何启用Proguard
通常项目新建完成后,build.gradle文件中会有如下一段配置:
buildTypes {
debug {
minifyEnabledtrue
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
signingConfig signingConfigs.config
}
release {
minifyEnabledtrue
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
signingConfig signingConfigs.config
}
}
如上截图,将minifyEnabled设置为true,开启混淆代码,可以同时配置多个混淆文件。
配置中默认加入了sdk的混淆文件,proguard-android.txt
Proguard配置
百度了一些语法,方便以后查阅。
保留选项(配置不进行处理的内容)
-keep {Modifier} {class_specification} 保护指定的类文件和类的成员
-keepclassmembers {modifier} {class_specification} 保护指定类的成员,如果此类受到保护他们会保护的更好
-keepclasseswithmembers {class_specification} 保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。
-keepnames {class_specification} 保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)
-keepclassmembernames {class_specification} 保护指定的类的成员的名称(如果他们不会压缩步骤中删除)
-keepclasseswithmembernames {class_specification} 保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)
-printseeds {filename} 列出类和类的成员-keep选项的清单,标准输出到给定的文件
压缩
-dontshrink 不压缩输入的类文件
-printusage {filename}
-whyareyoukeeping {class_specification}
优化
-dontoptimize 不优化输入的类文件
-assumenosideeffects {class_specification} 优化时假设指定的方法,没有任何副作用
-allowaccessmodification 优化时允许访问并修改有修饰符的类和类的成员
混淆
-dontobfuscate 不混淆输入的类文件
-obfuscationdictionary {filename} 使用给定文件中的关键字作为要混淆方法的名称
-overloadaggressively 混淆时应用侵入式重载
-useuniqueclassmembernames 确定统一的混淆类的成员名称来增加混淆
-flattenpackagehierarchy {package_name} 重新包装所有重命名的包并放在给定的单一包中
-repackageclass {package_name} 重新包装所有重命名的类文件中放在给定的单一包中
-dontusemixedcaseclassnames 混淆时不会产生形形色色的类名
-keepattributes {attribute_name,…} 保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-renamesourcefileattribute {string} 设置源文件中给定的字符串常量
后面的文件名,类名,或者包名等可以使用占位符代替
?表示一个字符
可以匹配多个字符,但是如果是一个类,不会匹配其前面的包名
** 可以匹配多个字符,会匹配前面的包名。
在android中在android Manifest文件中的activity,service,provider, receviter,等都不能进行混淆。一些在xml中配置的view也不能进行混淆,android提供的默认配置中都有。(未知原因)
Proguard输出文件
混淆之后,会给我们输出一些文件,在build/outputs/mapping/debug目录下。
分别有以下文件:
dump.txt 描述apk文件中所有类文件间的内部结构。
mapping.txt 列出了原始的类,方法,和字段名与混淆后代码之间的映射。
seeds.txt 列出了未被混淆的类和成员
usage.txt 列出了从apk中删除的代码
Proguard案例文件
# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-dontoptimize
-dontpreverify
-keepattributesSignature
-keepattributes*Annotation*
-keepclass sun.misc.Unsafe { *; }
-keepclass com.eastelsoft.zk.bean.** { *; }
-keepclass * implements org.coreframe.ui.I_KJActivity { *; }
-dontwarncom.igexin.**
-keepclass com.igexin.**{*;}
-keepclass com.baidu.**{*;}
-keepclass vi.com.gdi.bgl.**{*;}
-keepclassmembersclass * {
public (org.json.JSONObject);
}
-keepclass com.umeng.**
-keeppublic class com.idea.fifaalarmclock.app.R$*{
public static final int *;
}
-keeppublic class com.umeng.fb.ui.ThreadView {
}
-dontwarncom.umeng.**
-dontwarnorg.apache.commons.**
-keeppublic class * extends com.umeng.**
-keepclass com.umeng.** {*; }
-keepclasseswithmembernamesclass * {
native ;
}
-keepclassmemberspublic class * extends android.view.View {
void set*(***);
*** get*();
}
-keepclassmembersclass * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembersenum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclass * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepclassmembersclass **.R$* {
public static ;
}
-dontwarnandroid.support.**
配置过程中遇到的坑
1.项目中使用了许多第三方库,如百度地图,友盟,Gson等包,需要根据官方上的说明进行分别配置,
e.g. 百度地图
-keepclass com.baidu.**{*;}
-keepclass vi.com.gdi.bgl.**{*;}
2. 第一次配置完后,软件跑起来各种问题,后面发现全是gson解析失败,所以对model进行了keep操作,也没找到更好的方法。
-keepclass com.eastelsoft.zk.bean.** { *; }
3.项目中如果用了反射,需要额外配置一些.
-keepattributesSignature
-keepattributes*Annotation*
-keepclass * implements org.coreframe.ui.I_KJActivity { *; }
这里对接口进行了keep操作。
当你用了proguard配置后如果出现问题,要一步一步去分析,如果发现按钮不能点击的问题, 就尝试看看activity中的代码是否出现问题,先keep一些类,逐步调试,最后解决问题。