打包系列教程目录:

纯ant命令行打包android apk之图文从原理角度完全详解android打包过程(打包系列教程之一)

用ant的build.xml构建自动化打包android apk 完全详解(打包系列教程之二)

Android 多渠道打包之混淆文件ProGuard技术详解-特别篇(打包系列教程之三)

android studio gradle 多渠道打包之完全详解(打包系列教程之四)

android studio gradle 多版本多apk打包(打包系列教程之五)

详解高速神器python脚步打包android apk,超级快!!(打包系列教程之六)


通过前两篇的学习,我们对android打包流程有了基本的认识,本来这篇内容是准备分析ant的android多渠道打包过程,但是在测试案例的时候,发现还有一个比较重要的知识点没介绍-ProGuard技术,因此本篇就来介绍一下android的混淆技术之ProGuard。

1.什么是ProGuard技术?

 首先我们来了解一下什么是ProGuard技术,直接上google官网的说明:

  The ProGuard tool shrinks, optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and methods with semantically obscure names. The result is a smaller sized .apkfile that is more difficult to reverse engineer. Because ProGuard makes your application harder to reverse engineer, it is important that you use it when your application utilizes features that are sensitive to security like when you are Licensing Your Applications.

      ProGuard is integrated into the Android build system, so you do not have to invoke it manually. ProGuard runs only when you build your application in release mode, so you do not have to deal with obfuscated code when you build your application in debug mode. Having ProGuard run is completely optional, but highly recommended.

    第一段话的意思是,ProGuard工具是用于压缩,优化,混淆我们的代码,主作用是可以移除代码中的无用类,字段,方法和属性同时可以混淆(类,字段,方法,属性的)命名。最终结果可以使我们的apk文件体积更加小,也会让我们的apk更加难以被他人逆向工程,这对于那些特别时包含一些安全性功能的apk来说是相当重要的。很抽象,我也这么觉得,结合其他资料,我们把ProGuard技术的功能概括为以下4项:

1.压缩(shrinks)  :检查并移除代码中无用的类,字段,方法,属性。

2.优化(optimizes):对字节码进行优化,移除无用的指令。

3.混淆(obfuscates):使用a,b,c,d等简短而无意义的名称,对类,字段和方法进行重名,这样即使代码被逆向工程,对方也比较难以读懂。

4.预检测(Preveirfy):在java平台上对处理后的代码进行再次检测。

这样应该比较好理解,概括成一句话就是ProGuard技术可以压缩,优化我们的apk,同时会混淆我们的代码,以防止被破解后对方也比较难以读懂我们的apk代码,为进一步保证代码的可运行性,ProGuard还会对混淆后的代码进行预检测,从而让代码更具稳定性。

        第2段话的意思是,ProGuard混淆技术是集成到Android构建系统,所以我们不需要手动调用它。ProGuard混淆技术只有当我们构建您的应用程序并准备发布应用时才需要使用,所以我们在debug模式下没有必要进行代码混淆。ProGuard混淆技术也只是一种可选技术,即使不使用ProGuard混淆技术,我们的应用程序也可以进行运行,但是强烈建议在发布应用程序时使用该技术。

        通过上述google官网的说明,我们也就明白了ProGuard混淆技术已经集成在了Android构建环境中,我们在使用时不无需关注如何调用,系统会环境会在需要时会自动去调用,因此我们要做的唯一一件事就是写好ProGuard混淆文件。下面我们先来了解一下ProGuard技术的工作原理。

2.ProGuard技术的工作原理

        通过前面的分析我们也知道了ProGuard技术是由shrinks,optimizes,obfuscates,Preveirfy四个功能组成,其中每个功能都是可选择,但是google已经帮我们决定了使用ProGuard的功能,我们无需关心。那么ProGuard是如何工作的呢?在这里我们引入一个概念EntryPoint。EntryPoint可以理解为一种标志,它是在ProGuard过程中不会被处理的类或者方法,在压缩的过程,ProGuard会从上述的EntryPoint中开始遍搜索出哪些类和类的成员在使用(被标记为EntryPoint的类和方法有些是在使用的而且这些是我们在混淆文件中配置不希望被混淆的类和方法,有些是没有使用的)。对于那些没有被使用的类和成员,就会在压缩阶段被丢弃。然后在接下来的优化步骤中,那些非EntryPoint的类,方法都会被设置为private,static或者final,而且不使用的参数都会被移除。接着在混淆的步骤中,ProGuard会对非EntryPoint的类和方法进行重命名。最后就会对代码进行预检测,以便保证稳定性。

