本篇文章:本身在混淆的时候整理出比较全面的混淆方法,比较实用,本身走过的坑,淌出来的路。请你们不要再走回头路,可能只要咱们代码加混淆,一点不对就会致使项目运行崩溃等后果,有许多人发现没有打包运行好好地,打包完成之后而又不不能够了,致使了许多困惑,本片文章来问你们解决困惑,但愿对你们有帮助。html
android{ buildTypes { release { buildConfigField "boolean", "LOG_DEBUG", "false" //不显示log minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.config } } }
由于开启混淆会使编译时间变长,因此debug模式下不开启。咱们须要作的是:
1.将release下minifyEnabled
的值改成true
,打开混淆;
2.加上shrinkResources true
,打开资源压缩。
3.buildConfigField
不显示log日志
4.signingConfig signingConfigs.config
配置签名文件文件java
自定义混淆方案适用于大部分的项目android
#指定压缩级别 -optimizationpasses 5 #不跳过非公共的库的类成员 -dontskipnonpubliclibraryclassmembers #混淆时采用的算法 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* #把混淆类中的方法名也混淆了 -useuniqueclassmembernames #优化时容许访问并修改有修饰符的类和类的成员 -allowaccessmodification #将文件来源重命名为“SourceFile”字符串 -renamesourcefileattribute SourceFile #保留行号 -keepattributes SourceFile,LineNumberTable #保持泛型 -keepattributes Signature #保持全部实现 Serializable 接口的类成员 -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(); } #Fragment不须要在AndroidManifest.xml中注册,须要额外保护下 -keep public class * extends android.support.v4.app.Fragment -keep public class * extends android.app.Fragment # 保持测试相关的代码 -dontnote junit.framework.** -dontnote junit.runner.** -dontwarn android.test.** -dontwarn android.support.test.** -dontwarn org.junit.**
真正通用的、须要添加的就是上面这些,除此以外,须要每一个项目根据自身的需求添加一些混淆规则:算法
第三方库所需的混淆规则。正规的第三方库通常都会在接入文档中写好所需混淆规则,使用时注意添加。json
-keep public class **.*Model*.** {*;}
JavaScript
调用的方法android:onClick
等。 <module-name>/build/outputs/mapping/release/
目录下会输出如下文件:dump.txt
mapping.txt
seeds.txt
usage.txt
seeds.txt
文件检查未被混淆的类和成员中是否已包含全部指望保留的,再根据 usage.txt
文件查看是否有被误移除的代码。<sdk-root>/tools/proguard/
路径下有附带的的反解工具(Window 系统为 proguardgui.bat
,Mac 或 Linux 系统为 proguardgui.sh
)。retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]
例如:api
retrace.bat -verbose mapping.txt obfuscated_trace.txt
AndroidManifest.xml
涉及到的类已经自动被保持,所以不用特地去添加这块混淆规则。(不少老的混淆文件里会加,如今已经不必)proguard-android.txt
已经存在一些默认混淆规则,不必在 proguard-rules.pro 重复添加Android中的“混淆”能够分为两部分,一部分是 Java
代码的优化与混淆,依靠 proguard
混淆器来实现;另外一部分是资源压缩,将移除项目及依赖的库中未被使用的资源(资源压缩严格意义上跟混淆没啥关系,但通常咱们都会放一块儿用)。安全
代码混淆是包含了代码压缩、优化、混淆等一系列行为的过程。如上图所示,混淆过程会有以下几个功能:app
压缩。移除无效的类、类成员、方法、属性等;
优化。分析和优化方法的二进制代码;根据proguard-android-optimize.txt
中的描述,优化可能会形成一些潜在风险,不能保证在全部版本的Dalvik上都正常运行。
混淆。把类名、属性名、方法名替换为简短且无心义的名称;
预校验。添加预校验信息。这个预校验是做用在Java平台上的,Android平台上不须要这项功能,去掉以后还能够加快混淆速度。
这四个流程默认开启。ide
在 Android
项目中咱们能够选择将“优化”和“预校验”关闭,对应命令是-dontoptimize、-dontpreverify
(固然,默认的 proguard-android.txt
文件已包含这两条混淆命令,不须要开发者额外配置)。函数
资源压缩将移除项目及依赖的库中未被使用的资源,这在减小 apk
包体积上会有不错的效果,通常建议开启。具体作法是在 build.grade
文件中,将 shrinkResources
属性设置为 true
。须要注意的是,只有在用minifyEnabled true
开启了代码压缩后,资源压缩才会生效。
资源压缩包含了“合并资源”和“移除资源”两个流程。
“合并资源”流程中,名称相同的资源被视为重复资源会被合并。须要注意的是,这一流程不受shrinkResources
属性控制,也没法被禁止, gradle
必然会作这项工做,由于假如不一样项目中存在相同名称的资源将致使错误。gradle
在四处地方寻找重复资源:
src/main/res/
路径
不一样的构建类型(debug
、release
等等)
不一样的构建渠道
项目依赖的第三方库
合并资源时按照以下优先级顺序
依赖 -> main -> 渠道 -> 构建类型
假如重复资源同时存在于main文件夹和不一样渠道中,gradle 会选择保留渠道中的资源。
同时,若是重复资源在同一层次出现,好比src/main/res/ 和 src/main/res2/
,则 gradle
没法完成资源合并,这时会报资源合并错误。
“移除资源”流程则见名知意,须要注意的是,相似代码,混淆资源移除也能够定义哪些资源须要被保留,这点在下文给出。
在上文“混淆配置”中有这样一行代码
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
这行代码定义了混淆规则由两部分构成:位于 SDK 的 tools/proguard/ 文件夹中的 proguard-android.txt 的内容以及默认放置于模块根目录的 proguard-rules.pro 的内容。前者是 SDK 提供的默认混淆文件,后者是开发者自定义混淆规则的地方。
更多详细的请到官网
命令 | 做用 | |
---|---|---|
-keep | 防止类和成员被移除或者被重命名 | |
-keepnames | 防止类和成员被重命名 | |
-keepclassmembers | 防止成员被移除或者被重命名 | |
-keepnames | 防止成员被重命名 | |
-keepclasseswithmembers | 防止拥有该成员的类和成员被移除或者被重命名 | |
-keepclasseswithmembernames | 防止拥有该成员的类和成员被重命名 |
[保持命令] [类] { [成员] }
举个例子,假如须要将com.biaobiao.test包下全部继承Activity的public类及其构造函数都保持住,能够这样写:
-keep public class com.biaobiao.test.** extends Android.app.Activity { <init> }
-keep public class com.biaobiao.example.Test { *; }
不混淆某个包全部的类
-keep class com.biaobiao.test.** { *; } }
不混淆某个类的子类
-keep public class * extends com.biaobiao.example.Test { *; }
不混淆全部类名中包含了“model”的类及其成员
-keep public class * extends com.biaobiao.example.Test { *; }
不混淆某个接口的实现
-keep class * implements com.biaobiao.example.TestInterface { *; }
不混淆某个类的构造方法
-keepclassmembers class com.biaobiao.example.Test { public <init>(); }
不混淆某个类的特定的方法
-keepclassmembers class com.biaobiao.example.Test { public void test(java.lang.String); } }
不混淆某个类的内部类
-keep class com.biaobiao.example.Test$* { *; }
用shrinkResources true
开启资源压缩后,全部未被使用的资源默认被移除。假如你须要定义哪些资源必须被保留,在 res/raw/
路径下建立一个 xml 文件,例如keep.xml
。
经过一些属性的设置能够实现定义资源保持的需求,可配置的属性有:
keep
定义哪些资源须要被保留(资源之间用“,”隔开)discard
定义哪些资源须要被移除(资源之间用“,”隔开)shrinkMode
开启严格模式 Resources.getIdentifier()
用动态的字符串来获取并使用资源时,普通的资源引用检查就可能会有问题。例如,以下代码会致使全部以“img_”开头的资源都被标记为已使用。当代码中经过 Resources.getIdentifier()
用动态的字符串来获取并使用资源时,普通的资源引用检查就可能会有问题。例如,以下代码会致使全部以“img_”开头的资源都被标记为已使用。
String name = String.format("img_%1d", angle + 1); res = getResources().getIdentifier(name, "drawable", getPackageName());
咱们能够设置 tools:shrinkMode
为 strict
来开启严格模式,使只有确实被使用的资源被保留。
以上就是自定义资源保持规则相关的配置,举个例子:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*" tools:discard="@layout/unused2" tools:shrinkMode="strict"/>
一些替代资源,例如多语言支持的 strings.xml,多分辨率支持的 layout.xml 等,在咱们不须要使用又不想删除掉时,可使用资源压缩将它们移除。
咱们使用 resConfig 属性来指定须要支持的属性,例如
一些替代资源,例如多语言支持的 strings.xml
,多分辨率支持的 layout.xml
等,在咱们不须要使用又不想删除掉时,可使用资源压缩将它们移除。
咱们使用 resConfig
属性来指定须要支持的属性,例如
android { defaultConfig { ... resConfigs "en", "fr" } }
其余未显式声明的语言资源将被移除。
proguard-android.txt
文件内容
# 代码混淆压缩比,在0~7之间 -optimizationpasses 5 # 混合时不使用大小写混合,混合后的类名为小写 -dontusemixedcaseclassnames # 指定不去忽略非公共库的类 -dontskipnonpubliclibraryclasses # 不作预校验,preverify是proguard的四个步骤之一,Android不须要preverify,去掉这一步可以加快混淆速度。 -dontpreverify -verbose # 避免混淆泛型 -keepattributes Signature # 保留Annotation不混淆 -keepattributes *Annotation*,InnerClasses #google推荐算法 -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* # 避免混淆Annotation、内部类、泛型、匿名类 -keepattributes *Annotation*,InnerClasses,Signature,EnclosingMethod # 重命名抛出异常时的文件名称 -renamesourcefileattribute SourceFile # 抛出异常时保留代码行号 -keepattributes SourceFile,LineNumberTable # 处理support包 -dontnote android.support.** -dontwarn android.support.** # 保留继承的 -keep public class * extends android.support.v4.** -keep public class * extends android.support.v7.** -keep public class * extends android.support.annotation.** # 保留R下面的资源 -keep class **.R$* {*;} # 保留四大组件,自定义的Application等这些类不被混淆 -keep public class * extends android.app.Activity -keep public class * extends android.app.Appliction -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.preference.Preference -keep public class com.android.vending.licensing.ILicensingService # 保留在Activity中的方法参数是view的方法, # 这样以来咱们在layout中写的onClick就不会被影响 -keepclassmembers class * extends android.app.Activity{ public void *(android.view.View); } # 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆 -keepclassmembers class * { void *(**On*Event); void *(**On*Listener); } # 保留本地native方法不被混淆 -keepclasseswithmembernames class * { native <methods>; } # 保留枚举类不被混淆 -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } # 保留Parcelable序列化类不被混淆 -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } -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(); } #assume no side effects:删除android.util.Log输出的日志 -assumenosideeffects class android.util.Log { public static *** v(...); public static *** d(...); public static *** i(...); public static *** w(...); public static *** e(...); } #保留Keep注解的类名和方法 -keep,allowobfuscation @interface android.support.annotation.Keep -keep @android.support.annotation.Keep class * -keepclassmembers class * { @android.support.annotation.Keep *; } #3D 地图 V5.0.0以前: -dontwarn com.amap.api.** -dontwarn com.autonavi.** -keep class com.amap.api.**{*;} -keep class com.autonavi.**{*;} -keep class com.amap.api.maps.**{*;} -keep class com.autonavi.amap.mapcore.*{*;} -keep class com.amap.api.trace.**{*;} #3D 地图 V5.0.0以后: -keep class com.amap.api.maps.**{*;} -keep class com.autonavi.**{*;} -keep class com.amap.api.trace.**{*;} #定位 -keep class com.amap.api.location.**{*;} -keep class com.amap.api.fence.**{*;} -keep class com.autonavi.aps.amapapi.model.**{*;} #搜索 -keep class com.amap.api.services.**{*;} #2D地图 -keep class com.amap.api.maps2d.**{*;} -keep class com.amap.api.mapcore2d.**{*;} #导航 -keep class com.amap.api.navi.**{*;} -keep class com.autonavi.**{*;} # Retain generic type information for use by reflection by converters and adapters. -keepattributes Signature # Retain service method parameters when optimizing. -keepclassmembers,allowshrinking,allowobfuscation interface * { @retrofit2.http.* <methods>; } # Ignore annotation used for build tooling. -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement # Ignore JSR 305 annotations for embedding nullability information. -dontwarn javax.annotation.** # JSR 305 annotations are for embedding nullability information. -dontwarn javax.annotation.** # A resource is loaded with a relative path so the package of this class must be preserved. -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. -dontwarn org.codehaus.mojo.animal_sniffer.* # OkHttp platform used only on JVM and when Conscrypt dependency is available. -dontwarn okhttp3.internal.platform.ConscryptPlatform #fastjson混淆 -keepattributes Signature -dontwarn com.alibaba.fastjson.** -keep class com.alibaba.**{*;} -keep class com.alibaba.fastjson.**{*; } -keep public class com.ninstarscf.ld.model.entity.**{*;}
全部文章参考