Android 代碼混淆


本篇文章:自己在混淆的時候整理出比較全面的混淆方法,比較實用,自己走過的坑,淌出來的路。請大家不要再走回頭路,可能只要我們代碼加混淆,一點不對就會導致項目運行崩潰等后果,有許多人發現沒有打包運行好好地,打包完成以后而又不不可以了,導致了許多困惑,本片文章來問大家解決困惑,希望對大家有幫助。

Android混淆最佳實踐

1. 混淆配置

 

因為開啟混淆會使編譯時間變長,所以debug模式下不開啟。我們需要做的是:
1.將release下minifyEnabled的值改為true,打開混淆;
2.加上shrinkResources true,打開資源壓縮。
3.buildConfigField 不顯示log日志
4.signingConfig signingConfigs.config配置簽名文件文件

自定義混淆規則

自定義混淆方案適用於大部分的項目

android{

buildTypes {
        release {
            buildConfigField "boolean", "LOG_DEBUG", "false" //不顯示log
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.config
            }
        }
}

 or

buildTypes {
        debug {         
            minifyEnabled false // 混淆  
            zipAlignEnabled true // Zipalign優化 
            shrinkResources true // 移除無用的resource文件    
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  // 加載默認混淆配置文件  
            signingConfig signingConfigs.debug // 簽名
        }
        release {                      
            minifyEnabled true // 混淆            
            zipAlignEnabled true // Zipalign優化          
            shrinkResources true  // 移除無用的resource文件           
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  // 加載默認混淆配置文件
            signingConfig signingConfigs.relealse  // 簽名
        }
    }
 

 

 

2. 混淆規則

混淆會用無意義的短變量去重命名類、變量、方法,但是對於外部的一些引用是通過名字找到對應的方法和類。混淆過后通過原來的名字去找混淆后的名字,是找不到對應方法和類,就會出異常報錯。所以有些情況是不能進行混淆的。

  • 自定義控件不進行混淆
  • 枚舉類不被混淆
  • 反射類不進行混淆
  • 實體類不被混淆
  • JS調用的Java方法
  • 四大組件不進行混淆
  • JNI中調用類不進行混淆
  • Layout布局使用的View構造函數、android:onClick等
  • Parcelable 的子類和 Creator 靜態成員變量不混淆
  • 第三方開源庫或者引用其他第三方的SDK包不進行混淆

 

3. 混淆模板

1)基本指令

# 設置混淆的壓縮比率 0 ~ 7 -optimizationpasses 5 # 混淆時不使用大小寫混合,混淆后的類名為小寫 -dontusemixedcaseclassnames # 指定不去忽略非公共庫的類 -dontskipnonpubliclibraryclasses # 指定不去忽略非公共庫的成員 -dontskipnonpubliclibraryclassmembers # 混淆時不做預校驗 -dontpreverify # 混淆時不記錄日志 -verbose # 忽略警告 -ignorewarning # 代碼優化 -dontshrink # 不優化輸入的類文件 -dontoptimize # 保留注解不混淆 -keepattributes *Annotation*,InnerClasses # 避免混淆泛型 -keepattributes Signature # 保留代碼行號,方便異常信息的追蹤 -keepattributes SourceFile,LineNumberTable # 混淆采用的算法 -optimizations !code/simplification/cast,!field/*,!class/merging/* # dump.txt文件列出apk包內所有class的內部結構 -dump class_files.txt # seeds.txt文件列出未混淆的類和成員 -printseeds seeds.txt # usage.txt文件列出從apk中刪除的代碼 -printusage unused.txt # mapping.txt文件列出混淆前后的映射 -printmapping mapping.txt 

2)不需混淆的Android類

-keep public class * extends android.app.Fragment -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.preference.Preference -keep public class * extends android.content.ContentProvider -keep public class * extends android.support.v4.** -keep public class * extends android.support.annotation.** -keep public class * extends android.support.v7.** -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 com.android.vending.licensing.ILicensingService -keep class android.support.** {*;} 

3)support-v4包

-dontwarn android.support.v4.** -keep class android.support.v4.app.** { *; } -keep interface android.support.v4.app.** { *; } -keep class android.support.v4.** { *; } 

4)support-v7包

-dontwarn android.support.v7.** -keep class android.support.v7.internal.** { *; } -keep interface android.support.v7.internal.** { *; } -keep class android.support.v7.** { *; } 

5)support design

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

6)避免混淆自定義控件類的 get/set 方法和構造函數

-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); } 

7)關閉 Log日志

-assumenosideeffects class android.util.Log { public static boolean isLoggable(java.lang.String, int); public static int v(...); public static int i(...); public static int w(...); public static int d(...); public static int e(...); } 

-dontoptimize不要配置,不然將會關閉優化,導致日志語句不會被優化掉。