为什么要进行代码混淆呢?

Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码。为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆。混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义。被混淆过的程序代码,仍然遵照原来的档案格式和指令集,执行结果也与混淆前一样,只是混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,在缺乏相应的函数名和程序注释的况下,即使被反编译,也将难以阅读。同时混淆是不可逆的,在混淆的过程中一些不影响正常运行的信息将永久丢失,这些信息的丢失使程序变得更加难以理解。

3.构建属于我们自己的ProGuard文件

       既然其他事情google都帮我们搞定了,那我们就专心写ProGuard文件吧。下面是混淆的基本配置信息,几乎所有app都要使用,可以说是ProGuard文件必备的内容

3.1基本配置
-optimizationpasses 5  #指定代码的压缩级别 0 - 7,一般都是5,无需改变-dontusemixedcaseclassnames #不使用大小写混合,混淆后类名称为小写#告诉Proguard 不要跳过对非公开类的处理,默认是跳过-dontskipnonpubliclibraryclasses #如果应用程序引入的有jar包,并且混淆jar包里面的class#不做预校验,preverify是proguard的4个功能之一#android不需要preverify,去掉这一步加快混淆速度-dontpreverify-verbose #混淆时记录日志(混淆后生产映射文件 map 类名 -> 转化后类名的映射-printmapping proguardMapping.txt #指定映射文件的名称#指定混淆时的算法,后面的参数是一个过滤器#这个过滤器是谷歌推荐的算法,一般也不会改变-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*#类型转换错误 添加如下代码以便过滤泛型(不写可能会出现类型转换错误,一般情况把这个加上就是了),即避免泛型被混淆-keepattributes Signature#假如项目中有用到注解,应加入这行配置,对JSON实体映射也很重要,eg:fastjson-keepattributes *Annotation*#抛出异常时保留代码行数-keepattributes SourceFile,LineNumberTable
注释很详细,不过多解释,对于-dontusemixedcaseclassnames这里有点要说明一下,proguard会默认我们的操作系统能够区分大小写字母的文件,如b.java和B.java会被认为是两个不同的文件,但是window系统并不这样认为(window系统对大小写不敏感的)。因此在window系统下必须在 proguard文件中指明-dontusemixedcaseclassnames选项。如果没这样做并且我们的项目中类的数量超过26个的话,那么proguard就会默认混用大小写文件名,进而导致class文件相互覆盖。所以为了安全起见,我们都默认设置该选项。

3.2 需要保留的相关信息(指明不需要混淆的相关信息)

#保持 native 的方法不去混淆-keepclasseswithmembernames class * {    native ;}#v4包下的文件都不要混淆 -dontwarn   如果有警告也不终止-dontwarn android.support.v4.**-keep class android.support.v4.app.**{*;}-keep class android.support.v4.** { *; }-keep interface android.support.v4.app.** { *; }-keep public class * extends android.support.v4.**-keep public class * extends android.app.Fragment  #所有fragment的子类不要去混淆-keep public class * extends android.app.Activity  #所有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 * extends android.view.View-keep public class com.android.vending.licensing.ILicensingService#保持指定规则的方法不被混淆(Android layout 布局文件中为控件配置的onClick方法不能混淆)-keepclassmembers class * extends android.app.Activity {    public void *(android.view.View);}#保持自定义控件指定规则的方法不被混淆-keep public class * extends android.view.View {    public (android.content.Context);    public (android.content.Context, android.util.AttributeSet);    public (android.content.Context, android.util.AttributeSet, int);    public void set*(...);}#保持枚举 enum 不被混淆-keepclassmembers enum * {    public static **[] values();    public static ** valueOf(java.lang.String);}#保持 Parcelable 不被混淆(aidl文件不能去混淆)-keep class * implements android.os.Parcelable {    public static final android.os.Parcelable$Creator *;}#需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆)-keepnames class * implements java.io.Serializable#保护实现接口Serializable的类中,指定规则的类成员不被混淆-keepclassmembers class * implements java.io.Serializable {    static final long serialVersionUID;    private static final java.io.ObjectStreamField[] serialPersistentFields;    !static !transient ;    private void writeObject(java.io.ObjectOutputStream);    private void readObject(java.io.ObjectInputStream);    java.lang.Object writeReplace();    java.lang.Object readResolve();}#保持R文件不被混淆,否则,你的反射是获取不到资源id的-keep class **.R$* { *; }#对于带有回调函数onXXEvent的不被混淆-keepclassmenbers class *{    void *(**On*Event)
3.3 对于我们自己特定app相关的信息
我们创建一个项目,结构目录如下:


3.3.1.保留model中的实体类和成员不被混淆

一般建议我们的实体类都写在同一个包下,方便我们书写混淆代码,我们的混淆代码应该这样写:

-keep public class com.zejian.android4package.model.**{*;} 

3.3.2.保留内部类不被混淆

如果内部类如果被混淆后,我们的代码如果刚好被调用这时候就会造成空指针而崩溃,有一个一劳永逸的办法就是不写内部类,把需要的类单独抽成一个类。但如果一定要写内部类的话,那么这个类就必须在混淆时进行保留。举个例子,我们要保留NewFragment的所有内部类,可以按以下书写方式($符是用来分割内部类和本体类的):

-keep public class com.zejian.android4package.fragment. NewFragment$*{*;} 

3.3.3.WebView相关信息不被混淆

如果项目中使用到了WebView的相关操作,必须加入以下代码:

-keepclassmembers class * extends android.webkit.WebViewClient {  public void *(android.webkit.WebView,java.lang.String,android.graphics.Bitmap);  public boolean *(android.webkit.WebView,java.lang.String);}-keepclassmembers class * extends android.webkit.WebChromeClient {  public void *(android.webkit.WebView,java.lang.String);}

3.3.4.JavaScript相关信息不被混淆

比如我们代码定义了与js调用相关的回调类,这时我们也保证该类不能被混淆(项目中所有使用js交互的都必须确保不被混淆)。

final class JavaScriptInterface {            public void clickOnAndroid() {                mHandler.post(new Runnable() {                    public void run() {                        mWebView.loadUrl("javascript:wave()");                    }                });            }        }   
假定这时JavaScriptInterface 是MainActivity的内部类,保留指令应该这样书写:

-keepclassmembers class com.zejian.android4package.activity.MainActivity$JavaScriptInterface {      ;  }  

3.3.5.反射的处理

        比较幸运的是proguard对Class.forName("AnyClass")中的参数AnyClass字段进行保留,在这样点上proguard还是比较智能的,因为它会检测程序总中使用的Class.forName方法,并对其参数AnyClass字符串进行保留。但是在混淆的过程中,对于Class.forName("AnyClass")方法或者AnyClass.class的类名称都会被混淆。因此,我们要在proguard文件中保留这样的类名称。共有以下要避免混淆的函数:

Class.forName("AnyClass");AnyClass.class.getField("someField");AnyClass.class.getDeclaredField("someField");AnyClass.class.getMethod("someField",new Class[]{});AnyClass.class.getMethod("someField",new Class[]{A.class});AnyClass.class.getMethod("someField",new Class[]{A.class,B.class});AnyClass.class.getDeclaredMethod("someField",new Class[]{});AnyClass.class.getDeclaredMethod("someField",new Class[]{A.class});AnyClass.class.getDeclaredMethod("someField",new Class[]{A.class,B.class});AtomicIntegerFieldUpdater.newUpdater(AnyClass.class,"someField");AtomicLongFieldUpdater.newUpdater(AnyClass.class,"someField");AtomicReferenceFieldUpdater.newUpdater(AnyClass.class,SomeType.class,"someField");

在混淆的时候,我们要在项目中搜寻以上的方法,将相应的类活着方法名称进行保留而不被混淆。

3.4 针对第三方jar包的解决方案

这里分两种情况,一种是我们用的第三方开源库,另一种是我们使用的第三方的SDK。开源库是没有必要混淆的,因为源码都是开源的,大家都可以用的代码。而第三方SDK也没有必要混淆,因为这些SDK都是经过混淆的,所以对于这些SDK我们要做的是避免这些SDK的类和方法在我们的app代码中被混淆。比如我们使用了第3方法开源库,如Volley网络请求库,Gson解析库,android-support-v4包.....我们可以进行如下保留:

