前言
这阵子自己的心又长草了,静不下来~又挺迷茫的!在这个纷纷跳槽的季节,感觉还是应该让自己静下心来多学习学习。还是写写博客,总结总结~梳理下心里的野草。
上个月跟朋友讨论了这么一问题:“项目上线之后由于代码被混淆的缘故,导致收集到的异常信息看着很困难”,刚好最近在复习混淆方面的知识,在总结混淆的知识点的同时,顺便探讨总结下这问题。项目上线肯定避免不了的是对项目进行混淆、打包、签名和发布,可能还有APK加固等等,其实这流程并不复杂,都有一套明确的流程,所以整起来也不是很困难。而上面提到的“混淆导致上线后的异常信息查看起来挺困难”这问题,这几天也大概探讨完,打算记录在下篇文章~~那么这篇文章先开始扯淡吧!
Ⅰ.简述
混淆的概念:将Android项目进行打包之时,可以将项目里的包名、类名、变量名进行更改,使得代码不容易泄露,类似于对其apk中的文件加密.
混淆的作用:
- 1.增加Apk反编译之后代码泄露的困难性
- 2.生成的apk体积会缩小
什么是混淆?
Android SDK 本身就提供混淆的功能,将混淆开关进行开启后,开发者需要做的是对Android Studio工程项目中的proguard-rules.pro文件进行混淆白名单的配置.
那么什么是混淆白名单呢?其实就是指定一些包名、类名、变量等不可以被混淆。假设没指定白名单就进行混淆打包,而某某类的类名被混淆了(假设变成了a),那么可能其他引用或使用该类的类就找不到该类,说不定应用就会因此崩溃或是导致相应的功能无法使用.
那么所谓的混淆也就是配置混淆白名单,那么下面看看混淆之后的apk的内部结构.可以看到红圈圈出来的部分都是进行混淆的,而有部分是没有进行混淆的,比如黑圈圈出来的属性动画兼容库nineoldandroids,其包名类名就没有变成abc这样的代替符
上面我是用apk逆向助手对apk进行反编译,市场上的反编译工具有很多种,可以自行Google搜索。
补充
本篇文章记录的混淆知识点主要基于Android Studio开发工具。
Ⅱ.开始混淆
1.开启混淆开关
混淆的开关在项目/app/build.gradle文件里,看下面的截图,将minifyEnabled设置为true就是开启混淆,关于下面的配置代码可以直接写在build.gradle文件的android节点下
代码混淆一般是在上线前的apk打包才会去配置混淆开启,要是忘记配置的代码,那怎么办呢?直接进去Project Structrue,然后根据下面截图所标识的进行设置,如此这般,只要打release包就是开启混淆进行打包的.
2.设置混淆白名单
基于Android Studio创建的项目里有一文件名称为”proguard-rules.pro”的文件,路径是”项目/app/proguard-rules.pro”,没经过编辑之前,里面只有一些注释的代码,如下图
那么设置的混淆白名单又该怎么写呢?Google搜索的话会有很多博客上的模板可以复制进行套用.如下图,那么就可以进行参考,下面第三部分将常用的混淆指令和对应的注释都列举出来,基本常用的都有,有疏漏的那就自行搜索下.
Ⅲ.实际混淆指令
在应用中,大多数的混淆指令是已经确定的了,比如下面的基本指令部分,基本不用修改的。而其他的混淆指令,比如第三方的SDK/框架的混淆指令一般在其官方文档都可以找到,所以相对来说还是比较方便的,下面将这几天归类的混淆指令总结下.
基本指令:
- # 设置混淆的压缩比率 0 ~ 7
- -optimizationpasses 5
- # 混淆后类名都为小写 Aa aA
- -dontusemixedcaseclassnames
- # 指定不去忽略非公共库的类
- -dontskipnonpubliclibraryclasses
- #不做预校验的操作
- -dontpreverify
- # 混淆时不记录日志
- -verbose
- # 混淆采用的算法.
- -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
- #保留代码行号,方便异常信息的追踪
- -keepattributes SourceFile,LineNumberTable
-
- #dump文件列出apk包内所有class的内部结构
- -dump class_files.txt
- #seeds.txt文件列出未混淆的类和成员
- -printseeds seeds.txt
- #usage.txt文件列出从apk中删除的代码
- -printusage unused.txt
- #mapping文件列出混淆前后的映射
- -printmapping mapping.txt
避免混淆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 public class com.android.vending.licensing.ILicensingService
-
- #不提示V4包下错误警告
- -dontwarn android.support.v4.**
- #保持下面的V4兼容包的类不被混淆
- -keep class android.support.v4.**{*;}
避免混淆所有native的方法,涉及到C、C++
- -keepclasseswithmembernames class * {
- native <methods>;
- }
避免混淆自定义控件类的get/set方法和构造函数
- -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 enum * {
- public static **[] values();
- public static ** valueOf(java.lang.String);
- }
避免混淆序列化类
- #不混淆Parcelable和它的实现子类,还有Creator成员变量
- -keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
- }
-
- #不混淆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();
- }
避免混淆JSON类的构造函数
- #使用GSON、fastjson等框架时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象
- -keepclassmembers class * {
- public <init>(org.json.JSONObject);
- }
避免混淆第三方SDK
- # ==================环信混淆start=================
- -keep class com.hyphenate.** {*;}
- -dontwarn com.hyphenate.**
- # ==================环信end======================
-
- # ==================bugly start==================
- -dontwarn com.tencent.bugly.**
- -keep public interface com.tencent.**
- -keep public class com.tencent.** {*;}
- -keep public class com.tencent.bugly.**{*;}
- # ==================bugly end====================
-
- # ===============百度定位 start====================
- -keep class vi.com.gdi.** { *; }
- -keep public class com.baidu.** {*;}
- -keep public class com.mobclick.** {*;}
- -dontwarn com.baidu.mapapi.utils.*
- -dontwarn com.baidu.platform.comapi.b.*
- -dontwarn com.baidu.platform.comapi.map.*
- # ===============百度定位 end======================
-
- //备注:其他的第三方包的混淆指令可以到其官方文档去拷贝
避免混淆第三方框架
- # ==================picasso框架 start===============
- -keep class com.parse.*{ *; }
- -dontwarn com.parse.**
- -dontwarn com.squareup.picasso.**
- -keepclasseswithmembernames class * {
- native <methods>;
- }
- # ==================picasso end====================
-
- # ==================EventBus start=================
- -keep class org.greenrobot.** {*;}
- -keep class de.greenrobot.** {*;}
- -keepclassmembers class ** {
- public void onEvent*(**);
- void onEvent*(**);
- }
- # ==================EventBus end===================
-
- # ==================okhttp start===================
- -dontwarn com.squareup.okhttp.**
- -keep class com.squareup.okhttp.** { *;}
- -dontwarn okio.**
- -keep class okio.**{*;}
- -keep interface okio.**{*;}
- # ==================okhttp end=====================
-
- //备注:其它框架的混淆指令可以到其官方文档去拷贝
其它混淆指令
- #避免混淆属性动画兼容库
- -dontwarn com.nineoldandroids.*
- -keep class com.nineoldandroids.** { *;}
-
- #不混淆泛型
- -keepattributes Signature
-
- #避免混淆注解类
- -dontwarn android.annotation
- -keepattributes *Annotation*
-
- #避免混淆内部类
- -keepattributes InnerClasses
-
- #避免混淆实体类,修改成你对应的包名
- -keep class com.wyk.test.bean.** { *; }
- -keep class com.wyk.test.event.** { *; }
- -keep public class com.wyk.test.utils.eventbus.** { *;}
-
- #避免混淆Rxjava/RxAndroid
- -dontwarn sun.misc.**
- -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
- long producerIndex;
- long consumerIndex;
- }
- -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
- rx.internal.util.atomic.LinkedQueueNode producerNode;
- }
- -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
- rx.internal.util.atomic.LinkedQueueNode consumerNode;
- }
-
- #避免混淆js相关的接口
- -keepattributes *JavascriptInterface*
- -keep class com.wyk.test.js.** { *; }
Ⅳ.混淆配置注意点
1.假设当配置 “-libraryjars libs/jpush-android-2.1.6.jar” 对jar包进行混淆白名单化,如果gradle报错的话,可以考虑注释掉(格式:-libraryjars [jar包名])这样的配置信息.采用下面的配置信息进行替换
- -dontwarn cn.jpush.**
- -keep class cn.jpush.** { *; }
2.下面是对属性动画兼容库的混淆白名单配置信息,刚开始觉得只是保持com.nineoldandroids包下的类不被混淆,后来经过反编译混淆后的apk包,发现效果是”不混淆该class com.nineoldandroids包下的类、子包和子包的类,也不混淆其中类的成员变量.
-keep class com.nineoldandroids.** { *;}
Ⅴ.其它
1.混淆套用模板
个人觉得下面链接的博文就写得非常好,所以可以进行参考.
参考博文:5分钟搞定android混淆
2.资源混淆
Proguard混淆只是针对代码进行混淆,解压之后的apk包还是能看到项目的资源文件和其名称,比如布局、logo图片等等.这时可以选择对资源文件进行混淆,下面两个链接是腾讯推出的资源混淆工具相关的博文,可以参考.
资源混淆工具相关的博文
http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=42
https://github.com/shwenzhang/AndResGuard/blob/master/README.zh-cn.md
3.加固
为了使得apk更加不容易被破解,混淆之后还可以对apk进行加固,现今市面上的加固技术有很多种,有360加固、爱加密加固、梆梆加固等等,可以自行选择,加固技术就相当于给apk包加多一个壳,相应的体积也会增大,大概增大1M~2M左右,需要的话可以自行搜索,加固还是挺简单的.
4.参考链接
http://blog.csdn.net/maxwell_nc/article/details/51998766
http://blog.csdn.net/chen930724/article/details/49687067
http://blog.csdn.net/lovexjyong/article/details/24652085
http://www.jianshu.com/p/f3455ecaa56e
Ⅱ.下面讲异常收集(可忽略)
这篇文章主要的技术点是异常收集,项目上线前除了混淆、打包、加固、签名和发布等,还有一项是无可避免的,就是对线上的应用进行各种统计,对应用进行各种统计包括异常的收集统计、应用的渠道下载率、活跃量、留存率和页面访问路径统计等等,有很多第三方的统计SDK可供接入使用,比如友盟+、百度、诸葛IO 等第三方,精细点的话可以考虑下无埋点技术等. 只要在上线前集成了统计SDK,那么就可以在其相应的后台看到上线后各种数据的统计报表.
统计对于运营和项目维护还是很有必要的,开发人员可以看到收集到的异常,然后对异常进行分析并找到相应解决的方案,那么这里就要开始文章的主题了,下面的截图是友盟+后台收集到的异常信息,在其异常信息下面还可以收集到该异常发生的手机型号、版本和渠道。看下异常信息吧,当看到红圈圈出来的部分,是不是就迷惑了,异常信息里怎么会有abc 这样的替代符,本来异常信息可以让开发者清楚知道异常发生的地方,可以使其轻易定位到,但现在呢?难不成靠猜的方式去定位异常,那就呵呵了.怪不得朋友说异常信息定位问题非常迷惑,那么下面开始来整整这迷惑.
Ⅲ.还原混淆信息的方式
针对上面的异常信息出现abc 的替代符,主要是由于混淆打包导致的,上面abc 其实是项目的类名或变量名的代替符,那么如果apk没有经过混淆就会导致apk源码泄露或被二次打包,虽说混淆了之后的apk还是很大风险会泄露,但相对来说代码泄露的难度是增大了,所以混淆是不可缺的。那么上面的异常信息又该如何定位Bug呢?
Android SDK工具包就提供了解决的工具,sdk\tools\proguard\bin路径下名为”proguardgui.bat”和”retrace.bat”(windows和linux下,工具的后缀名不同)的两个工具,前者是通过图形化的方式去将被混淆的异常信息反编译,后者则通过命令行的方式将被混淆的异常信息反编译.那么在使用这工具前,还得有一个叫”mapping.txt”的文件,看下面截图,这是在打包apk完成后生成的一个文件,主要记录着混淆前后的信息映射关系。
每次打包apk 完成后生成的mapping.txt 都是有必要保存的,那怎么使用上面提到的 “proguardgui.bat”和”retrace.bat” 这两个工具呢?看下面截图即可,简简单单搞定proguardgui.bat ,但抱歉的是本人试了很多次,都不能将异常信息转换回去,而最无语的是搜索到的文章介绍的方法跟我操作的完全一样,这时候我就发现了经常碰到的奇葩问题,基本文章上演示截图的异常信息都是一样的,尼玛这些文章的截图既然都是抄袭的,难不成Android SDK提供的”proguardgui.bat” 图形化工具已经失效了,接着试试”retrace.bat” 工具.上面也提到了 “proguardgui.bat”和”retrace.bat” 这两个工具基本是一样的,只是使用方式不同,一个是图形化方式,一个则是命令行方式。
在retrace.bat命令行工具里反编译异常,使用的指令为
- 格式:retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]
- 例如:retrace.bat -verbose d:/mapping.txt d:/wyk_stacktrace.txt
那么接着就验证下命令行形式的 “retrace.bat”,并不同于上面的proguardgui.bat 工具有面板可以粘贴报错信息,所以先把异常信息保存为txt文件,然后命令行进入Android SDK存放的路径sdk\tools\proguard\bin目录,根据上面的指令格式进行输入,结果如下:
结论:”proguardgui.bat”和”retrace.bat” 这两个工具包无法还原Apk线上被混淆的异常信息.
上面的截图就是使用”retrace.bat” 工具的反编译异常信息的结果,可以看到abc 的标识符依然存在,所以仍得不到完整的异常信息。反复试了很多次,依旧无果,还是找找有没有其他方式吧~~话说在Android SDK的sdk\tools\proguard\lib目录下有”proguardgui.jar”和”retrace.jar” 这两个jar包,上面使用到的”proguardgui.bat”和”retrace.bat” 这两个工具可能是基于这两个jar包的,思考如果直接使用这两jar包尝试反编译异常信息的话是否有解。先试试retrace.jar 这个jar包,命令行进入到jar包所在的目录,在命令行输入如下指令,输出的信息和上面的retrace.bat工具输出的一样,依然没有完整的异常信息.
- 格式:java -jar retrace.jar [-verbose] mapping.txt [<stacktrace_file>]
- 例如:java -jar retrace.jar -verbose d:/mapping.txt d:/error.txt
接着试试proguardgui.jar,命令行进入jar包所在的目录,输入 “java -jar proguardgui.jar” 启动proguard工具,看到的界面和proguardgui.bat 是一样的,应该说proguardgui.bat 启动的也是这个jar包,验证之后还是没有得到完整的异常信息.
结论:”proguardgui.jar”和”retrace.jar” 这两个jar包无法还原Apk线上被混淆的异常信息.
Ⅳ.根据mapping.txt文件验证
上面的工具可以还原被混淆的异常信息,其原理是因为mapping.txt存在其混淆前后的映射信息,那是不是可以根据被混淆的一小段异常信息在mapping.txt文件查找相应的映射关系,拷贝被混淆的异常信息在mapping.txt文件进行全文搜索,下面图1是收集在统计异常后台的信息,图2是在mapping.txt文件查找图1红圈部分的映射信息.图3也是异常信息和映射关系.
结论:通过上面异常信息混淆前后的映射关系,切记打包时将相应的apk和生成的mapping.txt进行对应保存,这将对上线之后的Bug追踪和维护起着非常重要的作用;
Ⅴ.其他还原混淆异常信息的方式
上面根据mapping.txt查找信息映射关系的方式,显然不适合线上Bug的追踪和应用的维护,因此就得另找出口,经常使用到的统计异常SDK有友盟+和Bugly,早前一直都在用友盟+的统计异常SDK,之后由于统计数据不及时和疏漏,所以之后的应用选择接入Bugly,Bugly针对异常的收集还是非常及时和准确的。
这些统计异常的SDK其实都有提供还原被混淆异常信息的功能,这样对开发者就非常友好了,该功能的位置在SDK后台的异常信息上边,只需要导入异常信息对应的应用版本的mapping文件,点击”解析”按钮就可以看到原始的异常信息。
在友盟+的统计后台亲测发现,被混淆的异常无法还原,探究了几番仍找不到原因.而在Bugly的统计后台亲测是有效的,可以看到下面被混淆的异常信息和还原之后的异常信息.
Ⅵ.总结
- App线上异常的追踪,可以选择友盟+、百度、诸葛IO等第三方,精细点的话可以考虑下无埋点技术等;
- 经过测试发现,Android SDK包的”proguardgui.bat” 和”retrace.bat” 这两个工具包无法还原Apk线上被混淆的异常信息;
- Apk打包后生成的的mapping文件保存着代码混淆前后的映射关系;
- 第三方SDK的统计后台一般都提供还原 “被混淆异常信息” 的功能;
- 切记 打包时将apk版本和生成的mapping.txt进行对应保存.
我的模版
- #############################################
- #
- # 对于一些基本指令的添加
- #
- #############################################
- # 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
- -optimizationpasses 5
-
- # 混合时不使用大小写混合,混合后的类名为小写
- -dontusemixedcaseclassnames
-
- # 指定不去忽略非公共库的类
- -dontskipnonpubliclibraryclasses
-
- # 这句话能够使我们的项目混淆后产生映射文件
- # 包含有类名->混淆后类名的映射关系
- -verbose
-
- # 指定不去忽略非公共库的类成员
- -dontskipnonpubliclibraryclassmembers
-
- # 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
- -dontpreverify
-
- # 保留Annotation不混淆
- -keepattributes *Annotation*,InnerClasses
-
- # 避免混淆泛型
- -keepattributes Signature
-
- # 抛出异常时保留代码行号
- -keepattributes SourceFile,LineNumberTable
-
- # 指定混淆是采用的算法,后面的参数是一个过滤器
- # 这个过滤器是谷歌推荐的算法,一般不做更改
- -optimizations !code/simplification/cast,!field/*,!class/merging/*
-
- #############################################
- #
- # Android开发中一些需要保留的公共部分
- #
- #############################################
-
- # 保留我们使用的四大组件,自定义的Application等等这些类不被混淆
- # 因为这些子类都有可能被外部调用
- -keep public class * extends android.app.Activity
- -keep public class * extends android.app.Appliction
- -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.app.backup.BackupAgentHelper
- -keep public class * extends android.view.View
- -keep public class * extends android.support.v4.**
- -keep public class * extends android.support.v7.**
- -keep public class * extends android.support.annotation.**
- -keep public class com.android.vending.licensing.ILicensingService
- -dontnote android.net.http.*
- -dontnote org.apache.commons.codec.**
- -dontnote org.apache.http.**
- -dontwarn android.support.design.**
- -keep class android.support.design.** { *; }
- -keep interface android.support.design.* { *; }
- -keep public class android.support.design.R$ { *; }
-
- # 保留support下的所有类及其内部类
- -keep class android.support.** {*;}
-
- # 保留R下面的资源
- -keep class **.R$* {*;}
-
- # 保留本地native方法不被混淆
- -keepclasseswithmembernames class * {
- native <methods>;
- }
-
- # 保留在Activity中的方法参数是view的方法,
- # 这样以来我们在layout中写的onClick就不会被影响
- -keepclassmembers class * extends android.app.Activity{
- public void *(android.view.View);
- }
-
- # 保留枚举类不被混淆
- -keepclassmembers enum * {
- public static **[] values();
- public static ** valueOf(java.lang.String);
- }
-
- # 保留我们自定义控件(继承自View)不被混淆
- -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);
- }
-
- # 保留Parcelable序列化类不被混淆
- -keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
- }
-
- # 保留Serializable序列化的类不被混淆
- -keepnames class * implements java.io.Serializable
- -keepclassmembers class * implements java.io.Serializable {
- static final long serialVersionUID;
- private static final java.io.ObjectStreamField[] serialPersistentFields;
- !static !transient <fields>;
- !private <fields>;
- !private <methods>;
- private void writeObject(java.io.ObjectOutputStream);
- private void readObject(java.io.ObjectInputStream);
- java.lang.Object writeReplace();
- java.lang.Object readResolve();
- }
-
- # webView处理,项目中没有使用到webView忽略即可
- -keepclassmembers class fqcn.of.javascript.interface.for.webview {
- public *;
- }
- -keepclassmembers class * extends android.webkit.webViewClient {
- public *;
- }
-
- -dontwarn com.zhixun.extraterrestrial.util.ForbidCopyPasteUtil
-
- #############################################
- #
- # 项目中特殊处理部分
- #
- #############################################
-
- #-----------处理实体类---------------
- # 在开发的时候我们可以将所有的实体类放在一个包内,这样我们写一次混淆就行了。
- #-keep class com.blankj.data.bean.**{ *; }
-
- # 或者对实体类都加 @Keep 即可
- # @Keep
- -keep,allowobfuscation @interface android.support.annotation.Keep
- -keep @android.support.annotation.Keep class *
- -keepclassmembers class * {
- @android.support.annotation.Keep *;
- }
-
- #-----------处理第三方依赖库---------
- #--Retrofit
- -dontwarn retrofit2.**
- -keep class retrofit2.** { *; }
- -keepattributes Signature
- -keepattributes Exceptions
-
- #--RxJava RxAndroid
- -dontwarn sun.misc.**
- -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
- long producerIndex;
- long consumerIndex;
- }
- -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
- rx.internal.util.atomic.LinkedQueueNode producerNode;
- }
- -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
- rx.internal.util.atomic.LinkedQueueNode consumerNode;
- }
-
- #--Gson
- -keepattributes Signature
- -keepattributes *Annotation*
- -keep class sun.misc.Unsafe { *; }
- -keep class com.google.gson.stream.** { *; }
- # Application classes that will be serialized/deserialized over Gson 下面替换成自己的实体类
- #-keep class com.example.bean.** { *; }
-
- #--Okhttp
- -dontwarn com.squareup.okhttp3.**
- -keep class com.squareup.okhttp3.** { *;}
- -dontwarn okio.**
- -dontwarn okhttp3.internal.platform.ConscryptPlatform
-
- #--Glide
- -keep public class * implements com.bumptech.glide.module.GlideModule
- -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
- **[] $VALUES;
- public *;
- }
-
- #--Utils
- -keep class com.blankj.utilcode.** { *; }
- -keepclassmembers class com.blankj.utilcode.** { *; }
- -dontwarn com.blankj.utilcode.**
-
- #--RxLifeCycle
- -keep class com.trello.rxlifecycle2.** { *; }
-
- #--rxbinding2
- -keep class com.jakewharton.rxbinding2.view.ViewScrollChangeEventObservable { *; }
- -keep class com.jakewharton.rxbinding2.view.RxViewKt { *; }
- -keep class com.jakewharton.rxbinding2.view.ViewScrollChangeEventObservable$* { *; }
- -keep class com.jakewharton.rxbinding2.view.ViewScrollChangeEventObservable$Listener { *; }
- -keepattributes Exceptions,InnerClasses
-
- #--dagger2
- -keep class dagger.** { *; }
- -dontwarn dagger.**
-
- #--BaseRecyclerViewAdapterHelper
- -keep class com.chad.library.adapter.** { *; }
- -keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
- -keep public class * extends com.chad.library.adapter.base.BaseViewHolder
- -keepclassmembers class **$** extends com.chad.library.adapter.base.BaseViewHolder {
- <init>(...);
- }
-
- #--指纹解锁
- -keep class com.fingerprints.service.** { *; }# MeiZuFingerprint
- -keep class com.samsung.android.sdk.** { *; }# SmsungFingerprint
- -dontwarn com.samsung.android.sdk.**
- -dontwarn com.fingerprints.service.**
-
- #--k线图
- -keep class com.github.mikephil.charting.** { *; }
-
- # Realm
- -keep class io.realm.annotations.RealmModule
- -keep @io.realm.annotations.RealmModule class *
- -keep class io.realm.internal.Keep
- -keep @io.realm.internal.Keep class * { *; }
- -dontwarn javax.**
- -dontwarn io.realm.**
-
- #--换肤
- -keep class skin.support.** { *; }
- -dontwarn skin.support.**
-
- #--拷贝
- -dontwarn net.soureceforge.pinyin4j.**
- -dontwarn demo.**
- -libraryjars libs/pinyin4j-2.5.0.jar
- -keep class net.sourceforge.pinyin4j.** { *;}
- -keep class demo.** { *;}
- -keep class com.hp.** { *;}
文章来源网络:点击这里查看源文.