android 4.2 混淆,关于混淆,你需要知道的全部

本文详细介绍了ProGuard的配置规则,包括类、字段、方法和类型的通配符匹配,以及Android应用和库的典型配置示例。强调了反射处理、优化建议和注意事项,指出并非所有反射引用都需要显式保持,并提供了关于如何有效配置ProGuard以保留关键代码的指导。
摘要由CSDN通过智能技术生成

类名 通配符如下:

通配符

含义

?

匹配单个字符,包名分隔符(.)除外

*

匹配除(.)外的任意字符

**

匹配任意字符(包含.),如com.rush.**匹配com.rush包下的所有类及其所有子包的类。

字段和方法 通配符如下:

通配符

含义

匹配所有构造方法

匹配所有字段

匹配所有方法

?

匹配单个字符,包名分隔符(.)除外

*

匹配除(.)外的任意字符

类型 通配符如下:

通配符

含义

%

匹配原始类型,如int, boolean等

?

匹配任意单个字符

*

匹配除包名分隔符(.)外的任意字符

**

匹配任意字符,包括包名分隔符(.)

***

匹配任意类型(原始类型、非原始类型、数组或非数组类型)

匹配任意参数个数,任意参数类型

其中类配置完整定义如下,其中[]表示可选:

[ @annotationtype] [[!] public| final| abstract|@ ...] [!] interface|class|enumclassname

[extends|implements [ @annotationtype] classname]

[{

[ @annotationtype] [[!] public| private| protected|static| volatile| transient...] |

(fieldtype fieldname);

[ @annotationtype] [[!] public| private| protected|static|synchronized| native| abstract|strictfp ...] |

(argumenttype,...) |

classname(argumenttype,...) |

(returntype methodname(argumenttype,...));

[ @annotationtype] [[!] public| private| protected|static ... ] *;

...

}]

keep过于简单粗暴,proguard提供了6种不同的配置:

保留

防止被移除或重命名

防止被重命名(未使用的会被移除)

类和类成员

-keep

-keepnames

仅类成员

-keepclassmembers

-keepclassmembernames

如类含有某成员,保留类及其成员

-keepclasseswithmembers

-keepclasseswithmembernames

3

其它常用配置

-verbose

指定在混淆过程中输出更多信息,配置这个选项后,在遇到异常时,将输出完整的堆栈,而不仅仅是异常消息。

-dontnote [class_filter]

指定不输出潜在的错误或者遗漏,比如拼写错误或者缺失了有用的信息。class_filter是一个正则表达式,匹配到类将不输出这些信息。

-dontwarn [class_filter]

指定一组类,不警告这些类中找不到引用或其它重要的问题。这个选项是很危险的,比如,找不到引用的错误可能导致代码不能正常work。

(在引用一些存在警告的jar包,这个选项比较有用。)

-ignorewarnings

指定输出所以警告信息,但继续进行混淆。同上一选项,慎用。

-printconfiguration [filename]

指定输出整个过程中的所有配置,输出到标准输出流或者指定文件中。这有时候在调度配置时有用。

-dump [filename]

指定在任一处理过程后,输出class文件的结构,可以输出到标准输出流或者指定文件中。

4

proguard配置示例

4.1 Android默认推荐配置

在IDE自动生成的project.properties文件中,有这样一行:

#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

Android Studio默认生成的build.gradle文件有如下配置:

buildTypes{

release{

minifyEnabledfalse

proguardFiles getDefaultProguardFile( 'proguard-android.txt'), 'proguard-rules.pro'

}

}

其中getDefaultProguardFile('proguard-android.txt')获取的也是tools/proguard/proguard-android.txt。

下面看一下这个文件的配置:

# 不使用大小写混合类名

-dontusemixedcaseclassnames

# 不路过引用库中的非 public类

-dontskipnonpubliclibraryclasses

# 输出更多信息

-verbose

# 不进行优化

-dontoptimize

# 不进行预校验

-dontpreverify

# keep注解

-keepattributes *Annotation*

#keep google license服务接口

-keep publicclasscom.google.vending.licensing.ILicensingService

-keeppublicclasscom.android.vending.licensing.ILicensingService

# keepnative方法及其所属类

-keepclasseswithmembernamesclass* {

native ;

}

# keep自定义view的get/set方法

-keepclassmembers publicclass* extendsandroid.view.View{

voidset*(***);

*** get*();

}

# keep继续自Activity中所有包含public void *(android.view.View)签名的方法,如onClick

-keepclassmembers class* extendsandroid.app.Activity{

publicvoid*(android.view.View);

}

# keep枚举中的values和valueOf方法

-keepclassmembers enum* {

publicstatic**[] values();

publicstatic** valueOf(java.lang.String);

}

# keep Parcelable的CREATOR成员

-keepclassmembers class* implementsandroid.os.Parcelable{

publicstaticfinal android.os.Parcelable$Creator CREATOR;

}

# keep R文件的静态字段

-keepclassmembers class**.R$* {

publicstatic;

}

# 不输出support包中的警告

-dontwarn android.support.**

4.2 一个典型library库的配置

示例引用自官方文档samples

https://www.guardsquare.com/en/products/proguard/manual/examples#library

# 保存mapping映射文件到out. map

-printmapping out. map

# keep已keep方法的参数类型及参数名称

