ProGuard的各种参数说明(2)

简介: ProGuard的各种参数说明(2)

四、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 {
            minifyEnabled false
            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 public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
# keep native方法及其所属类
-keepclasseswithmembernames class * {
    native <methods>;
}
# keep自定义view的get/set方法
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}
# keep继续自Activity中所有包含public void *(android.view.View)签名的方法,如onClick
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}
# keep枚举中的values和valueOf方法
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
# keep Parcelable的CREATOR成员
-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}
# keep R文件的静态字段
-keepclassmembers class **.R$* {
    public static <fields>;
}
# 不输出support包中的警告
-dontwarn android.support.**
4.2 一个典型library库的配置
示例引用自官方文档samples
# 保存mapping映射文件到out.map
-printmapping out.map 
# keep已keep方法的参数类型及参数名称
-keepparameternames 
# 这个配置未弄清楚,待测试
-renamesourcefileattribute SourceFile 
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
                SourceFile,LineNumberTable,*Annotation*,EnclosingMethod 
# keep所有类的protected成员
-keep public class * { 
      public protected *; 
} 
# keep在jdk 1.2中编译器插入的代码
-keepclassmembernames class * { 
    java.lang.Class class$(java.lang.String); 
    java.lang.Class class$(java.lang.String, boolean); 
} 
# keep native方法
-keepclasseswithmembernames,includedescriptorclasses class * { 
    native <methods>; 
} 
# keep枚举中的values和valueOf方法
-keepclassmembers,allowoptimization enum * { 
    public static **[] values(); 
    public static ** valueOf(java.lang.String); 
} 
# keep系列化相关方法
-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(); 
}

4.3 一个典型Android App的配置

示例引用自官方文档samples


-dontpreverify 
-repackageclasses '' 
-allowaccessmodification 
# 不优化算法指令
-optimizations !code/simplification/arithmetic 
-keepattributes *Annotation* 
# keep继承自系统组件的类
-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自定义view及其构造方法、set方法
-keep public class * extends android.view.View { 
      public <init>(android.content.Context); 
      public <init>(android.content.Context, android.util.AttributeSet); 
      public <init>(android.content.Context, android.util.AttributeSet, int); 
      public void set*(...); 
} 
-keepclasseswithmembers class * { 
    public <init>(android.content.Context, android.util.AttributeSet); 
} 
-keepclasseswithmembers class * { 
    public <init>(android.content.Context, android.util.AttributeSet, int); 
} 
-keepclassmembers class * extends android.content.Context { 
    public void *(android.view.View); 
    public void *(android.view.MenuItem); 
} 
-keepclassmembers class * implements android.os.Parcelable { 
    static ** CREATOR; 
} 
-keepclassmembers class **.R$* { 
    public static <fields>; 
} 
# keep javascript注释的方法,使用到webview js回调方法的需要添加此配置
-keepclassmembers class * { 
    @android.webkit.JavascriptInterface <methods>; 
}


五、关于反射

并不是所有会被反射引用的类都必须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", new Class[0]);
b.class.getDeclaredField("a");
b.class.getDeclaredMethod("a", new Class[0]);

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

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

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

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


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


六、关于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

目录
相关文章
|
5月前
|
存储 Java 编译器
.groovy后缀是什么文件
.groovy后缀是什么文件
95 0
|
5月前
|
Unix 编译器 开发工具
Cmake 命令行参数:探索 Cmake 的设置和配置选项
Cmake 命令行参数:探索 Cmake 的设置和配置选项
309 1
|
5月前
好用的 自定义Makefile文件
好用的 自定义Makefile文件
29 0
|
算法 IDE Java
ProGuard的各种参数说明(1)
ProGuard的各种参数说明(1)
634 0
ProGuard:保留包名,混淆类
ProGuard:保留包名,混淆类
223 0
C#编程:通过文件路径获取文件名
C#编程:通过文件路径获取文件名
335 0
|
安全 Android开发 数据安全/隐私保护
【Android 安全】DEX 加密 ( Proguard 混淆 | 混淆后的报错信息 | Proguard 混淆映射文件 mapping.txt )
【Android 安全】DEX 加密 ( Proguard 混淆 | 混淆后的报错信息 | Proguard 混淆映射文件 mapping.txt )
288 0
【Android 安全】DEX 加密 ( Proguard 混淆 | 混淆后的报错信息 | Proguard 混淆映射文件 mapping.txt )
|
缓存 C语言 iOS开发
获取文件路径
获取文件路径
164 0
|
Android开发
ProGuard中keep到底有什么作用
一直以为keep就是不要混淆,近期发现还有另外一个作用
378 0
Qt .pro文件之defineReplace函数的用法,实现lib文件名自动添加后缀“d“
Qt .pro文件之defineReplace函数的用法,实现lib文件名自动添加后缀“d“
579 0