Android使用R8壓縮煤杀,混淆眷蜈,優(yōu)化App

在Android開發(fā)中,為了使App盡可能小沈自,可以使用R8來壓縮端蛆,混淆,優(yōu)化App酥泛,當(dāng)使用Android Gradle插件3.4.0或更高版本時今豆,插件不再使用ProGuard執(zhí)行優(yōu)化而是R8。

R8的功能

  • 代碼壓縮:安全地從App及其庫依賴項中刪除未使用的類柔袁,字段呆躲,方法和屬性。
  • 資源壓縮:從打包的App中刪除未使用的資源捶索,包括應(yīng)用程序庫依賴項中未使用的資源插掂。它與代碼壓縮一起使用,這樣一旦刪除了未使用的代碼腥例,也可以安全地刪除不再引用的資源辅甥。
  • 代碼混淆:使用簡短無意義的名稱重命名代碼里的類,字段和方法燎竖,從而減少DEX文件大小璃弄。
  • 代碼優(yōu)化:刪除未使用的代碼或重寫代碼使其更簡潔。

R8 和 Proguard

R8和Proguard 相比构回,R8 可以更快地縮減代碼夏块,同時改善輸出大小,R8 默認(rèn)處于啟用狀態(tài)纤掸,你可將以下代碼添加到項目的 gradle.properties 文件以停用 R8:

android.enableR8=false

R8 普通模式是兼容 Proguard的脐供,R8 完全模式與會啟用一些額外的優(yōu)化,這個時候可能需要一些其它ProGuard規(guī)則以避免運(yùn)行時問題借跪,可以在 項目的gradle.properties 文件中設(shè)置以下內(nèi)容啟用完全模式政己。

android.enableR8.fullMode=true

啟用壓縮,混淆掏愁,優(yōu)化

使用Android Studio創(chuàng)建新項目時歇由,默認(rèn)情況下不啟用壓縮,混淆托猩,優(yōu)化印蓖,因為這會增加項目的構(gòu)建時間,而且有些代碼混淆后會出錯京腥。要想啟用這些功能赦肃,需要在項目的build.gradle包含下面的內(nèi)容。

getDefaultProguardFile('proguard-android.txt') 方法可從 Android SDK tools/proguard/ 文件夾獲取默認(rèn)的 ProGuard規(guī)則文件公浪。

proguard-rules.pro文件用于添加自定義 ProGuard 規(guī)則他宛。默認(rèn)情況下,該文件位于模塊根目錄欠气。

android {
    buildTypes {
        release {
            //啟用代碼壓縮厅各,混淆,優(yōu)化
            minifyEnabled true

            //啟用資源壓縮
            shrinkResources true

            //ProGuard規(guī)則文件
            proguardFiles getDefaultProguardFile(
                    'proguard-android-optimize.txt'),
                    'proguard-rules.pro'
        }
    }
    ...
}

自定義要保留的資源

如果您有想要保留或舍棄的特定資源预柒,請在您的項目中創(chuàng)建一個包含 <resources> 標(biāo)記的 XML 文件队塘,并在 tools:keep 屬性中指定每個要保留的資源袁梗,在 tools:discard 屬性中指定每個要舍棄的資源。這兩個屬性都接受逗號分隔的資源名稱列表憔古。您可以使用星號字符作為通配符遮怜。

<?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" />

嚴(yán)格壓縮模式

如果你的代碼或庫代碼(例如AppCompat)調(diào)用了Resources.getIdentifier(),這就表示你的代碼將根據(jù)動態(tài)生成的字符串查詢資源名稱鸿市,默認(rèn)情況下資源壓縮器會采取防御性行為锯梁,將所有具有匹配名稱格式的資源標(biāo)記為可能已使用,無法移除焰情。例如陌凳,以下代碼會使所有帶 img_ 前綴的資源標(biāo)記為已使用。

String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());

在 keep.xml 文件中將 shrinkMode 設(shè)置為 strict可以停用該防御性行為内舟,這個時候你必須用tools:keep 屬性手動保留這些資源合敦。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:shrinkMode="strict" />

合并重復(fù)資源

默認(rèn)情況下,Gradle 還會合并同名資源谒获,例如可能位于不同資源文件夾中的同名可繪制對象蛤肌。這一行為不受 shrinkResources 屬性控制,也無法停用批狱,因為在有多個資源匹配代碼查詢的名稱時裸准,有必要利用這一行為來避免錯誤。

只有在兩個或更多個文件具有完全相同的資源名稱赔硫、類型限定符時炒俱,才會進(jìn)行資源合并。

自定義要保持的代碼

在ProGuard規(guī)則文件中可以使用-keep保持特定代碼不被移除或混淆爪膊,或者向你想保持的代碼添加 @Keep 注解权悟,在類上添加 @Keep 可原樣保持整個類,在方法或字段上添加它可完整保持方法/字段(及其名稱)以及類名稱推盛。

-keep public class MyClass

必須保持的代碼

  • AndroidManifest.xml引用的類峦阁。
  • JNI調(diào)用的方法。
  • 反射用到的類耘成。
  • WebView中JavaScript使用的類榔昔。
  • Layout文件引用的自定義View。

常用ProGuard規(guī)則

關(guān)閉壓縮

-dontshrink

關(guān)閉代碼優(yōu)化瘪菌,默認(rèn)Proguard規(guī)則文件已包含

-dontoptimize

關(guān)閉混淆

-dontobfuscate

指定代碼優(yōu)化級別撒会,值在0-7之間,默認(rèn)為5

-optimizationpasses 5

