本篇文章:本身在混淆的時候整理出比較全面的混淆方法,比較實用,本身走過的坑,淌出來的路。請你們不要再走回頭路,可能只要咱們代碼加混淆,一點不對就會致使項目運行崩潰等後果,有許多人發現沒有打包運行好好地,打包完成之後而又不不能夠了,致使了許多困惑,本片文章來問你們解決困惑,但願對你們有幫助。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.**{*;}
全部文章參考