8)避免資源混淆

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

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

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

10)避免回調函數 onXXEvent 混淆

-keepclassmembers class * { void *(*Event); } 

11)避免混淆枚舉類

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

12)Natvie 方法不混淆

-keepclasseswithmembernames class * { native <methods>; } 

13)避免Parcelable混淆

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

14)避免Serializable接口的子類中指定的某些成員變量和方法混淆

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

15)WebView混淆配置

-keepclassmembers class fqcn.of.javascript.interface.for.webview { public *; } -keepclassmembers class * extends android.webkit.webViewClient { public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); public boolean *(android.webkit.WebView, java.lang.String); } -keepclassmembers class * extends android.webkit.webViewClient { public void *(android.webkit.webView, jav.lang.String); } 

16)ButterKnife混淆配置

-keep class butterknife.** { *; } -dontwarn butterknife.internal.** -keep class **$$ViewBinder { *; } -keepclasseswithmembernames class * { @butterknife.* <fields>; } -keepclasseswithmembernames class * { @butterknife.* <methods>; } 

17)OkHttp3混淆配置

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

18)Retrofit2混淆配置

-dontwarn retrofit2.** -keep class retrofit2.** { *; } -keepattributes Signature -keepattributes Exceptions 

19)RxJava、RxAndroid混淆配置

-dontwarn sun.misc.** -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { long producerIndex; long consumerIndex; } -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { rx.internal.util.atomic.LinkedQueueNode producerNode; } -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { rx.internal.util.atomic.LinkedQueueNode consumerNode; } 

20)Glide混淆配置

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

21)Picasso混淆配置

-keep class com.parse.*{ *; } -dontwarn com.parse.** -dontwarn com.squareup.picasso.** -keepclasseswithmembernames class * { native <methods>; } 

22)Fresco混淆配置

# Keep our interfaces so they can be used by other ProGuard rules. # See http://sourceforge.net/p/proguard/bugs/466/ -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip -keep,allowobfuscation @interface com.facebook.soloader.DoNotOptimize # Do not strip any method/class that is annotated with @DoNotStrip -keep @com.facebook.common.internal.DoNotStrip class * -keepclassmembers class * { @com.facebook.common.internal.DoNotStrip *; } # Do not strip any method/class that is annotated with @DoNotOptimize -keep @com.facebook.soloader.DoNotOptimize class * -keepclassmembers class * { @com.facebook.soloader.DoNotOptimize *; } # Keep native methods -keepclassmembers class * { native <methods>; } -dontwarn okio.** -dontwarn com.squareup.okhttp.** -dontwarn okhttp3.** -dontwarn javax.annotation.** -dontwarn com.android.volley.toolbox.** -dontwarn com.facebook.infer.** 

23)Fastjson混淆配置

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

24)Gson混淆配置

-keep class com.google.gson.** {*;} -keep class com.google.**{*;} -keep class sun.misc.Unsafe { *; } -keep class com.google.gson.stream.** { *; } -keep class com.google.gson.examples.android.model.** { *; } 

25)Banner混淆配置

-keep class com.youth.banner.** { *; } 

26)GreenDao混淆配置

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

27)百度定位混淆配置

-keep class vi.com.gdi.** { *; } -keep public class com.baidu.** {*;} -keep public class com.mobclick.** {*;} -dontwarn com.baidu.mapapi.utils.* -dontwarn com.baidu.platform.comapi.b.* -dontwarn com.baidu.platform.comapi.map.* 

28)百度地圖混淆配置

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

29)高徳地圖混淆配置

-dontwarn com.amap.api.** -dontwarn com.a.a.** -dontwarn com.autonavi.** -keep class com.amap.api.** {*;} -keep class com.autonavi.** {*;} -keep class com.a.a.** {*;} 

30)Bugly混淆配置

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

31)EventBus混淆配置

  • EventBus 2:
-keepclassmembers class ** { public void onEvent*(***); } # Only required if you use AsyncExecutor -keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent { <init>(java.lang.Throwable); } 
  • EventBus 3:
-keepattributes *Annotation* -keepclassmembers class ** { 

32)友盟分享混淆配置