# 不混淆 GSON-keep class com.google.gson.** { *; }-keep class com.google.gson.JsonObject {*;}-keep class org.json.** {*;}-keep class com.badlogic.** { *;}-keep class * extends com.badlogic.gdx.utils.Json*-keep class com.google.** {*;}-keep class sun.misc.Unsafe { *; }-keep class com.futurice.project.models.pojo.** { *; }#volley-keep class com.android.volley.**{*;}-keep class com.android.volley.** {*;}-keep class com.android.volley.toolbox.** {*;}-keep class com.android.volley.Response$* { *; }-keep class com.android.volley.Request$* { *; }-keep class com.android.volley.RequestQueue$* { *; }-keep class com.android.volley.toolbox.HurlStack$* { *; }-keep class com.android.volley.toolbox.ImageLoader$* { *; }
如果是第三方SDK,我们可以按照官方提供的代码进行避免被混淆,如百度地图,环信等....

#第3方即时通信:环信不混淆-keep class com.easemob.** {*;}-keep class org.jivesoftware.** {*;}-keep class org.apache.** {*;}-dontwarn  com.easemob.**#2.0.9后的不需要加下面这个keep#-keep class org.xbill.DNS.** {*;}#另外,demo中发送表情的时候使用到反射,需要keep SmileUtils-keep class com.easemob.chatuidemo.utils.SmileUtils {*;}#注意前面的包名,如果把这个类复制到自己的项目底下,比如放在com.example.utils底下,应该这么写(实际要去掉#)#-keep class com.example.utils.SmileUtils {*;}#如果使用easeui库,需要这么写-keep class com.easemob.easeui.utils.EaseSmileUtils {*;}#2.0.9后加入语音通话功能,如需使用此功能的api,加入以下keep-dontwarn ch.imvs.**-dontwarn org.slf4j.**-keep class org.ice4j.** {*;}-keep class net.java.sip.** {*;}-keep class org.webrtc.voiceengine.** {*;}-keep class org.bitlet.** {*;}-keep class org.slf4j.** {*;}-keep class ch.imvs.** {*;}
3.5  提几点注意事项

3.5.1 根据我在公司这段时间的工作经验,一开始我打包给测试时,都没经过混淆,测试完后都以为没问题了,但是后面混淆打包一堆问题就来了,只能一个个解决呗,所以还是比较推荐给测试人员的时候,尽量以混淆包为主,这样可以提前发现问题。比较突出的问题是引用第3方包时,混淆后很容易出现各种莫名其妙的错误,所以这点要特别小心,一定要对第3方的功能加以测试,确保混淆后没问题。

3.5.2 打包时,要注意看log记录,尽量不要使用-ignorewarnings语句,因为它会忽略所有警告,这样的话隐藏风险太大了。

3.5.3 注意别混淆了自定义的view类,否则xml文件在寻找类时可能会抛空指针异常。

3.6 如何使用proguard文件  

这里分两种,一种是eclipse,一种是android studio:

我们先来看一下eclipse的项目:


我们可以看到标明的两个文件,proguard-project.txt(以前使用的是proguard.cfg)和project.properties文件(这两个文件是创建项目时自动生成的),其中proguard-project.txt就是用来书写ProGuard规则的文件,我们前面所描述的全部规则都要写在这个文件里面。我们打开该文件看看


可以看文件开头的注释说明:Add project specific ProGuard rules here. By default, the flags in this file are appended to flags specified in ${sdk.dir}/tools/proguard/proguard-android.txt。这里主要是说在该文件添加ProGuard规则而且android工具中也提供了一个默认的proguard-android.txt文件,路径是${sdk.dir}/tools/proguard/proguard-android.txt。至于使用我们自己编写还是默认提供的proguard-project.txt这是由我们自己决定的。这里有点要说明的是,除了我们前面所分析的ProGuard规则外,我们在proguard-project.txt文件中还需要添加说明一些jar包或者依赖的library:


接下来我们要看看proguard-project.txt文件又是在那里决定的呢?其实这就是在 project.properties文件里面决定的,我们看看该文件

第一段注释就说明了该文件是由Android Tools自动帮我们创建的。第二段意思是我们需要自定义一个名为ant.properties的属性文件,这个文件将被用于ant的构建系统。其实这个文件是用来存放我们的签名key信息的,而这些信息将会被我们定义的build.xml文件所读取,用于ant的自动化打包的签名信息(这个在下一篇内容会重新分析,我们在这里只要知道有这样一个文件就行),下面给出ant.properties的文件例子,注意该文件需要我们自己创建噢。


我们这里仅为演示,随意给出一个key的信息,如果大家需要用eclipse打包的话,按该规则使用填写自己的信息即可。我用的是mac系统哈,window系统可能需要变成反双斜杆:


第三段意思是说,为了确保我们的代码可以使用ProGuard技术进行压缩,混淆,我们需要在该文件注明我们要使用的proguard-project.txt文件。第四段是注明我们项目所使用的android版本号。如图我们使用的是android-22的API。这里我们给出project.properties文件的一般使用配置(eclipse版):

# This file is automatically generated by Android Tools.# Do not modify this file -- YOUR CHANGES WILL BE ERASED!## This file must be checked in Version Control Systems.## To customize properties used by the Ant build system edit# "ant.properties", and override values to adapt the script to your# project structure.## To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt# Project target.#指明我们项目所使用的API级别target=android-22#指明我们混淆代码所使用的proguard文件proguard.config=proguard-android.txt#指明我们项目所依赖的library,比如我们这里使用到了环信SDK,android-support-v7-appcompat...android.library.reference.1=../chatmodelandroid.library.reference.2=../android-support-v7-appcompatandroid.library.reference.3=../cardview

 好了,eclipse就介绍到这里。但还是建议赶紧转android studio吧。接下来我们来看看android studio上打包时是如何使用proguard文件的,下面是android studio项目工程目录:


我们可以看到as中只有一个 proguard-rules.pro文件,而这个就是我们需要书写混淆规则的文件。同样的方法,我们打开该文件看看

标明红框的这段话的意思是,在这个文件中指明我们混淆代码的规则,默认的as会指明android工具箱中自带的proguard-project.txt文件,而且我们可以通过该项目的build.gradle文件更改我们所要使用的混淆文件。既然这样我们看看build.gradle文件


通过gadle文件,我们发现这里面配置了我们签名要使用到的key信息(相当代替eclipse中的ant.properties文件),同时在构建类型(buildTypes)中通过minifyEnabled属性设置为true来启用混淆优化功能,其中proguardFiles这部分有两段,前一部分代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明,免去了我们很多事,这个文件的目录在 /tools/proguard/proguard-android.txt , 后一部分是我们项目里的自定义的混淆文件,目录就在 app/proguard-rules.pro , 如果我们用Studio 创建的新项目默认生成的文件名是 proguard-rules.pro , 这个名字没关系,在这个文件里我们可以声明第三方依赖的一些混淆规则和一些自己的混淆规则,而signingConfig则是引用前面已经定义好的签名key信息,同时要注意的是通过Android Studio进行 混淆代码时,默认已经将 lib目录中的 jar 都已经添加到打包脚本中,所以不需要再次手动添加,否则会出现“ java.io.IOException: The same input jar is specified twice” 错误。还有一点与eclipse不同的是默认情况下Android Studio生成mapping.txt等文件的路径是build/outputs/mapping/release/mapping.txt,因此没必要proguard-rules.pro文件中配置以下信息(eclipse的proguard-project.txt文件需要配置):

 #未混淆的类和成员 -printseeds seeds.txt #列出从 apk 中删除的代码 -printusage unused.txt #混淆前后的映射 -printmapping mapping.txt
