proguard混淆

来源:互联网 发布:ubuntu安装firefox57 编辑:程序博客网 时间:2024/05/10 03:24

proguard混淆

Android源码很容易被工具反编译出来,因此,对源码做混淆是一种非常常用的保护源码的方式,不仅如此,proguard还会对源码做一些优化,可以对代码进行去冗余压缩,代码优化,代码混淆等。在Android中的主要应用就是对代码混淆:就是将类名,方法名,Field名变成如a,b,c或者1,2,3等难以阅读和理解的名字,以防止逆向工程和被反编译阅读源码。

开启proguard混淆配置

下面说一下怎样在EclipseAndroid Studio中为项目开启proguard混淆。
Eclipse:
在项目根路径下有两个文件:project.propertiesproguard-project.txt,在创建项目时默认生成的,如果没有手动创建即可。

..

project.properties里有下面一段被注释的话,去掉#号取消注释即开启了proguard混淆:

...# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):...

Android Studio:
在项目根路径下有两个文件:build.gradleproguard-rules.pro,其中proguard-rules.pro是创建项目是默认生成的。

这里写图片描述

build.gradle中有下面的配置,即表示开启proguard混淆:

android{......  buildTypes {        release {            shrinkResources true            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }}

proguard-android.txt:这是Android SDK tools下面提供的一个默认的配置文件。
proguard-project.txt / proguard-rules.pro:这是我们自定义的配置文件,在proguard-android.txt的基础上,添加一些项目相关的自定义配置。

proguard-android.txt的默认配置:
这个文件存放于Android SDK/tools/proguard目录下,打开可以看到如下内容:

# This is a configuration file for ProGuard.# http://proguard.sourceforge.net/index.html#manual/usage.html-dontusemixedcaseclassnames-dontskipnonpubliclibraryclasses-verbose# Optimization is turned off by default. Dex does not like code run# through the ProGuard optimize and preverify steps (and performs some# of these optimizations on its own).-dontoptimize-dontpreverify# Note that if you want to enable optimization, you cannot just# include optimization flags in your own project configuration file;# instead you will need to point to the# "proguard-android-optimize.txt" file instead of this one from your# project.properties file.-keepattributes *Annotation*-keep public class com.google.vending.licensing.ILicensingService-keep public class com.android.vending.licensing.ILicensingService# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native-keepclasseswithmembernames class * {    native <methods>;}# keep setters in Views so that animations can still work.# see http://proguard.sourceforge.net/manual/examples.html#beans-keepclassmembers public class * extends android.view.View {   void set*(***);   *** get*();}# We want to keep methods in Activity that could be used in the XML attribute onClick-keepclassmembers class * extends android.app.Activity {   public void *(android.view.View);}# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations-keepclassmembers enum * {    public static **[] values();    public static ** valueOf(java.lang.String);}-keepclassmembers class * implements android.os.Parcelable {  public static final android.os.Parcelable$Creator CREATOR;}-keepclassmembers class **.R$* {    public static <fields>;}# The support library contains references to newer platform versions.# Don't warn about those in case this app is linking against an older# platform version.  We know about them, and they are safe.-dontwarn android.support.**

这个就是默认的混淆配置文件了,挨着来浏览一下。
-dontusemixedcaseclassnames 表示混淆时不使用大小写混合类名。
-dontskipnonpubliclibraryclasses 表示不跳过library中的非public的类。
-verbose 表示打印混淆的详细信息。
-dontoptimize 表示不进行优化,建议使用此选项,因为根据proguard-android-optimize.txt中的描述,优化可能会造成一些潜在风险,不能保证在所有版本的Dalvik上都正常运行。
-dontpreverify 表示不进行预校验。这个预校验是作用在Java平台上的,Android平台上不需要这项功能,去掉之后还可以加快混淆速度。
-keepattributes *Annotation* 表示对注解中的参数进行保留。

-keep public class com.google.vending.licensing.ILicensingService-keep public class com.android.vending.licensing.ILicensingService

表示不混淆上述声明的两个类,这两个类我们基本也用不上,是接入Google原生的一些服务时使用的。

-keepclasseswithmembernames class * {    native <methods>;}

表示不混淆任何包含native方法的类的类名以及native方法名,这个和我们刚才验证的结果是一致的。

-keepclassmembers public class * extends android.view.View {   void set*(***);   *** get*();}

表示不混淆任何一个View中的setXxx()和getXxx()方法,因为属性动画需要有相应的setter和getter的方法实现,混淆了就无法工作了。

-keepclassmembers class * extends android.app.Activity {   public void *(android.view.View);}

表示不混淆Activity中参数是View的方法,因为有这样一种用法,在XML中配置android:onClick=”buttonClick”属性,当用户点击该按钮时就会调用Activity中的buttonClick(View view)方法,如果这个方法被混淆的话就找不到了。

-keepclassmembers enum * {    public static **[] values();    public static ** valueOf(java.lang.String);}

表示不混淆枚举中的values()和valueOf()方法,枚举我用的非常少,这个就不评论了。

-keepclassmembers class * implements android.os.Parcelable {  public static final android.os.Parcelable$Creator CREATOR;}

表示不混淆Parcelable实现类中的CREATOR字段,毫无疑问,CREATOR字段是绝对不能改变的,包括大小写都不能变,不然整个Parcelable工作机制都会失败。

-keepclassmembers class **.R$* {    public static <fields>;}

表示不混淆R文件中的所有静态字段,我们都知道R文件是通过字段来记录每个资源的id的,字段名要是被混淆了,id也就找不着了。
-dontwarn android.support.** 表示对android.support包下的代码不警告,因为support包中有很多代码都是在高版本中使用的,如果我们的项目指定的版本比较低在打包时就会给予警告。不过support包中所有的代码都在版本兼容性上做足了判断,因此不用担心代码会出问题,所以直接忽略警告就可以了。

proguard中的keep关键字

proguard中有下面几个keep关键字:

关键字 描述 keep 保留类和类中的成员,防止它们被混淆或移除 keepnames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除 keepclassmembers 只保留类中的成员,防止它们被混淆或移除 keepclassmembernames 只保留类中的成员,防止它们被混淆,但当成员没有被引用时会被移除 keepclasseswithmembers 保留类和类中的成员,防止它们被混淆或移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆 keepclasseswithmembernames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆

proguard中的通配符

proguard还包括下面一些通配符:

通配符 描述 field 匹配类中的所有字段 method 匹配类中的所有方法 init 匹配类中的所有构造函数 * 匹配任意长度字符,但不含包名分隔符(.)。比如说我们的完整类名是com.example.test.MyActivity,使用com.,或者com.exmaple.都是无法匹配的,因为无法匹配包名中的分隔符,正确的匹配方式是com.exmaple..,或者com.exmaple.test.,这些都是可以的。但如果你不写任何其它内容,只有一个*,那就表示匹配所有的东西 ** 匹配任意长度字符,并且包含包名分隔符(.)。比如proguard-android.txt中使用的-dontwarn android.support.**就可以匹配android.support包下的所有内容,包括任意长度的子包 *** 匹配任意参数类型。比如void set*(***)就能匹配任意传入的参数类型,*** get*()就能匹配任意返回值的类型 … 匹配任意长度的任意类型参数。比如void test(…)就能匹配任意void test(String a)或者是void test(int a, String b)这些方法

对项目做混淆配置proguard-android.txt

我们可以修改proguard-android.txt中的规则,但是直接在proguard-android.txt中修改会对我们本机上所有项目的混淆规则都生效,那么有没有什么办法只针对当前项目的混淆规则做修改呢?当然是有办法的了,你会发现任何一个Android Studio项目在app模块目录下都有一个proguard-rules.pro文件,这个文件就是用于让我们编写只适用于当前项目的混淆规则的,那么接下来用上面的知识来对项目混淆规则做修改。

  1. 对项目中使用到的三方库做处理
    -dontwarn xxx.xxx.**
    某些三方库中对某些API做了引用,如果不存在,则在打包的时候会报错,使用-dontwarn,可以在打包的时候忽略此错误.
    -keep class xxx.xxx.** { *; }
    这样是不对指定包下面的所有子包和类做任何混淆,因为引用的都是三方开源库,既然是开源的,所以也没用必要做混淆.
    下面列出了项目中用到的三方库混淆:
    google的support库:

    -keep class android.support.** { *; }

    EventBus:

    -keep class de.** { *; }

    Volley:

    -keep  class com.android.volley.** { *; }

    百度推送和百度地图:

    -keep  class com.baidu.** { *; }

    Gson:

    -keep  class com.google.gson.** { *; }

    universal-image-loader

    -keep  class com.nostra13.universalimageloader.** { *; }

    友盟统计

    -keep  class com.umeng.analytics.** { *; }

    OkHttp

    -keep  class okhttp3.** { *; }

    okio

    -keep  class okio.** { *; }

    LitePal

    -keep  class org.litepal.** { *; }
  2. 对Gson解析的实体类不能做混淆
    因为Gson在把Json串解析成实体类的时候,是通过反射来获取类的字段名,所以不能对类做混淆.因为项目里面需要由Gson解析的实体类都存放在reponse包下面,所以添加下面的配置:
    -keep class **.response.** { *; }
    另外,所有请求返回需要解析的对应的实体类跟请求URL关联,存放在ResponseTypeProvider 里面的,所以需要添加下面的配置:
    -keep class **.ResponseTypeProvider { *; }
    最后,Gson还需要添加下面的配置:
    -keepattributes Signature

  3. LitePal
    项目中应用了ORM数据库LitePal,会把继承了DataSupport 的类通过反射获取想要属性生成对应表和字段,所以对继承了DataSupport 的类不能做混淆:
    -keep class * extends org.litepal.crud.DataSupport { *; }

  4. EventBus
    项目中用到了EventBus作为事件总线处理库,它会通过反射去看注册了的类,需要用OnEvent***()的方法,如果找不到则会直接Crash,所以需要对所有onEvent***()不做混淆,其中方法参数也是不定的,所以()里面参数用**代替:

    -keepclassmembers class ** { public void onEvent*(**);}
  5. 百度地图
    由于对百度地图下面的所有类都做了混淆,在运行百度地图的时候,应用会Crash掉,提示vi.com.gdi.bgl.android.java.EnvDrawText 找不到,所以需要添加下面的配置:

    -keep class vi.com.gdi.bgl.android.java.EnvDrawText { *; }
0 0