宁波网站制作公司官网,漂亮的网页设计欣赏,大淘客怎样做网站,有经验的做网站关于作者#xff1a;CSDN内容合伙人、技术专家#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 #xff0c;擅长java后端、移动开发、人工智能等#xff0c;希望大家多多支持。 目录 一、导读二、概览三、语法规则3.1 输入/输出选项3.2 保留选项3.3 缩… 关于作者CSDN内容合伙人、技术专家 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 擅长java后端、移动开发、人工智能等希望大家多多支持。 目录 一、导读二、概览三、语法规则3.1 输入/输出选项3.2 保留选项3.3 缩小选项3.4 优化选项3.5 混淆选项3.6 预验证选项3.7 常规选项 四、过滤器4.1 增量混淆4.2 寻找未使用的代码及方法等废弃代码 五、混淆基本原则5.1 系统相关类不要混淆5.2 部分项目相关类不要混淆5.3、添加混淆字典5.4 r8 proguard 六、 推荐阅读 一、导读
我们继续总结学习基础知识温故知新。 本文讲述Android Proguard 相关知识。
二、概览
Proguard 四部曲 shrink删减删减无用代码包括类、变量、方法和属性缩减了APK包的大小
optimize优化优化方法字节码并移除无用的构造方法
obfuscate混淆混淆现有代码将有意义的命名替换为无意义的命名
preverify预校验给类添加预校验信息这是J2ME和Java 6及以上要求的
proguard 文档
三、语法规则
3.1 输入/输出选项 filename“文件名”的缩写 ‘-include filename’. -include filename从给定文件filename递归读取配置选项 -basedirectory directoryname指定这些配置参数或此配置文件中所有后续相对文件名的基目录 -injars class_path指定要处理的应用程序的输入 jar或 apks、aabs、aars、wars、ears、jmods、zip 或目录。 可以使用多个-injars选项指定类路径条目。
-outjars class_path指定输出 jar 的名称或 apks、aabs、aars、wars、ears、jmods、zips 或目录。 为了更好的可读性可以使用多个-outjars选项指定类路径条目。如果没有任何-outjars选项则不会编写任何 jars
-libraryjars class_path指定要处理的应用程序的库 jar或 apks、aabs、aars、wars、ears、jmods、zips、目录
-skipnonpubliclibraryclasses指定在读取库 jar 时跳过非公共类以加快处理速度并减少 ProGuard 的内存使用量
-dontskipnonpubliclibraryclasses指定不忽略非公共库类。从版本 4.5 开始这是默认设置
-dontskipnonpubliclibraryclassmembers指定不忽略包可见的库类成员字段和方法
-keepdirectories [directory_filter]指定要保留在输出 jar 中的目录或 apks、aabs、aars、wars、ears、jmods、zips 或目录
-target version已弃用此选项仅适用于 Java 类文件版本 11
-forceprocessing指定处理输入即使输出看起来是最新的
3.2 保留选项 -keep [,modifier,...] class_specification
-keepnames class_specification
指定要保留为代码入口点的类和类成员字段和方法-keepclassmembers [,modifier,...] class_specification
-keepclassmembernames class_specification
指定要保留的类成员如果它们的类也被保留-keepclasseswithmembers [,modifier,...] class_specification
-keepclasseswithmembernames class_specification
指定要保留的类和类成员前提是所有指定的类成员都存在-if class_specification指定必须present激活后续保留选项-keep、-keepclassmembers、…的类和类成员。 条件和后续的 keep 选项可以共享通配符和对通配符的引用。例如您可以使用Dagger和Butterknife等框架保留类前提是项目中存在具有相关名称的类。
-printseeds [filename]指定详尽列出与各种-keep选项匹配的类和类成员。该列表将打印到标准输出或给定文件。该列表可用于验证是否确实找到了预期的类成员 特别是在您使用通配符时。例如您可能想要列出您保留的所有应用程序或所有小程序。
3.3 缩小选项
-dontshrink指定不收缩输入。默认情况下ProGuard 会缩小代码它会删除所有未使用的类和类成员。它只保留各种-keep选项列出的选项以及它们直接或间接依赖的选项。 它还在每个优化步骤之后应用收缩步骤因为某些优化可能会提供删除更多类和类成员的可能性。
-printusage [filename]指定列出输入类文件的死代码。该列表将打印到标准输出或给定文件。例如您可以列出应用程序未使用的代码。仅适用于收缩时。
-whyareyoukeeping class_specification指定打印有关为何给定类和类成员保留在收缩步骤中的详细信息。如果您想知道为什么某些给定元素出现在输出中这可能很有用。
3.4 优化选项
-dontoptimize指定不优化输入类文件。默认情况下ProGuard 会优化所有代码。它内联和合并类和类成员并在字节码级别优化所有方法。
-optimizations optimization_filter以更细粒度的级别指定要启用和禁用的优化。仅适用于优化时 例如
# 指定混淆是采用的算法后面的参数是一个过滤器
# 这个过滤器是谷歌推荐的算法一般不做更改
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*-optimizationpasses n指定代码的压缩级别 0 - 7(指定代码进行迭代优化的次数在Android里面默认是5这条指令也只有在可以优化时起作用。)
-assumenosideeffects class_specification指定除了可能返回值之外没有任何副作用的方法。例如该方法System.currentTimeMillis()返回一个值但它没有任何副作用。 在优化步骤中如果 ProGuard 可以确定未使用返回值则可以删除对此类方法的调用。ProGuard 会分析您的程序代码以自动查找此类方法。 它不会分析库代码因此此选项很有用。例如您可以指定 method System.currentTimeMillis()以便删除对其的任何空闲调用。如果小心的话 您还可以使用该选项来删除日志记录代码。请注意ProGuard 将该选项应用于指定方法的整个层次结构。仅适用于优化时。一般来说做出假设可能是危险的。 您可以轻松地破坏已处理的代码。仅当您知道自己在做什么时才使用此选项
-assumenoexternalsideeffects class_specification
-assumenoescapingparameters class_specification
-assumenoexternalreturnvalues class_specification
-assumevalues class_specification
-allowaccessmodification
-mergeinterfacesaggressively
-optimizeaggressively代码优化相关用不好容易出问题。
3.5 混淆选项
-dontobfuscate指定不混淆输入类文件。默认情况下ProGuard 会混淆代码它为类和类成员分配新的短随机名称。它删除了仅对调试有用的内部属性例如源文件名、变量名和行号。
-printmapping [filename]指定打印已重命名的类和类成员从旧名称到新名称的映射。映射被打印到标准输出或给定文件。例如后续增量混淆需要它或者如果您想再次理解混淆的堆栈跟踪。仅在混淆时适用。
-applymapping filename指定重用在 ProGuard 的先前混淆运行中打印出的给定名称映射。映射文件中列出的类和类成员接收与其一起指定的名称。未提及的类和类成员将获得新名称。 该映射可以引用输入类以及库类。此选项对于增量混淆非常有用即处理现有代码片段的附加组件或小补丁。如果代码结构发生根本性变化ProGuard 可能会打印出应用映射导致冲突的警告。 您可以通过-useuniqueclassmembernames在两次混淆运行中指定该选项来降低这种风险。只允许使用单个映射文件。仅在混淆时适用。
-obfuscationdictionary proguard-dic.txt //指定一个字典文件作为混淆字典
-classobfuscationdictionary proguard-dic.txt //类字典
-packageobfuscationdictionary proguard-dic.txt //包字典-overloadaggressively指定在混淆时应用积极的重载。然后多个字段和方法可以获得相同的名称只要它们的参数和返回类型不同如 Java 字节码所要求的不仅仅是它们的参数如 Java 语言所要求的。 此选项可以使处理后的代码更小并且更难以理解大小体积。仅在混淆时适用。
但是可能存在问题如Google 的 Dalvik VM 无法处理过载的静态字段。
-useuniqueclassmembernames指定将相同的混淆名称分配给具有相同名称的类成员并将不同的混淆名称分配给具有不同名称的类成员对于每个给定的类成员签名。如果没有该选项更多的类成员可以映射到相同的短名称如“a”、“b”等。因此 该选项会稍微增加结果代码的大小但它确保保存的混淆名称映射始终可以在后续增量混淆步骤中受到尊重
-dontusemixedcaseclassnames指定在混淆时不生成大小写混合的类名。默认情况下混淆的类名可以包含大写字符和小写字符的混合。
-keeppackagenames [package_filter]指定不混淆给定的包名称。
-flattenpackagehierarchy [package_name]指定通过将重命名的所有包移动到单个给定父包中来重新打包它们。如果不带参数或使用空字符串 (‘’)包将移至根包中。此选项是进一步混淆包名称的示例之一。它可以使处理后的代码更小且更难以理解大小体积。仅在混淆时适用。
与 repackageclasses 冲突
-repackageclasses [package_name]指定通过将重命名的所有类文件移动到单个给定包中来重新打包它们。如果没有参数或使用空字符串 (‘’)则包将被完全删除。该选项会覆盖该-flattenpackagehierarchy选项。这是进一步混淆包名称的另一个例子。 它可以使处理后的代码变得更小并且更难以理解大小体积。它的已弃用名称是-defaultpackage. 仅在混淆时适用。
-keepattributes [attribute_filter]指定要保留的任何可选属性。可以使用一个或多个指令来指定属性-keepattributes
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
# 保护代码中的Annotation不被混淆
-keepattributes *Annotation*
# 避免混淆泛型, 这在JSON实体映射时非常重要
-keepattributes Signature-keepparameternames指定保留所保留方法的参数名称和类型。该选项实际上保留了调试属性LocalVariableTable和LocalVariableTypeTable
-renamesourcefileattribute [string]指定要放入类文件的SourceFile属性和属性中的常量字符串。SourceDir请注意该属性必须首先存在因此还必须使用-keepattributes指令显式保留它。 例如您可能希望让经过处理的库和应用程序生成有用的模糊堆栈跟踪。仅在混淆时适用。
-keepkotlinmetadata已弃用使用-keep class kotlin.Metadata替代。指定处理kotlin.Metadata注释如果存在。目前仅支持对其内容进行缩小和混淆。如果启用此选项则应从优化中排除包含此类注释的类。
-adaptclassstrings [class_filter]指定与类名相对应的字符串常量也应该被混淆。如果没有过滤器所有与类名相对应的字符串常量都会被调整。
-adaptresourcefilenames [file_filter]根据相应类文件如果有的混淆名称指定要重命名的资源文件。如果没有过滤器则与类文件对应的所有资源文件都会被重命名。
-adaptresourcefilecontents [file_filter]指定要更新内容的资源文件和本机库。资源文件中提到的任何类名都会根据相应类如果有的混淆名称进行重命名。
3.6 预验证选项
-dontpreverify指定不对已处理的类文件进行预验证。
-microedition指定处理的类文件针对 Java Micro Edition。
-android指定处理的类文件是针对Android平台的
3.7 常规选项
-verbose指定在处理过程中写出更多信息。如果程序因异常而终止此选项将打印出整个堆栈跟踪而不仅仅是异常消息。
-dontnote [class_filter]指定不打印有关配置中潜在错误或遗漏的注释例如类名称中的拼写错误或缺少可能有用的选项。可选的过滤器是正则表达式ProGuard 不会打印有关具有匹配名称的类的注释。
-dontwarn [class_filter]指定根本不警告未解决的引用和其他重要问题。可选的过滤器是正则表达式ProGuard 不会打印有关具有匹配名称的类的警告。忽视警告可能会很危险。
-ignorewarnings指定打印有关未解决的引用和其他重要问题的任何警告但在任何情况下都继续处理。忽视警告可能会很危险。屏蔽警告
-printconfiguration [filename]指定写出已解析的整个配置包括包含的文件和替换的变量。该结构被打印到标准输出或给定文件。
-dump [filename]指定在任何处理之后写出类文件的内部结构。该结构被打印到标准输出或给定文件。
-addconfigurationdebugging指定使用调试语句来检测已处理的代码这些调试语句会打印出缺少 ProGuard 配置的建议。
四、过滤器
? 匹配名称中的任何 单个 字符。 例如“ com.example.Test?”匹配“ com.example.Test1”和“ com.example.Test2”但不匹配“ com.example.Test12”。* 匹配名称中不包含包分隔符或目录分隔符的任何部分。
例如“ com.example.*Test*”匹配“ com.example.Test”和“ com.example.YourTestApplication”但不匹配“ com.example.mysubpackage.MyTest”。
或者更一般地说“ com.example.*”匹配“ com.example”中的所有类但不匹配其子包中的所有类。** 匹配名称的任何部分可能包含任意数量的包分隔符或目录分隔符。n 匹配同一选项中第n个匹配的通配符。例如“ com.example.*Foo1”匹配“ com.example.BarFooBar”。例如“ java/**.class,javax/**.class”匹配 和 中的所有类java文件javax。此外文件名前面可以有感叹号“ ” 从进一步尝试与后续文件名匹配中排除该文件名。例如“ !**.gif,images/**”匹配images目录中除 gif 文件之外的所有文件。忽略输入 jar 中的某些文件images此配置会删除该目录及其子目录中的所有文件。
-injars in.jar(!images/**)
-outjars out.jar仅保留第一个输入 jar 中的清单文件
-injars in1.jar
-injars in2.jar(!META-INF/MANIFEST.MF)
-injars in3.jar(!META-INF/MANIFEST.MF)
-outjars out.jar例如“ foo,*bar”匹配名称foo以及所有以 结尾的名称bar。init 匹配任何构造函数。
fields 匹配任何字段。
methods 匹配任何方法。
* 匹配任何字段或方法。通配符 意义
% 匹配任何原始类型 boolean、 int 等或 void 类型。
? 匹配类名中的任何单个字符。
* 匹配类名中不包含包分隔符的任何部分。
** 匹配类名的任何部分可能包含任意数量的包分隔符。
*** 匹配任何类型原始或非原始、数组或非数组。
... 匹配任意数量任意类型的参数。
n 匹配同一选项中第n个匹配的通配符。请注意?、 和通配符永远不会匹配原始类型。此外只有通配符才能匹配任何维度的数组类型。例如“ ** get*()”匹配“ java.lang.Object getObject()” 但不匹配“ float getFloat()”也不匹配“ java.lang.Object[] getObjects()”。
4.1 增量混淆
-injars proguardgui.jar
-outjars proguardgui_out.jar
-injars proguard.jar
-outjars proguard_out.jar
-libraryjars java.home/jmods/java.base.jmod(!**.jar;!module-info.class)
-applymapping proguard.map-keep public class proguard.gui.ProGuardGUI {public static void main(java.lang.String[]);
}4.2 寻找未使用的代码及方法等废弃代码 #不进行优化建议使用此选项
-dontoptimize
#指定不混淆输入类文件。默认情况下ProGuard 会混淆代码它为类和类成员分配新的短随机名称。它删除了仅对调试有用的内部属性例如源文件名、变量名和行号。
-dontobfuscate# 不进行预校验,Android不需要,可加快混淆速度。
-dontpreverify
#指定列出输入类文件的死代码。该列表将打印到标准输出或给定文件。例如您可以列出应用程序未使用的代码。仅适用于收缩时。
-printusage
点击build后可以看到如下的输出列出了几个没有使用到的类及方法 Task :app:minifyReleaseWithR8
org.fmod.example.CallBack
org.fmod.example.CallBackManager
org.fmod.example.DeadClass
org.fmod.example.MemoryShakeActivity:public void dpOperate()public void testa()public void testb()
org.fmod.example.BuildConfig
org.fmod.example.R$color
org.fmod.example.R$drawable
org.fmod.example.R$id
org.fmod.example.R$layout
org.fmod.example.R$mipmap
org.fmod.example.R$string
org.fmod.example.R$style
org.fmod.example.R$xml
org.fmod.example.R
org.fmod.example.databinding.ActivityMemoryBinding:public final android.widget.Button btMemoryprivate void init(android.widget.FrameLayout,android.widget.Button)public static org.fmod.example.databinding.ActivityMemoryBinding bind(android.view.View)public static org.fmod.example.databinding.ActivityMemoryBinding inflate(android.view.LayoutInflater)public static org.fmod.example.databinding.ActivityMemoryBinding inflate(android.view.LayoutInflater,android.view.ViewGroup,boolean)
androidx.core.location.LocationManagerCompat$$InternalSyntheticLambda$1$196e0315f48caa68131c5d4d780ff53e9618a06658f902ea94f753d0df163305$1
androidx.core.location.LocationManagerCompat:public static synthetic java.lang.Boolean $r8$lambda$JLIcm4BkQpukCiUbhX4BKZUICt4(android.location.LocationManager,androidx.core.location.LocationManagerCompat$GpsStatusTransport)#不进行优化建议使用此选项
-dontoptimize
#指定不混淆输入类文件。默认情况下ProGuard 会混淆代码它为类和类成员分配新的短随机名称。它删除了仅对调试有用的内部属性例如源文件名、变量名和行号。
-dontobfuscate# 不进行预校验,Android不需要,可加快混淆速度。
-dontpreverify
#指定列出输入类文件的死代码。该列表将打印到标准输出或给定文件。例如您可以列出应用程序未使用的代码。仅适用于收缩时。
-printusage-keep public class org.fmod.example.DeadClass {public static void main(java.lang.String[]);
}如果我们将某一个未使用的class 进行keep则结果如下 Task :app:minifyReleaseWithR8
org.fmod.example.BuildConfig
org.fmod.example.CallBack
org.fmod.example.CallBackManager
org.fmod.example.DeadClass:public void testa()public void testb()public void testc()
org.fmod.example.MemoryShakeActivity:public void dpOperate()public void testa()public void testb()
org.fmod.example.R$color
org.fmod.example.R$drawable
org.fmod.example.R$id
org.fmod.example.R$layout
org.fmod.example.R$mipmap
org.fmod.example.R$string
org.fmod.example.R$style
org.fmod.example.R$xml
org.fmod.example.R
org.fmod.example.databinding.ActivityMemoryBinding:public final android.widget.Button btMemoryprivate void init(android.widget.FrameLayout,android.widget.Button)public static org.fmod.example.databinding.ActivityMemoryBinding bind(android.view.View)public static org.fmod.example.databinding.ActivityMemoryBinding inflate(android.view.LayoutInflater)public static org.fmod.example.databinding.ActivityMemoryBinding inflate(android.view.LayoutInflater,android.view.ViewGroup,boolean)
androidx.core.location.LocationManagerCompat$$InternalSyntheticLambda$1$196e0315f48caa68131c5d4d780ff53e9618a06658f902ea94f753d0df163305$1
androidx.core.location.LocationManagerCompat:public static synthetic java.lang.Boolean $r8$lambda$JLIcm4BkQpukCiUbhX4BKZUICt4(android.location.LocationManager,androidx.core.location.LocationManagerCompat$GpsStatusTransport)五、混淆基本原则
项目中以下类不应该混淆
5.1 系统相关类不要混淆
四大组件如 Activity、Service、Provider、Broadcast及其Fragment等系统相关类
#继承activity,application,service,broadcastReceiver,contentprovider....不进行混淆
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.support.multidex.MultiDexApplication
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends androidx.fragment.app.Fragment
-keep public class * extends android.content.ContentProvider
view(WebView)相关类
-keepclassmembers class * extends android.app.Activity{public void *(android.view.View);
}
#不混淆任何一个View中的setXxx()和getXxx()方法
#因为属性动画需要有相应的setter和getter的方法实现
-keep public class * extends android.view.View{*** get*();void set*(***);public init(android.content.Context);public init(android.content.Context, android.util.AttributeSet);public init(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {public init(android.content.Context, android.util.AttributeSet);public init(android.content.Context, android.util.AttributeSet, int);
}枚举类
#不混淆枚举中的values()和valueOf()方法
-keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);
}注解support下的所有类及其内部类 -keep class android.support.** {*;}## 保留support下的所有类及其内部类
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**Serializable
# 继承Serizalizable的类的如下成员不被移除混淆
-keepclassmembers class * implements java.io.Serializable {java.lang.Object writeReplace();java.lang.Object readResolve();static final long serialVersionUID;private static final java.io.ObjectStreamField[] serialPersistentFields;private void writeObject(java.io.ObjectOutputStream);private void readObject(java.io.ObjectInputStream);
}Parcelable的子类和Creator静态成员变量 #不混淆Parcelable实现类中的CREATOR字段
-keep class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator *;
}5.2 部分项目相关类不要混淆
数据模型各种数据模型类GSON、fastjson等框架解析服务端数据时混淆后解析不了
-keep class com.xxx.entity.** {*;}Jni接口和java的native方法 这个方法需要和native方法保持一致混淆后找不到会报错
-keepclasseswithmembernames class * {native methods;
}Java接口 主要针对对外开放的接口 调用反射的地方 抽象内部类 比如Animal的内部类不混淆
-keep class com.xxx.demo.Animal{*;}
-keep class com.xxx.demo.Animal$*{*;}使用到的第三方开源库或者引用其他第三方的SDK包
# 微信支付
-keep class com.tencent.mm.opensdk.** {*; }AOP或者读取路径等的地方
整理了一个基础混淆文件 Android通用混淆文件
5.3、添加混淆字典
为了是混淆更混乱可以添加自定义的混淆字典 -classobfuscationdictionary proguard-dic.txt //类字典 -obfuscationdictionary proguard-dic.txt //混淆字典 -packageobfuscationdictionary proguard-dic.txt //包字典
混淆字典下载地址
5.4 r8 proguard
如果不想用R8想用回ProGuard的话可以在gradle.properties文件中添加下述配置禁用R8
android.enableR8falseandroid.enableR8.librariesfalseAndroid在打包后一般会有以下几个文件 mapping.txt、usage.txt 等
mapping.txt→ 原始与混淆过的类、方法、字段名称间的转换关系seeds.txt→ 未进行混淆的类与成员usage.txt→ APK中移除的代码即废弃代码configuration.txt→ missing_rules.txtresources.txt→ 资源优化记录文件哪些资源引用了其他资源哪些资源在使用哪些资源被移除参考
proguard 文档
六、 推荐阅读
Java 专栏
SQL 专栏
数据结构与算法
Android学习专栏
未经允许不得转载