-dontshrink -dontoptimize -dontwarn com.google.android.maps.** -dontwarn android.webkit.WebView -dontwarn com.umeng.** -dontwarn com.tencent.weibo.sdk.** -dontwarn com.facebook.** -keep public class javax.** -keep public class android.webkit.** -dontwarn android.support.v4.** -keep enum com.facebook.** -keepattributes Exceptions,InnerClasses,Signature -keepattributes *Annotation* -keepattributes SourceFile,LineNumberTable -keep public interface com.facebook.** -keep public interface com.tencent.** -keep public interface com.umeng.socialize.** -keep public interface com.umeng.socialize.sensor.** -keep public interface com.umeng.scrshot.** -keep public class com.umeng.socialize.* {*;} -keep class com.facebook.** -keep class com.facebook.** { *; } -keep class com.umeng.scrshot.** -keep public class com.tencent.** {*;} -keep class com.umeng.socialize.sensor.** -keep class com.umeng.socialize.handler.** -keep class com.umeng.socialize.handler.* -keep class com.umeng.weixin.handler.** -keep class com.umeng.weixin.handler.* -keep class com.umeng.qq.handler.** -keep class com.umeng.qq.handler.* -keep class UMMoreHandler{*;} -keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;} -keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;} -keep class im.yixin.sdk.api.YXMessage {*;} -keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;} -keep class com.tencent.mm.sdk.** { *; } -keep class com.tencent.mm.opensdk.** { *; } -keep class com.tencent.wxop.** { *; } -keep class com.tencent.mm.sdk.** { *; } -dontwarn twitter4j.** -keep class twitter4j.** { *; } -keep class com.tencent.** {*;} -dontwarn com.tencent.** -keep class com.kakao.** {*;} -dontwarn com.kakao.** -keep public class com.umeng.com.umeng.soexample.R$*{ public static final int *; } -keep public class com.linkedin.android.mobilesdk.R$*{ public static final int *; } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep class com.tencent.open.TDialog$* -keep class com.tencent.open.TDialog$* {*;} -keep class com.tencent.open.PKDialog -keep class com.tencent.open.PKDialog {*;} -keep class com.tencent.open.PKDialog$* -keep class com.tencent.open.PKDialog$* {*;} -keep class com.umeng.socialize.impl.ImageImpl {*;} -keep class com.sina.** {*;} -dontwarn com.sina.** -keep class com.alipay.share.sdk.** { *; } -keepnames class * implements android.os.Parcelable { public static final ** CREATOR; } -keep class com.linkedin.** { *; } -keep class com.android.dingtalk.share.ddsharemodule.** { *; } -keepattributes Signature 

33)友盟推送混淆配置

-dontwarn com.umeng.** -dontwarn com.taobao.** -dontwarn anet.channel.** -dontwarn anetwork.channel.** -dontwarn org.android.** -dontwarn org.apache.thrift.** -dontwarn com.xiaomi.** -dontwarn com.huawei.** -dontwarn com.meizu.** -keepattributes *Annotation* -keep class com.taobao.** {*;} -keep class org.android.** {*;} -keep class anet.channel.** {*;} -keep class com.umeng.** {*;} -keep class com.xiaomi.** {*;} -keep class com.huawei.** {*;} -keep class com.meizu.** {*;} -keep class org.apache.thrift.** {*;} -keep class com.alibaba.sdk.android.**{*;} -keep class com.ut.**{*;} -keep class com.ta.**{*;} -keep public class **.R$*{ public static final int *; }

 

 

#指定壓縮級別 -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 相互轉換的實體類。假如項目命名規范要求實體類都要放在model包下的話,可以添加類似這樣的代碼把所有實體類都保持住:-keep public class **.*Model*.** {*;}
JNI中調用的類。
WebView中JavaScript調用的方法
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等等)
不同的構建渠道
項目依賴的第三方庫
合並資源時按照如下優先級順序

依賴 -> 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 提供的默認混淆文件,后者是開發者自定義混淆規則的地方。

常見的混淆指令

  • optimizationpasses
  • dontoptimize
  • dontusemixedcaseclassnames
  • dontskipnonpubliclibraryclasses
  • dontpreverify
  • dontwarn
  • verbose
  • optimizations
  • keep
  • keepnames
  • keepclassmembers
  • keepclassmembernames
  • keepclasseswithmembers
  • keepclasseswithmembernames
    更多詳細的請到官網

需要特別介紹的是與保持相關元素不參與混淆的規則相關的幾種命令:

命令 作用
-keep 防止類和成員被移除或者被重命名
-keepnames 防止類和成員被重命名
-keepclassmembers 防止成員被移除或者被重命名
-keepnames 防止成員被重命名
-keepclasseswithmembers 防止擁有該成員的類和成員被移除或者被重命名
-keepclasseswithmembernames 防止擁有該成員的類和成員被重命名

保持元素不參與混淆的規則

  [保持命令] [類] { [成員] } 
“類”代表類相關的限定條件,它將最終定位到某些符合該限定條件的類。它的內容可以使用:
  • 具體的類
  • 訪問修飾符(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類及其構造函數都保持住,可以這樣寫:
 -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$* { *; } 

自定義資源保持規則

1. keep.xml

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:shrinkModestrict來開啟嚴格模式,使只有確實被使用的資源被保留。

以上就是自定義資源保持規則相關的配置,舉個例子:

<?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.**{*;} 

所有文章參考

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM