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

目录
相关文章
|
安全 Java Maven
关于代码混淆,看这篇就够了
关于代码混淆,看这篇就够了
2404 4
|
Ubuntu 异构计算 Windows
ModelScope问题之下载推荐的基础镜像失败如何解决
ModelScope镜像是指用于在ModelScope平台上创建和管理的容器镜像,这些镜像包含用于模型训练和推理的环境和依赖;本合集将说明如何使用ModelScope镜像以及管理镜像的技巧和注意事项。
683 0
|
Ubuntu 编译器 芯片
FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台
FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台
FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台
|
网络协议 Shell Linux
【Shell 命令集合 网络通讯 】Linux 设置和配置PPP pppsetup命令 使用教程
【Shell 命令集合 网络通讯 】Linux 设置和配置PPP pppsetup命令 使用教程
673 0
|
人工智能 算法 安全
OpenRouter 推出百万 token 上下文 AI 模型!Quasar Alpha:提供完全免费的 API 服务,同时支持联网搜索和多模态交互
Quasar Alpha 是 OpenRouter 推出的预发布 AI 模型,具备百万级 token 上下文处理能力,在代码生成、指令遵循和低延迟响应方面表现卓越,同时支持联网搜索和多模态交互。
1097 1
OpenRouter 推出百万 token 上下文 AI 模型!Quasar Alpha:提供完全免费的 API 服务,同时支持联网搜索和多模态交互
|
机器学习/深度学习 存储 算法
OD初始认识
OD初始认识
|
存储 人工智能 API
使用CAMEL框架和Qwen模型自动进行数据获取及报告与知识图谱生成
此笔记本演示如何设置和利用 CAMEL 的检索增强生成(RAG)结合 Milvus 进行高效的网页抓取、多智能体角色扮演任务和知识图谱构建。我们将通过一个使用 Qwen 模型对 2024 年巴黎奥运会的土耳其射手进行全面研究的例子来逐步演示。
1428 14
最通俗易懂的 JAVA slf4j,log4j,log4j2,logback 关系与区别以及完整集成案例
最通俗易懂的 JAVA slf4j,log4j,log4j2,logback 关系与区别以及完整集成案例
最通俗易懂的 JAVA slf4j,log4j,log4j2,logback 关系与区别以及完整集成案例
|
网络协议 Linux 虚拟化
CentOS 8 错误: Error setting up base repository
CentOS 8 错误: Error setting up base repository
1008 2
|
NoSQL MongoDB 数据库
深入探究MongoDB的ObjectId:唯一性、顺序性与应用指南
深入探究MongoDB的ObjectId:唯一性、顺序性与应用指南
1512 0