当前位置:   article > 正文

Android 代码混淆

android 代码混淆

Android混淆最佳实践

1. 混淆配置

因为开启混淆会使编译时间变长,所以debug模式下不开启。我们需要做的是:
1.将release下minifyEnabled的值改为true,打开混淆;
2.加上shrinkResources true,打开资源压缩。
3.buildConfigField 不显示log日志
4.signingConfig signingConfigs.config配置签名文件文件

自定义混淆规则

自定义混淆方案适用于大部分的项目

  1. android{
  2. buildTypes {
  3. release {
  4. buildConfigField "boolean", "LOG_DEBUG", "false" //不显示log
  5. minifyEnabled true
  6. shrinkResources true
  7. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  8. signingConfig signingConfigs.config
  9. }
  10. }
  11. }

or

  1. buildTypes {
  2. debug {
  3. minifyEnabled false // 混淆
  4. zipAlignEnabled true // Zipalign优化
  5. shrinkResources true // 移除无用的resource文件
  6. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // 加载默认混淆配置文件
  7. signingConfig signingConfigs.debug // 签名
  8. }
  9. release {
  10. minifyEnabled true // 混淆
  11. zipAlignEnabled true // Zipalign优化
  12. shrinkResources true // 移除无用的resource文件
  13. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // 加载默认混淆配置文件
  14. signingConfig signingConfigs.relealse // 签名
  15. }
  16. }

2. 混淆规则

混淆会用无意义的短变量去重命名类、变量、方法,但是对于外部的一些引用是通过名字找到对应的方法和类。混淆过后通过原来的名字去找混淆后的名字,是找不到对应方法和类,就会出异常报错。所以有些情况是不能进行混淆的。

  • 自定义控件不进行混淆
  • 枚举类不被混淆
  • 反射类不进行混淆
  • 实体类不被混淆
  • JS调用的Java方法
  • 四大组件不进行混淆
  • JNI中调用类不进行混淆
  • Layout布局使用的View构造函数、android:onClick等
  • Parcelable 的子类和 Creator 静态成员变量不混淆
  • 第三方开源库或者引用其他第三方的SDK包不进行混淆

 

3. 混淆模板

