android混淆

前言

这阵子自己的心又长草了,静不下来~又挺迷茫的!在这个纷纷跳槽的季节,感觉还是应该让自己静下心来多学习学习。还是写写博客,总结总结~梳理下心里的野草。

上个月跟朋友讨论了这么一问题:“项目上线之后由于代码被混淆的缘故,导致收集到的异常信息看着很困难”,刚好最近在复习混淆方面的知识,在总结混淆的知识点的同时,顺便探讨总结下这问题。项目上线肯定避免不了的是对项目进行混淆、打包、签名和发布,可能还有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 这样的替代符,本来异常信息可以让开发者清楚知道异常发生的地方,可以使其轻易定位到,但现在呢?难不成靠猜的方式去定位异常,那就呵呵了.怪不得朋友说异常信息定位问题非常迷惑,那么下面开始来整整这迷惑.

Ⅲ.还原混淆信息的方式

umeng+_error.png

针对上面的异常信息出现abc 的替代符,主要是由于混淆打包导致的,上面abc 其实是项目的类名或变量名的代替符,那么如果apk没有经过混淆就会导致apk源码泄露或被二次打包,虽说混淆了之后的apk还是很大风险会泄露,但相对来说代码泄露的难度是增大了,所以混淆是不可缺的。那么上面的异常信息又该如何定位Bug呢?

Android SDK工具包就提供了解决的工具,sdk\tools\proguard\bin路径下名为”proguardgui.bat”和”retrace.bat”(windows和linux下,工具的后缀名不同)的两个工具,前者是通过图形化的方式去将被混淆的异常信息反编译,后者则通过命令行的方式将被混淆的异常信息反编译.那么在使用这工具前,还得有一个叫”mapping.txt”的文件,看下面截图,这是在打包apk完成后生成的一个文件,主要记录着混淆前后的信息映射关系。

mapping_file_img.png

每次打包apk 完成后生成的mapping.txt 都是有必要保存的,那怎么使用上面提到的 “proguardgui.bat”和”retrace.bat” 这两个工具呢?看下面截图即可,简简单单搞定proguardgui.bat ,但抱歉的是本人试了很多次,都不能将异常信息转换回去,而最无语的是搜索到的文章介绍的方法跟我操作的完全一样,这时候我就发现了经常碰到的奇葩问题,基本文章上演示截图的异常信息都是一样的,尼玛这些文章的截图既然都是抄袭的,难不成Android SDK提供的”proguardgui.bat” 图形化工具已经失效了,接着试试”retrace.bat” 工具.上面也提到了 “proguardgui.bat”和”retrace.bat” 这两个工具基本是一样的,只是使用方式不同,一个是图形化方式,一个则是命令行方式。

proguardGui_used.png

在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目录,根据上面的指令格式进行输入,结果如下:

proguard_used.png

结论:”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也是异常信息和映射关系.

3.11.2.png

3.11.1.png

3.11.3.png

结论:通过上面异常信息混淆前后的映射关系,切记打包时将相应的apk和生成的mapping.txt进行对应保存,这将对上线之后的Bug追踪和维护起着非常重要的作用;


Ⅴ.其他还原混淆异常信息的方式

上面根据mapping.txt查找信息映射关系的方式,显然不适合线上Bug的追踪和应用的维护,因此就得另找出口,经常使用到的统计异常SDK有友盟+和Bugly,早前一直都在用友盟+的统计异常SDK,之后由于统计数据不及时和疏漏,所以之后的应用选择接入Bugly,Bugly针对异常的收集还是非常及时和准确的。

这些统计异常的SDK其实都有提供还原被混淆异常信息的功能,这样对开发者就非常友好了,该功能的位置在SDK后台的异常信息上边,只需要导入异常信息对应的应用版本的mapping文件,点击”解析”按钮就可以看到原始的异常信息。

bugly_mapping01.png

bugly_mapping02.png

在友盟+的统计后台亲测发现,被混淆的异常无法还原,探究了几番仍找不到原因.而在Bugly的统计后台亲测是有效的,可以看到下面被混淆的异常信息和还原之后的异常信息.

bugly_can_useed.png


Ⅵ.总结

  • 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.** { *;}

 

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值