Android 混淆查缺补漏

2

 

在基于Android Studio项目的app module的build.gradle中有如下默认代码片段:

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

代表要发布的release包的混淆配置,默认不开启混淆,要开启混淆首先做如下修改:

minifyEnabled true

开启混淆后还可以添加shrinkResources true配置,代表开启资源文件压缩。

这样就在release模式下开启了混淆。一般在debug模式下不开启混淆,因为混淆会导致编译时间变长、无法debug问题,毕竟也是内部测试嘛,没必要!

 

开启混淆后,接下来就是用混淆配置文件来设置混淆规则:

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  • proguard-android.txt代表系统默认的混淆规则配置文件,该文件在<Android SDK目录>/tools/proguard下,一般不要更改该配置文件,因为也会作用于其它项目,除非你能确保所做的更改不影响其它项目的混淆。

  • proguard-rules.pro代码表当前project的混淆配置文件,在app module下,可以通过修改该文件来添加适用当前项目的混淆规则。

 

 

2.编写混淆配置文件

 

为了更好的编写proguard-rules.pro,先学习下系统的proguard-android.txt

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
# 混淆时不使用大小写混合类名
-dontusemixedcaseclassnames
# 不跳过library中的非public的类
-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
# 不混淆包含native方法的类的类名以及native方法名
-keepclasseswithmembernames class * {
    native <methods>;
}
# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
# 不混淆View中的setXxx()和getXxx()方法,以保证属性动画正常工作
-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
# 不混淆Activity中参数是View的方法,例如,一个控件通过android:onClick="clickMethodName"绑定点击事件,混淆后会导致点击事件失效
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
# 不混淆枚举类中的values()和valueOf()方法
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
# 不混淆Parcelable实现类中的CREATOR字段,以保证Parcelable机制正常工作
-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}
# 不混淆R文件中的所有静态字段,以保证正确找到每个资源的id
-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.
# 不对android.support包下的代码警告(如果我们打包的版本低于support包下某些类的使用版本,会出现警告的问题)
-dontwarn android.support.**
# Understand the @Keep support annotation.
# 不混淆Keep类
-keep class android.support.annotation.Keep
# 不混淆使用了注解的类及类成员
-keep @android.support.annotation.Keep class * {*;}
# 如果类中有使用了注解的方法,则不混淆类和类成员
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <methods>;
}
# 如果类中有使用了注解的字段,则不混淆类和类成员
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <fields>;
}
# 如果类中有使用了注解的构造函数,则不混淆类和类成员
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <init>(...);
}

可以看出proguard-android.txt主要作用是防止指定内容被混淆,其中使用了以-开头,结合keep类关键字,*、<>等通配符的语法,先get这些语法吧!

 

首先看keep类关键字:

 

 

关键字 含义
keep

 保留类和类成员,防止被混淆或移除

 

keepnames

 保留类和类成员,防止被混淆,但没有被引用的类成员会被移除

 

keepclassmembers只保留类成员,防止被混淆或移除
keepclassmembernames 只保留类成员,防止被混淆,但没有被引用的成员会被移除
keepclasseswithmembers 保留类和类成员,防止被混淆或移除,如果指定的类成员不存在还是会被混淆
keepclasseswithmembernames

 保留类和类成员,防止被混淆,如果指定的类成员不存在还是会被混淆,没有被引用的类成员会被移除

 

 

相关通配符:

 

 

通配符 含义
*匹配任意长度字符,但不含包名分隔符.。例如一个类的全包名路径是com.othershe.test.Person,使用com.othershe.test.*、com.othershe.test.*都是可以匹配的,但com.othershe.*就不能匹配
** 匹配任意长度字符,并包含包名分隔符.。例如要匹配com.othershe.test.**包下的所有内容
***

 匹配任意参数类型。例如*** getName(***)可匹配String getName(String)

... 匹配任意长度的任意类型参数。例如void setName(...)可匹配void setName(String firstName, String secondName)
<fileds>匹配类、接口中所有字段
<methods>匹配类、接口中所有方法
<init>匹配类中所有构造函数

 

到这里对混淆已经有了基本的了解,系统的proguard-android.txt已经为我们完成了大部分基础的混淆配置工作,至于编写当前app module下的proguard-rules.pro,只需要针对当前项目添加一些特有的配置,避免某些重要的东西被混淆掉导致错误,我们主要考虑以下几点:

 

  • 在AndroidManifest.xml中注册的继承四大组件的子类的类名以及重写的方法名都不会被混淆。

 

如果希望项目中android.support.v4.app.Fragment子类的类名和重写父类的方法名不被混淆可以添加如下配置:

# 不混淆Fragment的子类类名以及onCreate()、onCreateView()方法名
-keep public class * extends android.support.v4.app.Fragment {
    public void onCreate(android.os.Bundle);
    public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
}
  • 不混淆某个特定的类和类中所有成员

 

-keep class com.othershe.test.utils.CommonUtil { *; }

 

  • 不混淆某个目录下的文件,例如使用Gson时,数据bean不能被混淆,需要如下配置:

# com.othershe.test.model代表数据bean所在的全包名目录
-keep class com.othershe.test.model.** { *; }

 

  • 上一条的具体原因是因为Gson用到了反射。如果我们自己使用了反射,例如

Field field = service.getField("BASE_URL");

 

BASE_URL是service所属类的一个字段名,则该字段不能被混淆。

 

  • 保留泛型

-keepattributes Signature

 

  • 保留用于调试堆栈跟踪的行号信息(为了后期调试方便,建议配置)

-keepattributes SourceFile,LineNumberTable

 

  • 如果使用了上一行配置,还需要添加如下配置将源文件重命名为SourceFile,以便通过鼠标点击直达源文件:

-renamesourcefileattribute SourceFile

 

  • WebView中使用了JS调用,需要添加如下配置:

-keepclassmembers class fqcn.of.javascript.interface.for.webview {
   public *;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值