最后这里我给出一份比较 完整proguard-rules.pro的混淆文件,大家可以根据需要去留其中的信息,仅供参考:
# Add project specific ProGuard rules here.# By default, the flags in this file are appended to flags specified# in D:\adt-bundle-windows-x86-20140702\sdk/tools/proguard/proguard-android.txt# You can edit the include path and order by changing the proguardFiles# directive in build.gradle.## For more details, see#   http://developer.android.com/guide/developing/tools/proguard.html# Add any project specific keep options here:# If your project uses WebView with JS, uncomment the following# and specify the fully qualified class name to the JavaScript interface# class:#-keepclassmembers class fqcn.of.javascript.interface.for.webview {#   public *;#}-optimizationpasses 5  #指定代码的压缩级别 0 - 7,一般都是5,无需改变-dontusemixedcaseclassnames #不使用大小写混合#告诉Proguard 不要跳过对非公开类的处理,默认是跳过-dontskipnonpubliclibraryclasses #如果应用程序引入的有jar包,并且混淆jar包里面的class-verbose #混淆时记录日志(混淆后生产映射文件 map 类名 -> 转化后类名的映射#指定混淆时的算法,后面的参数是一个过滤器#这个过滤器是谷歌推荐的算法,一般也不会改变-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*#类型转换错误 添加如下代码以便过滤泛型(不写可能会出现类型转换错误,一般情况把这个加上就是了),即避免泛型被混淆-keepattributes Signature#假如项目中有用到注解,应加入这行配置,对JSON实体映射也很重要,eg:fastjson-keepattributes *Annotation*#抛出异常时保留代码行数-keepattributes SourceFile,LineNumberTable#保持 native 的方法不去混淆-keepclasseswithmembernames class * {    native ;}#第三方开源框架以及第三方jar包中的代码不是我们的目标和关心的对象,因此我们全部忽略不进行混淆。#EventBus的代码没必要混合-keep class com.XXX.eventbus.** { *; }-keep class com.XXX.event.** { *; }-keep class com.XXX.eventbus.util.** { *; }-keep class android.os.**{*;}-keepclassmembers class ** {    public void onEvent*(**);}#百度地图API不混淆-keep class com.baidu.** { *; }-keep class vi.com.gdi.bgl.android.**{*;}#友盟统计-keepclassmembers class * {   public (org.json.JSONObject);}#litepal 数据库框架-dontwarn org.litepal.*-keep class org.litepal.** { *; }-keep enum org.litepal.**-keep interface org.litepal.** { *; }-keep public class * extends org.litepal.**-keepclassmembers class * extends org.litepal.crud.DataSupport{*;}#ShareSDK-keep class cn.sharesdk.**{*;}-keep class com.sina.**{*;}-keep class **.R$* {*;}-keep class **.R{*;}-dontwarn cn.sharesdk.**-dontwarn **.R$*-keep class m.framework.**{*;}#个推-dontwarn com.igexin.**-dontwarn android.support.**-keep class com.igexin.**{*;}-keep class com.igexin.push.extension.distribution.basic.headsup.**{*;}#v4包下的文件都不要混淆 -dontwarn   如果有警告也不终止-dontwarn android.support.v4.**-keep class android.support.v4.app.**{*;}-keep class android.support.v4.** { *; }-keep interface android.support.v4.app.** { *; }-keep public class * extends android.support.v4.**-keep public class * extends android.app.Fragment  #所有fragment的子类不要去混淆-keep public class * extends android.app.Activity  #所有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 * extends android.view.View-keep public class com.android.vending.licensing.ILicensingService#保持指定规则的方法不被混淆(Android layout 布局文件中为控件配置的onClick方法不能混淆)-keepclassmembers class * extends android.app.Activity {    public void *(android.view.View);}#保持自定义控件指定规则的方法不被混淆-keep public class * extends android.view.View {    public (android.content.Context);    public (android.content.Context, android.util.AttributeSet);    public (android.content.Context, android.util.AttributeSet, int);    public void set*(...);}#保持枚举 enum 不被混淆-keepclassmembers enum * {    public static **[] values();    public static ** valueOf(java.lang.String);}#保持 Parcelable 不被混淆(aidl文件不能去混淆)-keep class * implements android.os.Parcelable {    public static final android.os.Parcelable$Creator *;}#需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆)-keepnames class * implements java.io.Serializable#保护实现接口Serializable的类中,指定规则的类成员不被混淆-keepclassmembers class * implements java.io.Serializable {    static final long serialVersionUID;    private static final java.io.ObjectStreamField[] serialPersistentFields;    !static !transient ;    private void writeObject(java.io.ObjectOutputStream);    private void readObject(java.io.ObjectInputStream);    java.lang.Object writeReplace();    java.lang.Object readResolve();}#保持R文件不被混淆,否则,你的反射是获取不到资源id的-keep class **.R$* { *; }#以下针对App本身设置#保护WebView对HTML页面的API不被混淆-keep class **.Webview2JsInterface { *; }#如果你的项目中用到了webview的复杂操作,最好加入-keepclassmembers class * extends android.webkit.WebViewClient {  public void *(android.webkit.WebView,java.lang.String,android.graphics.Bitmap);  public boolean *(android.webkit.WebView,java.lang.String);}-keepclassmembers class * extends android.webkit.WebChromeClient {  public void *(android.webkit.WebView,java.lang.String);}#对WebView的简单说明下:经过实战检验,做腾讯QQ登录,如果引用他们提供的jar,#若不加防止WebChromeClient混淆的代码,oauth认证无法回调,反编译基代码后可看到他们有用到WebChromeClient,加入此代码即可。#转换JSON的JavaBean,类成员名称保护,使其不被混淆-keepclassmembernames class com.cgv.cn.movie.common.bean.** { *; }#保证自定义类不被混淆 XXX换成你自己的包名-keep class com.XXX.view.** {*;}# 保持实体数据结构接口不被混淆(也就是被GSON注解的实体结构)此处是自己接口的包名 XXX换成你自己的包名-keep class com.XXX.model.** { *; }#使用gson包解析数据时,出现 missing type parameter 异常,添加如下代码-dontobfuscate #不混淆输入的类文件-dontoptimize  #不优化输入的类文件# 不混淆 GSON-keep class com.google.gson.** { *; }-keep class com.google.gson.JsonObject {*;}-keep class org.json.** {*;}-keep class com.badlogic.** { *;}-keep class * extends com.badlogic.gdx.utils.Json*-keep class com.google.** {*;}-keep class sun.misc.Unsafe { *; }-keep class com.futurice.project.models.pojo.** { *; }#volley-keep class com.android.volley.**{*;}-keep class com.android.volley.** {*;}-keep class com.android.volley.toolbox.** {*;}-keep class com.android.volley.Response$* { *; }-keep class com.android.volley.Request$* { *; }-keep class com.android.volley.RequestQueue$* { *; }-keep class com.android.volley.toolbox.HurlStack$* { *; }-keep class com.android.volley.toolbox.ImageLoader$* { *; }#fresco 防止该包下native类别优化时处理掉,运行奔溃-keep class com.facebook.imagepipeline.nativecode.**{*;}-keep class android.os.**{*;}#第3方即时通信:环信不混淆-keep class com.easemob.** {*;}-keep class org.jivesoftware.** {*;}-keep class org.apache.** {*;}-dontwarn  com.easemob.**#2.0.9后的不需要加下面这个keep#-keep class org.xbill.DNS.** {*;}#另外,demo中发送表情的时候使用到反射,需要keep SmileUtils-keep class com.easemob.chatuidemo.utils.SmileUtils {*;}#注意前面的包名,如果把这个类复制到自己的项目底下,比如放在com.example.utils底下,应该这么写(实际要去掉#)#-keep class com.example.utils.SmileUtils {*;}#如果使用easeui库,需要这么写-keep class com.easemob.easeui.utils.EaseSmileUtils {*;}#2.0.9后加入语音通话功能,如需使用此功能的api,加入以下keep-dontwarn ch.imvs.**-dontwarn org.slf4j.**-keep class org.ice4j.** {*;}-keep class net.java.sip.** {*;}-keep class org.webrtc.voiceengine.** {*;}-keep class org.bitlet.** {*;}-keep class org.slf4j.** {*;}-keep class ch.imvs.** {*;}

参考资料:app研发录

更多相关文章

  1. NPM 和webpack 的基础使用
  2. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  3. 读取android手机流量信息
  4. android EditText设置不可写
  5. android 使用html5作布局文件: webview跟javascript交互
  6. android studio调试c/c++代码
  7. Android(安卓)多媒体扫描过程(Android(安卓)Media Scanner Proces
  8. android“设置”里的版本号
  9. Android开发环境搭建

随机推荐

  1. SpringMVC+Volley实现Android端上传文件
  2. 网络请求Volley篇【Android】
  3. Android(安卓)禁止RecyclerView 上下滚动
  4. 从Android(安卓)init.rc到SystemServer.j
  5. Android画布(cavas)
  6. [init.rc] android开机过程执行shell脚本
  7. JetBrains与谷歌合作开发新一代Android开
  8. Android系统源码阅读(17):Android(安卓)应用
  9. Android(安卓)4.0 隐藏虚拟按键(导航栏)
  10. Android(安卓)CoordinatorLayout自定义Be