混淆時不使用大小寫混合類名师妙,默認(rèn)Proguard規(guī)則文件已包含

-dontusemixedcaseclassnames

不忽略庫中的非public的類诵肛,默認(rèn)Proguard規(guī)則文件已包含

-dontskipnonpubliclibraryclasses

不忽略庫中的非public的類成員

-dontskipnonpubliclibraryclassmembers

輸出詳細(xì)信息,默認(rèn)Proguard規(guī)則文件已包含

-verbose

不做預(yù)校驗默穴,預(yù)校驗是作用在Java平臺上的怔檩,Android平臺上不需要這項功能拿愧,去掉之后還可以加快混淆速度启上,默認(rèn)Proguard規(guī)則文件已包含

-dontpreverify

保持指定包下的類名副砍,不包括子包下的類名

-keep class com.xy.myapp*

保持指定包下的類名抄肖,包括子包下的類名

-keep class com.xy.myapp**

保持指定包下的類名以及類里面的內(nèi)容

-keep class com.xy.myapp.* {*;}

保持所有繼承于指定類的類

-keep public class * extends android.app.Activity

其它keep方法:

保留 防止被移除或者被混淆 防止被混淆
類和類成員 -keep -keepnames
僅類成員 -keepclassmembers -keepclassmembernames
如果擁有某成員,保留類和類成員 -keepclasseswithmembers -keepclasseswithmembernames

如果我們要保留一個類中的內(nèi)部類不被混淆則需要用$符號许蓖,如下例子表示保持MyClass內(nèi)部類JavaScriptInterface中的所有public內(nèi)容。

-keepclassmembers class com.xy.myapp.MyClass$JavaScriptInterface {
   public *;
}

保持指定類的所有方法

-keep class com.xy.myapp.MyClass {
    public <methods>;
}

保持指定類的所有字段

-keep class com.xy.myapp.MyClass {
    public <fields>;
}

保持指定類的所有構(gòu)造器

-keep class com.xy.myapp.MyClass {
    public <init>;
}

保持用指定參數(shù)作為形參的方法

-keep class com.xy.myapp.MyClass {
    public <methods>(java.lang.String);
}

類文件除了定義類调衰,字段膊爪,方法外,還為它們附加了一些屬性嚎莉,例如注解米酬,異常,行號等趋箩,優(yōu)化操作會刪除不必要的屬性赃额,使用-keepattributes可以保留指定的屬性

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
                SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

使指定的類不輸出警告信息

-dontwarn com.squareup.okhttp.**

特殊ProGuard規(guī)則

由于enum類的特殊性,下面兩個方法會被反射調(diào)用叫确,默認(rèn)Proguard規(guī)則文件已經(jīng)處理跳芳。

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

Parcelable的子類和Creator靜態(tài)成員變量要保持,否則會產(chǎn)生Android.os.BadParcelableException異常竹勉,默認(rèn)Proguard規(guī)則文件已經(jīng)處理飞盆。

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

常用混淆模板

# 指定代碼的壓縮級別
-optimizationpasses 5     

# 不忽略庫中的非public的類成員
-dontskipnonpubliclibraryclassmembers 

# google推薦算法
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*

# 避免混淆Annotation、內(nèi)部類次乓、泛型吓歇、匿名類
-keepattributes *Annotation*,InnerClasses,Signature,EnclosingMethod

# 拋出異常時保留代碼行號
-keepattributes SourceFile,LineNumberTable

# 保持四大組件
-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.content.ContentProvider
-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

# 保持support下的所有類及其內(nèi)部類
-keep class android.support.** {*;}

# 保留繼承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**

# 保持自定義控件
-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);
}

# 保持所有實(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();
}


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

輸出文件

啟用R8或ProGuard構(gòu)建項目后會在模塊下的build\outputs\mapping\release文件夾下輸出下列文件:

  • dump.txt:說明 APK 中所有類文件的內(nèi)部結(jié)構(gòu)。
  • mapping.txt:提供原始與混淆過的類票腰、方法和字段名稱之間的轉(zhuǎn)換城看。
  • seeds.txt:列出未進(jìn)行混淆的類和成員。
  • usage.txt:列出從 APK 移除的代碼杏慰。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末测柠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子逃默,更是在濱河造成了極大的恐慌鹃愤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件完域,死亡現(xiàn)場離奇詭異软吐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吟税,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門凹耙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姿现,“玉大人,你說我怎么就攤上這事肖抱”傅洌” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵意述,是天一觀的道長提佣。 經(jīng)常有香客問我,道長荤崇,這世上最難降的妖魔是什么拌屏? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮术荤,結(jié)果婚禮上倚喂,老公的妹妹穿的比我還像新娘。我一直安慰自己瓣戚,他們只是感情好端圈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著子库,像睡著了一般舱权。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刚照,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天刑巧,我揣著相機(jī)與錄音,去河邊找鬼无畔。 笑死啊楚,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的浑彰。 我是一名探鬼主播恭理,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼郭变!你這毒婦竟也來了颜价?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤诉濒,失蹤者是張志新(化名)和其女友劉穎周伦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體未荒,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡专挪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寨腔。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡速侈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出迫卢,到底是詐尸還是另有隱情倚搬,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布乾蛤,位于F島的核電站每界,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏家卖。R本人自食惡果不足惜盆犁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望篡九。 院中可真熱鬧,春花似錦醋奠、人聲如沸榛臼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沛善。三九已至,卻和暖如春塞祈,著一層夾襖步出監(jiān)牢的瞬間金刁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工议薪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尤蛮,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓斯议,卻偏偏與公主長得像产捞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哼御,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容