-keepparameternames

# 这个配置未弄清楚,待测试

-renamesourcefileattribute SourceFile

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,

SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

# keep所有类的protected成员

-keep publicclass* {

publicprotected*;

}

# keep在jdk 1.2中编译器插入的代码

-keepclassmembernames class* {

java.lang.Class class$(java.lang.String);

java.lang.Class class$(java.lang.String, boolean);

}

# keep native方法

-keepclasseswithmembernames,includedeorclasses class* {

native ;

}

# keep枚举中的values和valueOf方法

-keepclassmembers,allowoptimization enum* {

publicstatic**[] values();

publicstatic** valueOf(java.lang.String);

}

# keep系列化相关方法

-keepclassmembers class* implementsjava.io.Serializable{

staticfinal longserialVersionUID;

privatestaticfinal java.io.ObjectStreamField[] serialPersistentFields;

privatevoidwriteObject(java.io.ObjectOutputStream);

privatevoidreadObject(java.io.ObjectInputStream);

java.lang. Object writeReplace();

java.lang. Object readResolve();

}

4.3 一个典型Android App的配置

示例引用自官方文档samples

https://www.guardsquare.com/en/products/proguard/manual/examples#androidapplication

-dontpreverify

-repackageclasses ''

-allowaccessmodification

# 不优化算法指令

-optimizations !code/simplification/arithmetic

-keepattributes *Annotation*

# keep继承自系统组件的类

-keep public class* extendsandroid.app.Activity

-keep public class* extendsandroid.app.Application

-keep public class* extendsandroid.app.Service

-keep public class* extendsandroid.content.BroadcastReceiver

-keep public class* extendsandroid.content.ContentProvider

# keep自定义view及其构造方法、set方法

-keep public class* extendsandroid.view.View{

public (android.content.Context);

public (android.content.Context, android.util.AttributeSet);

public (android.content.Context, android.util.AttributeSet, int);

public void set*(...);

}

-keepclasseswithmembers class* {

public (android.content.Context, android.util.AttributeSet);

}

-keepclasseswithmembers class* {

public (android.content.Context, android.util.AttributeSet, int);

}

-keepclassmembers class* extendsandroid.content.Context{

public void *(android.view.View);

public void *(android.view.MenuItem);

}

-keepclassmembers class* implementsandroid.os.Parcelable{

static ** CREATOR;

}

-keepclassmembers class**.R$* {

public static ;

}

# keep java注释的方法,使用到webview js回调方法的需要添加此配置

-keepclassmembers class* {

@android.webkit.JavaInterface ;

}

5

关于反射

并不是所有会被反射引用的类都必须keep,在progurad过程中能直接分析到引用的类会被proguard做相应的处理:

# Class.forName的类名"SomeClass"被混淆后自动替换

Class.forName( "SomeClass")

SomeClass. class

# 以下字段和方法名都会在被混淆后自动替换

SomeClass. class.getField( "someField")

SomeClass. class.getDeclaredField( "someField")

SomeClass. class.getMethod( "someMethod", new Class[] {})

SomeClass. class.getMethod( "someMethod", new Class[] { A. class})

SomeClass. class.getMethod( "someMethod", new Class[] { A. class, B. class})

SomeClass. class.getDeclaredMethod( "someMethod", new Class[] {})

SomeClass. class.getDeclaredMethod( "someMethod", new Class[] { A. class})

SomeClass. class.getDeclaredMethod( "someMethod", new Class[] { A. class, B. class})

AtomicIntegerFieldUpdater.newUpdater(SomeClass. class, "someField")

AtomicLongFieldUpdater.newUpdater(SomeClass. class, "someField")

AtomicReferenceFieldUpdater.newUpdater(SomeClass. class, SomeType. class, "someField")

写个demo验证下:

Class> clazz = Class.forName( "com.rush.test.SimpleClass1");

clazz.getDeclaredMethod( "Test1");

SimpleClass2. class.getDeclaredField( "mTestField");

SimpleClass2. class.getDeclaredMethod( "Test2");

对以上代码编译并proguard,结果如下:

Class.forName(" com.rush.a.a") .getDeclaredMethod(" Test1", newClass[0]);

b.class.getDeclaredField(" a");

b.class.getDeclaredMethod(" a", newClass[0]);

通过Class.forName反射的class com.rush.test.SimpleClass1"被自动替换成了"com.rush.a.a";

但通过Class.forName获取的class再去反射方法没有正确处理;

通过完整class.getDeclaredField或者getDeclaredMethod反射时能够把字段名和方法名自动替换掉。

从结果看,反射并不是大家想像的那样必须keep,proguard能自动分析到引用的情况都能正确处理。但有些类是在配置文件里配置,或者动态拼接类名反射的,这些情况需要做好keep。

为了问题追踪的方便,建议所有会被反射引用的代码和library public接口都做好keep。

6

关于proguard配置的一些建议

所有会被反射引用的类都做好keep(建议,虽然有些反射能被正确处理)。 如native方法,四大组件,接口model,枚举,序列化类等。

只keep必须保留的内容,不要过度keep

使用热修复的App,添加-dontoptimize配置https://www.guardsquare.com/en/proguard/manual/introduction

https://www.guardsquare.com/en/proguard/manual/usage

https://www.guardsquare.com/en/proguard/manual/examples

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值