在 Gradle For Android(二) 多渠道打包與簽名配置中說過在日常開發(fā)中進(jìn)行打包apk的一些往事,打包測(cè)試、打包上傳應(yīng)用商店摔认,這些都避免不了喧兄。當(dāng)然在這過程中无畔,除了簽名打包,當(dāng)然少不了代碼的混淆了吠冤。代碼混淆浑彰,說白了就是代碼壓縮、代碼混淆以及資源壓縮的優(yōu)化拯辙。依靠 ProGuard郭变,將所有類名、方法名重命名為無意義的簡(jiǎn)單名稱涯保,增加了逆向工程難度诉濒。依靠Gradle插件,移除了沒有使用的資源夕春,減少了apk大小 未荒。
Gradle For Android 導(dǎo)讀
- Gradle For Android (一) 基礎(chǔ)定義與依賴管理篇
- Gradle For Android(二) 多渠道打包與簽名配置
- Gradle For Android(三)Gradle優(yōu)化與靈活的使用技巧
正文:
一、Android Gradle 混淆中的配置
一般及志,在我們的application moudle中的gradle配置項(xiàng)buildTypes中,例如如下:
release { //release類型
minifyEnabled false
// 啟用混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
這里minifyEnabled表示啟動(dòng)混淆片排,一般啟動(dòng)混淆編譯速度會(huì)比較慢,因此在編譯debug版本的時(shí)候一般默認(rèn)不開啟速侈。proguard-rules.pro這個(gè)表示該module默認(rèn)的混淆文件率寡,我們可以直接將混淆內(nèi)容寫在這里。另外倚搬,這里也要說下**shrinkResources **這個(gè)字段冶共,當(dāng)為true的時(shí)候,表示打開資源壓縮潭枣,編譯時(shí)會(huì)去掉沒被使用的資源文件比默。
修改后的配置代碼如下:
buildTypes {//表示構(gòu)建類型 一般有release debug 兩種
debug{
buildConfigField 'String','STATE_TEST','"debug"'//buildConfigField
resValue "string", "test_value", "AGradle_debug"http://resValue
}
release { //release類型
minifyEnabled true // 啟用混淆
shrinkResources true // 資源壓縮
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField 'String','STATE_TEST','"release"' //buildConfigField
resValue "string", "test_value", "AGradle_release" //resValue
}
}
二、混淆規(guī)則舉例
這里貼下網(wǎng)上認(rèn)為比較"通用"的混淆規(guī)則如下:
#指定壓縮級(jí)別
-optimizationpasses 5
#不跳過非公共的庫的類成員
-dontskipnonpubliclibraryclassmembers
#混淆時(shí)采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#把混淆類中的方法名也混淆了
-useuniqueclassmembernames
#優(yōu)化時(shí)允許訪問并修改有修飾符的類和類的成員
-allowaccessmodification
#將文件來源重命名為“SourceFile”字符串
-renamesourcefileattribute SourceFile
#保留行號(hào)
-keepattributes SourceFile,LineNumberTable
#保持所有實(shí)現(xiàn) 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中注冊(cè)盆犁,需要額外保護(hù)下
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment
# 保持測(cè)試相關(guān)的代碼
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**
"通用"命咐,當(dāng)然真正實(shí)現(xiàn)通用,除了上面的混淆規(guī)則谐岁,需要根據(jù)項(xiàng)目需要添加自定義的混淆規(guī)則
例如:
第三方庫混淆規(guī)則醋奠。這個(gè)比較常見榛臼,直接接入官方說明文檔。
model實(shí)體類窜司,典型在轉(zhuǎn)化json的時(shí)候沛善,必須保證model不被混淆,因此需加入--keep public class
JNI中調(diào)用的類以及方法不可被混淆
WebView中JavaScript調(diào)用的接口不混淆
AndroidMainfest塞祈、四大組件以及Application的子類不混淆
Parcelable的子類和Creator靜態(tài)成員變量不混淆金刁,否則會(huì)產(chǎn)生Android.os.BadParcelableException異常
Layout布局使用的View構(gòu)造函數(shù)、android:onClick等议薪。
三尤蛮、混淆結(jié)果的檢測(cè)
在開啟混淆后,通過混淆配置打包后斯议,會(huì)在目錄:
<module>/outputs/mapping/<渠道名>/<編譯類型>/..
如圖所示:
下面大概說明下:
- dump.txt :描述APK文件中所有類的內(nèi)部結(jié)構(gòu)
- mapping.txt :提供混淆前后類产捞、方法、類成員等的對(duì)照表
- seeds.txt:列出沒有被混淆的類和成員
usage.txt: 列出被移除的代碼
我們可以根據(jù) seeds.txt 文件檢查未被混淆的類和成員中是否已包含所有期望保留的哼御,再根據(jù) usage.txt 文件查看是否有被誤移除的代碼坯临。建議讀者都試下去查看下,必須有收獲~
四恋昼、自定義混淆規(guī)則
(一) proguard 參數(shù)
include {filename} 從給定的文件中讀取配置參數(shù)
basedirectory {directoryname} 指定基礎(chǔ)目錄為以后相對(duì)的檔案名稱
injars {class_path} 指定要處理的應(yīng)用程序jar,war,ear和目錄
outjars {class_path} 指定處理完后要輸出的jar,war,ear和目錄的名稱
libraryjars {classpath} 指定要處理的應(yīng)用程序jar,war,ear和目錄所需要的程序庫文件
dontskipnonpubliclibraryclasses 指定不去忽略非公共的庫類看靠。
dontskipnonpubliclibraryclassmembers 不跳過非公共的庫的類成員
上面部分參數(shù),日常移動(dòng)開發(fā)的應(yīng)用混淆中也不是經(jīng)常使用到的焰雕,如果讀者想進(jìn)一步深入了解每個(gè)參數(shù)實(shí)際作用衷笋,可以去官網(wǎng)進(jìn)行查閱,這里筆者不做太多說明哈矩屁。
(二)keep 參數(shù)
keep {Modifier(屬性辟宗,例如public,以下說明一致)} {class_specification(具體類或者成員的位置吝秕,以下說明一致)} 防止類和成員被移除或者被重命名
keepclassmembers {modifier} {class_specification} 防止成員被移除或者被重命名
keepnames {class_specification} 防止成員被重命名)
keepclassmembernames {class_specification} 防止擁有該成員的類和成員被移除或者被重命名
keepclasseswithmembernames {class_specification} 防止擁有該成員的類和成員被重命名
(三)混淆的必須知道的一些規(guī)則
1泊脐、一般規(guī)則形式:
[命令] [類] {
[成員]
}
類:代表相關(guān)指定條件的類,例如
- 具體的類
- 訪問修飾符(
public
烁峭、protected
容客、private
) - 通配符
*
,匹配任意長(zhǎng)度字符约郁,但不含包名分隔符(.) - 通配符
**
缩挑,匹配任意長(zhǎng)度字符,并且包含包名分隔符(.) -
extends
鬓梅,即可以指定類的基類 -
implement
供置,匹配實(shí)現(xiàn)了某接口的類 - $,內(nèi)部類
成員:代表指定類后符合指定條件的成員變量绽快,例如
- 匹配所有構(gòu)造器
- 匹配所有域
- 匹配所有方法
- 通配符
*
芥丧,匹配任意長(zhǎng)度字符紧阔,但不含包名分隔符(.) - 通配符
**
,匹配任意長(zhǎng)度字符续担,并且包含包名分隔符(.) - 通配符
***
擅耽,匹配任意參數(shù)類型 -
…
,匹配任意長(zhǎng)度的任意類型參數(shù)物遇。比如void test(…)就能匹配任意void test(String a)
或者是void test(int a, String b)
這些方法乖仇。 - 訪問修飾符(
public
、protected
询兴、private
)
舉個(gè)例子这敬,假如需要將name.huihui.test
包下所有繼承Activity
的public
類及其構(gòu)造函數(shù)都保持住,可以這樣寫:
-keep public class name.huihui.test.** extends Android.app.Activity {
<init>
}
2蕉朵、常用自定義混淆規(guī)則
- 不混淆某個(gè)類
-keep public class name.huihui.example.Test { *; }
- 不混淆某個(gè)包所有的類
-keep class name.huihui.test.** { *; }
- 不混淆某個(gè)類的子類
-keep public class * extends name.huihui.example.Test { *; }
- 不混淆所有類名中包含了“model”的類及其成員
-keep public class **.*model*.** {*;}
- 不混淆某個(gè)接口的實(shí)現(xiàn)
-keep class * implements name.huihui.example.TestInterface { *; }
- 不混淆某個(gè)類的構(gòu)造方法
-keepclassmembers class name.huihui.example.Test {
public <init>();
}
- 不混淆某個(gè)類的特定的方法
-keepclassmembers class name.huihui.example.Test {
public void test(java.lang.String);
}
五、自定義資源保持規(guī)則
前面說的通過shrinkResources true開啟資源壓縮后阳掐,未被使用的資源默認(rèn)不會(huì)被打包進(jìn)去始衅。如果開發(fā)者是自定義保留指定的資源文件,可以在res/raw/
路徑下創(chuàng)建一個(gè) xml 文件缭保,例如 keep.xml
汛闸,進(jìn)行自定義混淆規(guī)則。
一般屬性有:
-
tools:keep
定義哪些資源需要被保留(資源之間用“,”隔開) -
tools:discard
定義哪些資源需要被移除(資源之間用“,”隔開) -
tools:shrinkMode
開啟嚴(yán)格模式
例如:
<?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"/>
最后感謝@ 光源coder提供的混淆手冊(cè)艺骂,總結(jié)的不錯(cuò)~
希望對(duì)有些開發(fā)者有幫助具體查看可以github上的demo诸老,也歡迎加入開發(fā)交流群哈,詳情看個(gè)人簡(jiǎn)介钳恕。下一篇是對(duì)gradle的混淆說明别伏,歡迎讀者閱讀
DEMO
Gradle For Android(四)Gradle編譯中神秘的混淆
傻小孩b mark共勉,寫給在成長(zhǎng)路上奮斗的你