1)基本指令

  1. # 设置混淆的压缩比率 0 ~ 7
  2. -optimizationpasses 5
  3. # 混淆时不使用大小写混合,混淆后的类名为小写
  4. -dontusemixedcaseclassnames
  5. # 指定不去忽略非公共库的类
  6. -dontskipnonpubliclibraryclasses
  7. # 指定不去忽略非公共库的成员
  8. -dontskipnonpubliclibraryclassmembers
  9. # 混淆时不做预校验
  10. -dontpreverify
  11. # 混淆时不记录日志
  12. -verbose
  13. # 忽略警告
  14. -ignorewarning
  15. # 代码优化
  16. -dontshrink
  17. # 不优化输入的类文件
  18. -dontoptimize
  19. # 保留注解不混淆
  20. -keepattributes *Annotation*,InnerClasses
  21. # 避免混淆泛型
  22. -keepattributes Signature
  23. # 保留代码行号,方便异常信息的追踪
  24. -keepattributes SourceFile,LineNumberTable
  25. # 混淆采用的算法
  26. -optimizations !code/simplification/cast,!field/*,!class/merging/*
  27. # dump.txt文件列出apk包内所有class的内部结构
  28. -dump class_files.txt
  29. # seeds.txt文件列出未混淆的类和成员
  30. -printseeds seeds.txt
  31. # usage.txt文件列出从apk中删除的代码
  32. -printusage unused.txt
  33. # mapping.txt文件列出混淆前后的映射
  34. -printmapping mapping.txt

2)不需混淆的Android类

  1. -keep public class * extends android.app.Fragment
  2. -keep public class * extends android.app.Activity
  3. -keep public class * extends android.app.Application
  4. -keep public class * extends android.app.Service
  5. -keep public class * extends android.content.BroadcastReceiver
  6. -keep public class * extends android.preference.Preference
  7. -keep public class * extends android.content.ContentProvider
  8. -keep public class * extends android.support.v4.**
  9. -keep public class * extends android.support.annotation.**
  10. -keep public class * extends android.support.v7.**
  11. -keep public class * extends android.app.backup.BackupAgentHelper
  12. -keep public class * extends android.preference.Preference
  13. -keep public class * extends android.view.View
  14. -keep public class com.android.vending.licensing.ILicensingService
  15. -keep class android.support.** {*;}

3)support-v4包

  1. -dontwarn android.support.v4.**
  2. -keep class android.support.v4.app.** { *; }
  3. -keep interface android.support.v4.app.** { *; }
  4. -keep class android.support.v4.** { *; }

4)support-v7包 

  1. -dontwarn android.support.v7.**
  2. -keep class android.support.v7.internal.** { *; }
  3. -keep interface android.support.v7.internal.** { *; }
  4. -keep class android.support.v7.** { *; }

5)support design

  1. -dontwarn android.support.design.**
  2. -keep class android.support.design.** { *; }
  3. -keep interface android.support.design.** { *; }
  4. -keep public class android.support.design.R$* { *; }

6)避免混淆自定义控件类的 get/set 方法和构造函数

  1. -keep public class * extends android.view.View{
  2. *** get*();
  3. void set*(***);
  4. public <init>(android.content.Context);
  5. public <init>(android.content.Context, android.util.AttributeSet);
  6. public <init>(android.content.Context, android.util.AttributeSet, int);
  7. }

7)关闭 Log日志

  1. -assumenosideeffects class android.util.Log {
  2. public static boolean isLoggable(java.lang.String, int);
  3. public static int v(...);
  4. public static int i(...);
  5. public static int w(...);
  6. public static int d(...);
  7. public static int e(...);
  8. }

-dontoptimize不要配置,不然将会关闭优化,导致日志语句不会被优化掉。

8)避免资源混淆

-keep class **.R$* {*;}

9)避免layout中onclick方法(android:οnclick="onClick")混淆

  1. -keepclassmembers class * extends android.app.Activity{
  2. public void *(android.view.View);
  3. }

10)避免回调函数 onXXEvent 混淆

  1. -keepclassmembers class * {
  2. void *(*Event);
  3. }

11)避免混淆枚举类

  1. -keepclassmembers enum * {
  2. public static **[] values();
  3. public static ** valueOf(java.lang.String);
  4. }

12)Natvie 方法不混淆

  1. -keepclasseswithmembernames class * {
  2. native <methods>;
  3. }

13)避免Parcelable混淆

  1. -keep class * implements android.os.Parcelable {
  2. public static final android.os.Parcelable$Creator *;
  3. }

14)避免Serializable接口的子类中指定的某些成员变量和方法混淆

  1. -keepclassmembers class * implements java.io.Serializable {
  2. static final long serialVersionUID;
  3. private static final java.io.ObjectStreamField[] serialPersistentFields;
  4. !static !transient <fields>;
  5. private void writeObject(java.io.ObjectOutputStream);
  6. private void readObject(java.io.ObjectInputStream);
  7. java.lang.Object writeReplace();
  8. java.lang.Object readResolve();
  9. }

15)WebView混淆配置

  1. -keepclassmembers class fqcn.of.javascript.interface.for.webview {
  2. public *;
  3. }
  4. -keepclassmembers class * extends android.webkit.webViewClient {
  5. public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
  6. public boolean *(android.webkit.WebView, java.lang.String);
  7. }
  8. -keepclassmembers class * extends android.webkit.webViewClient {
  9. public void *(android.webkit.webView, jav.lang.String);
  10. }

16)ButterKnife混淆配置

  1. -keep class butterknife.** { *; }
  2. -dontwarn butterknife.internal.**
  3. -keep class **$$ViewBinder { *; }
  4. -keepclasseswithmembernames class * {
  5. @butterknife.* <fields>;
  6. }
  7. -keepclasseswithmembernames class * {
  8. @butterknife.* <methods>;
  9. }

17)OkHttp3混淆配置

  1. -dontwarn com.squareup.okhttp3.**
  2. -keep class com.squareup.okhttp3.** { *;}
  3. -dontwarn okio.**

18)Retrofit2混淆配置

  1. -dontwarn retrofit2.**
  2. -keep class retrofit2.** { *; }
  3. -keepattributes Signature
  4. -keepattributes Exceptions

19)RxJava、RxAndroid混淆配置

  1. -dontwarn sun.misc.**
  2. -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
  3. long producerIndex;
  4. long consumerIndex;
  5. }
  6. -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
  7. rx.internal.util.atomic.LinkedQueueNode producerNode;
  8. }
  9. -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
  10. rx.internal.util.atomic.LinkedQueueNode consumerNode;
  11. }

20)Glide混淆配置

  • Glide 3
  1. -keep public class * implements com.bumptech.glide.module.GlideModule
  2. -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  3. **[] $VALUES;
  4. public *;
  5. }
  • Glide 4
  1. -keep public class * implements com.bumptech.glide.module.AppGlideModule
  2. -keep public class * implements com.bumptech.glide.module.LibraryGlideModule
  3. -keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  4. **[] $VALUES;
  5. public *;
  6. }

21)Picasso混淆配置

  1. -keep class com.parse.*{ *; }
  2. -dontwarn com.parse.**
  3. -dontwarn com.squareup.picasso.**
  4. -keepclasseswithmembernames class * {
  5. native <methods>;
  6. }

22)Fresco混淆配置

  1. # Keep our interfaces so they can be used by other ProGuard rules.
  2. # See http://sourceforge.net/p/proguard/bugs/466/
  3. -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
  4. -keep,allowobfuscation @interface com.facebook.soloader.DoNotOptimize
  5. # Do not strip any method/class that is annotated with @DoNotStrip
  6. -keep @com.facebook.common.internal.DoNotStrip class *
  7. -keepclassmembers class * {
  8. @com.facebook.common.internal.DoNotStrip *;
  9. }
  10. # Do not strip any method/class that is annotated with @DoNotOptimize
  11. -keep @com.facebook.soloader.DoNotOptimize class *
  12. -keepclassmembers class * {
  13. @com.facebook.soloader.DoNotOptimize *;
  14. }
  15. # Keep native methods
  16. -keepclassmembers class * {
  17. native <methods>;
  18. }
  19. -dontwarn okio.**
  20. -dontwarn com.squareup.okhttp.**
  21. -dontwarn okhttp3.**
  22. -dontwarn javax.annotation.**
  23. -dontwarn com.android.volley.toolbox.**
  24. -dontwarn com.facebook.infer.**

23)Fastjson混淆配置

  1. -dontwarn com.alibaba.fastjson.**
  2. -keep class com.alibaba.fastjson.**{*; }

24)Gson混淆配置

  1. -keep class com.google.gson.** {*;}
  2. -keep class com.google.**{*;}
  3. -keep class sun.misc.Unsafe { *; }
  4. -keep class com.google.gson.stream.** { *; }
  5. -keep class com.google.gson.examples.android.model.** { *; }

25)Banner混淆配置

  1. -keep class com.youth.banner.** {
  2. *;
  3. }

26)GreenDao混淆配置

  • GreenDAO 2:
  1. -keep class de.greenrobot.dao.** {*;}
  2. -keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
  3. public static Java.lang.String TABLENAME;
  4. }
  5. -keep class **$Properties
  • GreenDAO 3:
  1. -keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
  2. public static java.lang.String TABLENAME;
  3. }
  4. -keep class **$Properties
  5. # If you do not use SQLCipher:
  6. -dontwarn org.greenrobot.greendao.database.**
  7. # If you do not use Rx:
  8. -dontwarn rx.**

27)百度定位混淆配置

  1. -keep class vi.com.gdi.** { *; }
  2. -keep public class com.baidu.** {*;}
  3. -keep public class com.mobclick.** {*;}
  4. -dontwarn com.baidu.mapapi.utils.*
  5. -dontwarn com.baidu.platform.comapi.b.*
  6. -dontwarn com.baidu.platform.comapi.map.*

28)百度地图混淆配置

  1. -keep class com.baidu.** {*;}
  2. -keep class vi.com.** {*;}
  3. -dontwarn com.baidu.**

29)高徳地图混淆配置

  1. -dontwarn com.amap.api.**
  2. -dontwarn com.a.a.**
  3. -dontwarn com.autonavi.**
  4. -keep class com.amap.api.** {*;}
  5. -keep class com.autonavi.** {*;}
  6. -keep class com.a.a.** {*;}

30)Bugly混淆配置

  1. -dontwarn com.tencent.bugly.**
  2. -keep public class com.tencent.bugly.**{*;}

31)EventBus混淆配置

  • EventBus 2:
  1. -keepclassmembers class ** {
  2. public void onEvent*(***);
  3. }
  4. # Only required if you use AsyncExecutor
  5. -keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent {
  6. <init>(java.lang.Throwable);
  7. }
  • EventBus 3:
  1. -keepattributes *Annotation*
  2. -keepclassmembers class ** {
  3. @org.greenrobot.eventbus.Subscribe <methods>;
  4. }
  5. -keep enum org.greenrobot.eventbus.ThreadMode { *; }
  6. # Only required if you use AsyncExecutor
  7. -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
  8. <init>(java.lang.Throwable);
  9. }

32)友盟分享混淆配置

  1. -dontshrink
  2. -dontoptimize
  3. -dontwarn com.google.android.maps.**
  4. -dontwarn android.webkit.WebView
  5. -dontwarn com.umeng.**
  6. -dontwarn com.tencent.weibo.sdk.**
  7. -dontwarn com.facebook.**
  8. -keep public class javax.**
  9. -keep public class android.webkit.**
  10. -dontwarn android.support.v4.**
  11. -keep enum com.facebook.**
  12. -keepattributes Exceptions,InnerClasses,Signature
  13. -keepattributes *Annotation*
  14. -keepattributes SourceFile,LineNumberTable
  15. -keep public interface com.facebook.**
  16. -keep public interface com.tencent.**
  17. -keep public interface com.umeng.socialize.**
  18. -keep public interface com.umeng.socialize.sensor.**
  19. -keep public interface com.umeng.scrshot.**
  20. -keep public class com.umeng.socialize.* {*;}
  21. -keep class com.facebook.**
  22. -keep class com.facebook.** { *; }
  23. -keep class com.umeng.scrshot.**
  24. -keep public class com.tencent.** {*;}
  25. -keep class com.umeng.socialize.sensor.**
  26. -keep class com.umeng.socialize.handler.**
  27. -keep class com.umeng.socialize.handler.*
  28. -keep class com.umeng.weixin.handler.**
  29. -keep class com.umeng.weixin.handler.*
  30. -keep class com.umeng.qq.handler.**
  31. -keep class com.umeng.qq.handler.*
  32. -keep class UMMoreHandler{*;}
  33. -keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;}
  34. -keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;}
  35. -keep class im.yixin.sdk.api.YXMessage {*;}
  36. -keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;}
  37. -keep class com.tencent.mm.sdk.** {
  38. *;
  39. }
  40. -keep class com.tencent.mm.opensdk.** {
  41. *;
  42. }
  43. -keep class com.tencent.wxop.** {
  44. *;
  45. }
  46. -keep class com.tencent.mm.sdk.** {
  47. *;
  48. }
  49. -dontwarn twitter4j.**
  50. -keep class twitter4j.** { *; }
  51. -keep class com.tencent.** {*;}
  52. -dontwarn com.tencent.**
  53. -keep class com.kakao.** {*;}
  54. -dontwarn com.kakao.**
  55. -keep public class com.umeng.com.umeng.soexample.R$*{
  56. public static final int *;
  57. }
  58. -keep public class com.linkedin.android.mobilesdk.R$*{
  59. public static final int *;
  60. }
  61. -keepclassmembers enum * {
  62. public static **[] values();
  63. public static ** valueOf(java.lang.String);
  64. }
  65. -keep class com.tencent.open.TDialog$*
  66. -keep class com.tencent.open.TDialog$* {*;}
  67. -keep class com.tencent.open.PKDialog
  68. -keep class com.tencent.open.PKDialog {*;}
  69. -keep class com.tencent.open.PKDialog$*
  70. -keep class com.tencent.open.PKDialog$* {*;}
  71. -keep class com.umeng.socialize.impl.ImageImpl {*;}
  72. -keep class com.sina.** {*;}
  73. -dontwarn com.sina.**
  74. -keep class com.alipay.share.sdk.** {
  75. *;
  76. }
  77. -keepnames class * implements android.os.Parcelable {
  78. public static final ** CREATOR;
  79. }
  80. -keep class com.linkedin.** { *; }
  81. -keep class com.android.dingtalk.share.ddsharemodule.** { *; }
  82. -keepattributes Signature

33)友盟推送混淆配置

  1. -dontwarn com.umeng.**
  2. -dontwarn com.taobao.**
  3. -dontwarn anet.channel.**
  4. -dontwarn anetwork.channel.**
  5. -dontwarn org.android.**
  6. -dontwarn org.apache.thrift.**
  7. -dontwarn com.xiaomi.**
  8. -dontwarn com.huawei.**
  9. -dontwarn com.meizu.**
  10. -keepattributes *Annotation*
  11. -keep class com.taobao.** {*;}
  12. -keep class org.android.** {*;}
  13. -keep class anet.channel.** {*;}
  14. -keep class com.umeng.** {*;}
  15. -keep class com.xiaomi.** {*;}
  16. -keep class com.huawei.** {*;}
  17. -keep class com.meizu.** {*;}
  18. -keep class org.apache.thrift.** {*;}
  19. -keep class com.alibaba.sdk.android.**{*;}
  20. -keep class com.ut.**{*;}
  21. -keep class com.ta.**{*;}
  22. -keep public class **.R$*{
  23. public static final int *;
  24. }

  1. #指定压缩级别
  2. -optimizationpasses 5
  3. #不跳过非公共的库的类成员
  4. -dontskipnonpubliclibraryclassmembers
  5. #混淆时采用的算法
  6. -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
  7. #把混淆类中的方法名也混淆了
  8. -useuniqueclassmembernames
  9. #优化时允许访问并修改有修饰符的类和类的成员
  10. -allowaccessmodification
  11. #将文件来源重命名为“SourceFile”字符串
  12. -renamesourcefileattribute SourceFile
  13. #保留行号
  14. -keepattributes SourceFile,LineNumberTable
  15. #保持泛型
  16. -keepattributes Signature
  17. #保持所有实现 Serializable 接口的类成员
  18. -keepclassmembers class * implements java.io.Serializable {
  19. static final long serialVersionUID;
  20. private static final java.io.ObjectStreamField[] serialPersistentFields;
  21. private void writeObject(java.io.ObjectOutputStream);
  22. private void readObject(java.io.ObjectInputStream);
  23. java.lang.Object writeReplace();
  24. java.lang.Object readResolve();
  25. }
  26. #Fragment不需要在AndroidManifest.xml中注册,需要额外保护下
  27. -keep public class * extends android.support.v4.app.Fragment
  28. -keep public class * extends android.app.Fragment
  29. # 保持测试相关的代码
  30. -dontnote junit.framework.**
  31. -dontnote junit.runner.**
  32. -dontwarn android.test.**
  33. -dontwarn android.support.test.**
  34. -dontwarn org.junit.**

真正通用的、需要添加的就是上面这些,除此之外,需要每个项目根据自身的需求添加一些混淆规则:

第三方库所需的混淆规则。正规的第三方库一般都会在接入文档中写好所需混淆规则,使用时注意添加。

在运行时动态改变的代码,例如反射。比较典型的例子就是会与 json 相互转换的实体类。假如项目命名规范要求实体类都要放在model包下的话,可以添加类似这样的代码把所有实体类都保持住:-keep public class **.*Model*.** {*;}

JNI中调用的类。

WebViewJavaScript调用的方法

Layout布局使用的View构造函数、android:onClick等。

检查混淆结果

混淆过的包必须进行检查,避免因混淆引入的bug。

一方面,需要从代码层面检查。使用上文的配置进行混淆打包后在<module-name>/build/outputs/mapping/release/目录下会输出以下文件:

dump.txt

描述APK文件中所有类的内部结构

mapping.txt

提供混淆前后类、方法、类成员等的对照表

seeds.txt

列出没有被混淆的类和成员

usage.txt

列出被移除的代码

我们可以根据 seeds.txt 文件检查未被混淆的类和成员中是否已包含所有期望保留的,再根据 usage.txt文件查看是否有被误移除的代码。

另一方面,需要从测试方面检查。将混淆过的包进行全方面测试,检查是否有 bug 产生。

解出混淆栈

混淆后的类、方法名等等难以阅读,这固然会增加逆向工程的难度,但对追踪线上 crash 也造成了阻碍。我们拿到 crash 的堆栈信息后会发现很难定位,这时需要将混淆反解。

<sdk-root>/tools/proguard/路径下有附带的的反解工具(Window 系统为proguardgui.bat,Mac 或 Linux 系统为proguardgui.sh)。

这里以 Window 平台为例。双击运行 proguardgui.bat 后,可以看到左侧的一行菜单。点击 ReTrace,选择该混淆包对应的 mapping 文件(混淆后在 <module-name>/build/outputs/mapping/release/ 路径下会生成 mapping.txt 文件,它的作用是提供混淆前后类、方法、类成员等的对照表),再将 crash 的 stack trace 黏贴进输入框中,点击右下角的 ReTrace ,混淆后的堆栈信息就显示出来了。

以上使用 GUI 程序进行操作,另一种方式是利用该路径下的 retrace 工具通过命令行进行反解,命令是

retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]

例如:

retrace.bat -verbose mapping.txt obfuscated_trace.txt

注意事项:

所有在 AndroidManifest.xml 涉及到的类已经自动被保持,因此不用特意去添加这块混淆规则。(很多老的混淆文件里会加,现在已经没必要)

proguard-android.txt已经存在一些默认混淆规则,没必要在 proguard-rules.pro 重复添加

混淆简介

Android中的“混淆”可以分为两部分,一部分是Java 代码的优化与混淆,依靠 proguard混淆器来实现;另一部分是资源压缩,将移除项目及依赖的库中未被使用的资源(资源压缩严格意义上跟混淆没啥关系,但一般我们都会放一起用)。

代码压缩

代码混淆是包含了代码压缩、优化、混淆等一系列行为的过程。如上图所示,混淆过程会有如下几个功能:

压缩。移除无效的类、类成员、方法、属性等;
优化。分析和优化方法的二进制代码;根据proguard-android-optimize.txt中的描述,优化可能会造成一些潜在风险,不能保证在所有版本的Dalvik上都正常运行。
混淆。把类名、属性名、方法名替换为简短且无意义的名称;
预校验。添加预校验信息。这个预校验是作用在Java平台上的,Android平台上不需要这项功能,去掉之后还可以加快混淆速度。
这四个流程默认开启。

Android项目中我们可以选择将“优化”和“预校验”关闭,对应命令是-dontoptimize、-dontpreverify(当然,默认的 proguard-android.txt文件已包含这两条混淆命令,不需要开发者额外配置)。

资源压缩

资源压缩将移除项目及依赖的库中未被使用的资源,这在减少apk 包体积上会有不错的效果,一般建议开启。具体做法是在 build.grade文件中,将shrinkResources属性设置为true。需要注意的是,只有在用minifyEnabled true开启了代码压缩后,资源压缩才会生效。

资源压缩包含了“合并资源”和“移除资源”两个流程。

“合并资源”流程中,名称相同的资源被视为重复资源会被合并。需要注意的是,这一流程不受shrinkResources属性控制,也无法被禁止,gradle必然会做这项工作,因为假如不同项目中存在相同名称的资源将导致错误。gradle 在四处地方寻找重复资源:

src/main/res/ 路径
不同的构建类型(debugrelease等等)
不同的构建渠道
项目依赖的第三方库
合并资源时按照如下优先级顺序

  1. 依赖 -> main -> 渠道 -> 构建类型

假如重复资源同时存在于main文件夹和不同渠道中,gradle 会选择保留渠道中的资源。

同时,如果重复资源在同一层次出现,比如src/main/res/ 和 src/main/res2/,则 gradle无法完成资源合并,这时会报资源合并错误。

“移除资源”流程则见名知意,需要注意的是,类似代码,混淆资源移除也可以定义哪些资源需要被保留,这点在下文给出。

自定义混淆规则

在上文“混淆配置”中有这样一行代码

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

这行代码定义了混淆规则由两部分构成:位于 SDK 的 tools/proguard/ 文件夹中的 proguard-android.txt 的内容以及默认放置于模块根目录的 proguard-rules.pro 的内容。前者是 SDK 提供的默认混淆文件,后者是开发者自定义混淆规则的地方。

常见的混淆指令

  • optimizationpasses
  • dontoptimize
  • dontusemixedcaseclassnames
  • dontskipnonpubliclibraryclasses
  • dontpreverify
  • dontwarn
  • verbose
  • optimizations
  • keep
  • keepnames
  • keepclassmembers
  • keepclassmembernames
  • keepclasseswithmembers
  • keepclasseswithmembernames
    更多详细的请到官网

需要特别介绍的是与保持相关元素不参与混淆的规则相关的几种命令:

命令作用
-keep防止类和成员被移除或者被重命名
-keepnames防止类和成员被重命名
-keepclassmembers防止成员被移除或者被重命名
-keepnames防止成员被重命名
-keepclasseswithmembers防止拥有该成员的类和成员被移除或者被重命名
-keepclasseswithmembernames防止拥有该成员的类和成员被重命名

保持元素不参与混淆的规则

  1. [保持命令] [类] {
  2. [成员]
  3. }

“类”代表类相关的限定条件,它将最终定位到某些符合该限定条件的类。它的内容可以使用:

  • 具体的类
  • 访问修饰符(public、protected、private)
  • 通配符*,匹配任意长度字符,但不含包名分隔符(.)
  • 通配符**,匹配任意长度字符,并且包含包名分隔符(.)
  • extends,即可以指定类的基类
  • implement,匹配实现了某接口的类
  • $,内部类

“成员”代表类成员相关的限定条件,它将最终定位到某些符合该限定条件的类成员。它的内容可以使用:

  • <init> 匹配所有构造器
  • <fields> 匹配所有域
  • <methods> 匹配所有方法
  • 通配符*,匹配任意长度字符,但不含包名分隔符(.)
  • 通配符**,匹配任意长度字符,并且包含包名分隔符(.)
  • 通配符***,匹配任意参数类型
  • …,匹配任意长度的任意类型参数。比如void test(…)就能匹配任意 void test(String a) 或者是 void test(int a, String b) 这些方法。
  • 访问修饰符(public、protected、private)
    举个例子,假如需要将com.biaobiao.test包下所有继承Activity的public类及其构造函数都保持住,可以这样写:
  1. -keep public class com.biaobiao.test.** extends Android.app.Activity {
  2. <init>
  3. }

常用自定义混淆规则

  • 不混淆某个类
  1. -keep public class com.biaobiao.example.Test { *; }

不混淆某个包所有的类

  1. -keep class com.biaobiao.test.** { *; }
  2. }

不混淆某个类的子类

  1. -keep public class * extends com.biaobiao.example.Test { *; }

不混淆所有类名中包含了“model”的类及其成员

  1. -keep public class * extends com.biaobiao.example.Test { *; }

不混淆某个接口的实现

  1. -keep class * implements com.biaobiao.example.TestInterface { *; }

不混淆某个类的构造方法

  1. -keepclassmembers class com.biaobiao.example.Test {
  2. public <init>();
  3. }

不混淆某个类的特定的方法

  1. -keepclassmembers class com.biaobiao.example.Test {
  2. public void test(java.lang.String);
  3. }
  4. }

不混淆某个类的内部类

  1. -keep class com.biaobiao.example.Test$* {
  2. *;
  3. }

自定义资源保持规则

1. keep.xml

shrinkResources true开启资源压缩后,所有未被使用的资源默认被移除。假如你需要定义哪些资源必须被保留,在 res/raw/ 路径下创建一个 xml 文件,例如keep.xml

通过一些属性的设置可以实现定义资源保持的需求,可配置的属性有:

  • keep 定义哪些资源需要被保留(资源之间用“,”隔开)
  • discard 定义哪些资源需要被移除(资源之间用“,”隔开)
  • shrinkMode 开启严格模式
  • 当代码中通过Resources.getIdentifier() 用动态的字符串来获取并使用资源时,普通的资源引用检查就可能会有问题。例如,如下代码会导致所有以“img_”开头的资源都被标记为已使用。
    当代码中通过 Resources.getIdentifier() 用动态的字符串来获取并使用资源时,普通的资源引用检查就可能会有问题。例如,如下代码会导致所有以“img_”开头的资源都被标记为已使用。
  1. String name = String.format("img_%1d", angle + 1);
  2. res = getResources().getIdentifier(name, "drawable", getPackageName());

我们可以设置 tools:shrinkModestrict来开启严格模式,使只有确实被使用的资源被保留。

以上就是自定义资源保持规则相关的配置,举个例子:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources xmlns:tools="http://schemas.android.com/tools"
  3. tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
  4. tools:discard="@layout/unused2"
  5. tools:shrinkMode="strict"/>

移除替代资源

一些替代资源,例如多语言支持的 strings.xml,多分辨率支持的 layout.xml 等,在我们不需要使用又不想删除掉时,可以使用资源压缩将它们移除。

我们使用 resConfig 属性来指定需要支持的属性,例如
一些替代资源,例如多语言支持的strings.xml,多分辨率支持的 layout.xml等,在我们不需要使用又不想删除掉时,可以使用资源压缩将它们移除。

我们使用 resConfig属性来指定需要支持的属性,例如

  1. android {
  2. defaultConfig {
  3. ...
  4. resConfigs "en", "fr"
  5. }
  6. }

其他未显式声明的语言资源将被移除。

最后附上一个我在实际项目中的混淆方案

proguard-android.txt文件内容

  1. # 代码混淆压缩比,在0~7之间
  2. -optimizationpasses 5
  3. # 混合时不使用大小写混合,混合后的类名为小写
  4. -dontusemixedcaseclassnames
  5. # 指定不去忽略非公共库的类
  6. -dontskipnonpubliclibraryclasses
  7. # 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
  8. -dontpreverify
  9. -verbose
  10. # 避免混淆泛型
  11. -keepattributes Signature
  12. # 保留Annotation不混淆
  13. -keepattributes *Annotation*,InnerClasses
  14. #google推荐算法
  15. -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
  16. # 避免混淆Annotation、内部类、泛型、匿名类
  17. -keepattributes *Annotation*,InnerClasses,Signature,EnclosingMethod
  18. # 重命名抛出异常时的文件名称
  19. -renamesourcefileattribute SourceFile
  20. # 抛出异常时保留代码行号
  21. -keepattributes SourceFile,LineNumberTable
  22. # 处理support包
  23. -dontnote android.support.**
  24. -dontwarn android.support.**
  25. # 保留继承的
  26. -keep public class * extends android.support.v4.**
  27. -keep public class * extends android.support.v7.**
  28. -keep public class * extends android.support.annotation.**
  29. # 保留R下面的资源
  30. -keep class **.R$* {*;}
  31. # 保留四大组件,自定义的Application等这些类不被混淆
  32. -keep public class * extends android.app.Activity
  33. -keep public class * extends android.app.Appliction
  34. -keep public class * extends android.app.Service
  35. -keep public class * extends android.content.BroadcastReceiver
  36. -keep public class * extends android.content.ContentProvider
  37. -keep public class * extends android.preference.Preference
  38. -keep public class com.android.vending.licensing.ILicensingService
  39. # 保留在Activity中的方法参数是view的方法,
  40. # 这样以来我们在layout中写的onClick就不会被影响
  41. -keepclassmembers class * extends android.app.Activity{
  42. public void *(android.view.View);
  43. }
  44. # 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
  45. -keepclassmembers class * {
  46. void *(**On*Event);
  47. void *(**On*Listener);
  48. }
  49. # 保留本地native方法不被混淆
  50. -keepclasseswithmembernames class * {
  51. native <methods>;
  52. }
  53. # 保留枚举类不被混淆
  54. -keepclassmembers enum * {
  55. public static **[] values();
  56. public static ** valueOf(java.lang.String);
  57. }
  58. # 保留Parcelable序列化类不被混淆
  59. -keep class * implements android.os.Parcelable {
  60. public static final android.os.Parcelable$Creator *;
  61. }
  62. -keepclassmembers class * implements java.io.Serializable {
  63. static final long serialVersionUID;
  64. private static final java.io.ObjectStreamField[] serialPersistentFields;
  65. private void writeObject(java.io.ObjectOutputStream);
  66. private void readObject(java.io.ObjectInputStream);
  67. java.lang.Object writeReplace();
  68. java.lang.Object readResolve();
  69. }
  70. #assume no side effects:删除android.util.Log输出的日志
  71. -assumenosideeffects class android.util.Log {
  72. public static *** v(...);
  73. public static *** d(...);
  74. public static *** i(...);
  75. public static *** w(...);
  76. public static *** e(...);
  77. }
  78. #保留Keep注解的类名和方法
  79. -keep,allowobfuscation @interface android.support.annotation.Keep
  80. -keep @android.support.annotation.Keep class *
  81. -keepclassmembers class * {
  82. @android.support.annotation.Keep *;
  83. }
  84. #3D 地图 V5.0.0之前:
  85. -dontwarn com.amap.api.**
  86. -dontwarn com.autonavi.**
  87. -keep class com.amap.api.**{*;}
  88. -keep class com.autonavi.**{*;}
  89. -keep class com.amap.api.maps.**{*;}
  90. -keep class com.autonavi.amap.mapcore.*{*;}
  91. -keep class com.amap.api.trace.**{*;}
  92. #3D 地图 V5.0.0之后:
  93. -keep class com.amap.api.maps.**{*;}
  94. -keep class com.autonavi.**{*;}
  95. -keep class com.amap.api.trace.**{*;}
  96. #定位
  97. -keep class com.amap.api.location.**{*;}
  98. -keep class com.amap.api.fence.**{*;}
  99. -keep class com.autonavi.aps.amapapi.model.**{*;}
  100. #搜索
  101. -keep class com.amap.api.services.**{*;}
  102. #2D地图
  103. -keep class com.amap.api.maps2d.**{*;}
  104. -keep class com.amap.api.mapcore2d.**{*;}
  105. #导航
  106. -keep class com.amap.api.navi.**{*;}
  107. -keep class com.autonavi.**{*;}
  108. # Retain generic type information for use by reflection by converters and adapters.
  109. -keepattributes Signature
  110. # Retain service method parameters when optimizing.
  111. -keepclassmembers,allowshrinking,allowobfuscation interface * {
  112. @retrofit2.http.* <methods>;
  113. }
  114. # Ignore annotation used for build tooling.
  115. -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
  116. # Ignore JSR 305 annotations for embedding nullability information.
  117. -dontwarn javax.annotation.**
  118. # JSR 305 annotations are for embedding nullability information.
  119. -dontwarn javax.annotation.**
  120. # A resource is loaded with a relative path so the package of this class must be preserved.
  121. -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
  122. # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
  123. -dontwarn org.codehaus.mojo.animal_sniffer.*
  124. # OkHttp platform used only on JVM and when Conscrypt dependency is available.
  125. -dontwarn okhttp3.internal.platform.ConscryptPlatform
  126. #fastjson混淆
  127. -keepattributes Signature
  128. -dontwarn com.alibaba.fastjson.**
  129. -keep class com.alibaba.**{*;}
  130. -keep class com.alibaba.fastjson.**{*; }
  131. -keep public class com.ninstarscf.ld.model.entity.**{*;}

所有文章参考

 

原文连接:Android 代码混淆 - Endv - 博客园

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/285551?site
推荐阅读
相关标签
  

闽ICP备14008679号