在Android工程中混淆时,并不是所有的类都去混淆, 一些指定的类,我们要过滤掉不让其混淆。在AndroidStudio中
混淆时 在 build.gradle 文件里面进行配置
buildTypes { debug { // 显示Log buildConfigField "boolean", "LOG_DEBUG", "true" versionNameSuffix "-debug" //混淆 minifyEnabled false //签名 signingConfig signingConfigs.debug } release { //代码混淆开关,一定要注意现在已经使用minifyEnabled代替runProguard了 minifyEnabled true //Zipalign优化 zipAlignEnabled true // 移除无用的resource文件 shrinkResources true // proguard-rules.pro 是当前使用的混淆文件(Eclipse中的proguard.cfg) //前一部分代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明,后一个文件是自己的定义混淆文件 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' }}
//代码混淆开关,一定要注意现在已经使用minifyEnabled代替runProguard了 minifyEnabled true
并不是所有的类都去混淆, 一些指定的类,我们要过滤掉不让其混淆。
首先 通常第三方开源库 是不必混淆的 也没意义。
譬如网络请求框架 okhttp.
我们在 app/proguard-rules.pro文件中配置
# 不混淆okhttp3
-keep class okhttp3.** { *; }-keep interface okhttp3.** {*;}-dontwarn okio.**
------------------------------------------------------------------------------------------------------------------------------------------------------------------
现在我们想指定某些类不让其混淆。 有两种方法,
一种 是让不能混淆的类 继承于同一个空类 。
一种 是让不能混淆的类 实现一个空接口。
由于类是单继承,所以当不能混淆的类已经有了父类就不适用了。
所以采用第二种 实现自己定义的空接口, 那么实现此接口的类都可以,而且不受这种单继承限制,任何类可以实现,任何接口可以继承。 当然也是继承类和实现接口的区别中的一条重要特性
/** * Created by 张丹江 on 2016/10/24. * 实现此接口的类,都不会被混淆 */public interface DontObfuscateInterface {}
在proguard-rules.pro 文件里面这样配置
-keep public interface com.danjiang.fastjsondemo.DontObfuscateInterface{public *;}-keep class * implements com.danjiang.fastjsondemo.DontObfuscateInterface {<methods>;<fields>;}
那么实现此接口的类都不会混淆了。
但是 还有一种情况 在fastjson解析时,有些类正常 有些类依然不正常。
FATAL EXCEPTION: main
Process: com.danjiang.fastjsondemo, PID: 21688
com.alibaba.fastjson.JSONException: default constructor not found. class com.danjiang.fastjsondemo.DataBean$a
at com.alibaba.fastjson.util.JavaBeanInfo.build(SourceFile:213)
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.<init>(SourceFile:40)
at com.alibaba.fastjson.parser.ParserConfig.createJavaBeanDeserializer(SourceFile:582)
at com.alibaba.fastjson.parser.ParserConfig.getDeserializer(SourceFile:457)
at com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer.getFieldValueDeserilizer(SourceFile:35)
说是默认构造没有找到,但是去给加了 空构造参数依然不能通过。 网上各种查询得出,是内部类被混淆的原因。网上给出答案 ,
-keepattributesExceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
是InnerClasses 这样 就可以 然后测试 此语句无效。 其中异常给出
com.danjiang.fastjsondemo.DataBean$a 为$符号后的a 就是这个类被混淆了 然后查询内部类混淆规则
$ 代表内部类
* 代表通配符
有 这样的答案 指定报名和类名。 写死是可以的通过的
-keepnames class 包名.类名$* {
public <fields>;
public <methods>;
}
然而这样违背了我们自定义的混淆接口的初衷, 这样就要对每一个具体的类的内部类在配置文件配置。 有100个含有内部类的类我们就得配置100次,有1万个就1万次,违背了我们的初衷。
然而 发现
令一种方法,就是让每一个内部类都去实现这样的 接口, 看看以往的工程,和现在的工程中都是这样做的。 临时各种实验都不成功暂且将每个内部类都实现这样的接口。 即使复杂的JavaBean 有多个内部类也要仔细的一个个去添加。。
也是没有办法,相比上一种也是简便许多 当然 当内部类数量 特别多时 都要去实现以下。
总感觉有可以解决的办法 开始分析进行各种尝试。 只让外部类实现,内部类不去实现 像这样
# 保持哪些类的子类 不被混淆-keep public class * extends android.app.Activity
#保持 Parcelable 不被混淆 以及里面的子接口 看到这里类的内部类却无法如此 除非指明报名
-keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *;}
而我们想要的是 -keep (class * implements com.danjiang.fastjsondemo.DontObfuscateInterface)$*
或者这样
-keep class * implements com.danjiang.fastjsondemo.DontObfuscateInterface {<methods>;<fields>;}$*
或者这样
-keep class$* * implements com.danjiang.fastjsondemo.DontObfuscateInterface
或者
-keep class$* * implements com.danjiang.fastjsondemo.DontObfuscateInterface$*
理想的认为这样代表 实现此接口的类的内部类,然并卵 语法不过。各种数小时的实验 未果
-keep (class * implements com.danjiang.fastjsondemo.DontObfuscateInterface)$*
最后想到-keep class com.danjiang.fastjsondemo.*$* {<methods>;<fields>;}
我的工程包名下面的所有类的内部类都不去混淆, 那么只需让不能混淆的 外部类实现DontObfuscateInterface接口就可以了
这样可以保证了不用处处配置 也不用内部类处处实现。
当然也有个缺点就是 所有的内部类不在被混淆。
也翻阅国外的回答,目前没有发现更强大的语法 直接支持 -keep (class * implements com.danjiang.fastjsondemo.DontObfuscateInterface)$* 这样的效果 。 或者此类生成个变脸类 取其内部类。
当然最后一种是目前最省事的一种写法,也有缺点内部类不在混淆。
如有高手发现其他更好的可以留言,欢迎指正不足。 详细混淆规则没有一一列举 仅仅是对 实现某个接口的类的内部类的混淆探索
邮箱 。zhangdanjiang_java@163.com