Android R8代碼混淆

?Android Gradle插件升級(jí)至3.4.0版本之后,帶來(lái)一個(gè)新特性-新一代混淆工具R8阁猜,做為D8的升級(jí)版替代Proguard颗味;在應(yīng)用壓縮、應(yīng)用優(yōu)化方面提供更極致的體驗(yàn)些膨。

R8 和 Proguard

?R8 一步到位地完成了所有的縮減(shrinking),去糖(desugaring)和 轉(zhuǎn)換成 Dalvik 字節(jié)碼(dexing )過(guò)程钦铺。

縮減(shrinking)過(guò)程實(shí)現(xiàn)以下三個(gè)重要的功能:

  • 代碼縮減:從應(yīng)用及其庫(kù)依賴項(xiàng)中檢測(cè)并安全地移除未使用的類(lèi)订雾、字段、方法和屬性矛洞。
  • 資源縮減:從封裝應(yīng)用中移除不使用的資源洼哎,包括應(yīng)用庫(kù)依賴項(xiàng)中的不使用的資源。
  • 優(yōu)化:檢查并重寫(xiě)代碼,以進(jìn)一步減小應(yīng)用的 DEX 文件的大小噩峦。
  • 混淆:縮短類(lèi)和成員的名稱锭沟,從而減小 DEX 文件的大小。

?R8 和當(dāng)前的代碼縮減解決方案 Proguard 相比识补,R8 可以更快地縮減代碼族淮,同時(shí)改善輸出大小。下面將通過(guò)幾張數(shù)據(jù)圖來(lái)對(duì)比(數(shù)據(jù)源自于 benchmark):


shrinkingTime.png
dexSize.png

apkSize.png

R8混淆使用

?R8的使用非常簡(jiǎn)單凭涂,使用方式與Proguard并無(wú)差異祝辣,Android Studio創(chuàng)建項(xiàng)目時(shí)默認(rèn)是關(guān)閉的,因?yàn)檫@會(huì)加長(zhǎng)工程打包時(shí)間切油,所以開(kāi)發(fā)階段不建議開(kāi)啟较幌。開(kāi)啟方式如下:

buildTypes {
        release {
            // 啟用代碼收縮、混淆和優(yōu)化白翻。
            minifyEnabled true
            // 啟用資源縮減
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

?可以看到gradle中加載了兩個(gè)混淆配置文件, 其中 proguard-rules.pro 供開(kāi)發(fā)者自定義混淆規(guī)則绢片;proguard-android-optimize.txt 這是默認(rèn)的配置文件滤馍,包含一些通用的混淆規(guī)則,在sdk/tools/proguard目錄下底循,其中包含的內(nèi)容如下:

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
#
# This file is no longer maintained and is not used by new (2.2+) versions of the
# Android plugin for Gradle. Instead, the Android plugin for Gradle generates the
# default rules at build time and stores them in the build directory.

# Optimizations: If you don't want to optimize, use the
# proguard-android.txt configuration file instead of this one, which
# turns off the optimization flags.  Adding optimization introduces
# certain risks, since for example not all optimizations performed by
# ProGuard works on all versions of Dalvik.  The following flags turn
# off various optimizations known to have issues, but the list may not
# be complete or up to date. (The "arithmetic" optimization can be
# used if you are only targeting Android 2.0 or later.)  Make sure you
# test thoroughly if you go this route.
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 5
-allowaccessmodification
-dontpreverify

# The remainder of this file is identical to the non-optimized version
# of the Proguard configuration file (except that the other file has
# flags to turn off optimization).

-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose

-keepattributes *Annotation*
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
    native <methods>;
}

# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

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

-keepclassmembers class **.R$* {
    public static <fields>;
}

# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version.  We know about them, and they are safe.
-dontwarn android.support.**

# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep

-keep @android.support.annotation.Keep class * {*;}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <methods>;
}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <fields>;
}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <init>(...);
}

ProGuard常用規(guī)則

關(guān)閉壓縮

-dontshrink

關(guān)閉代碼優(yōu)化

-dontoptimize

關(guān)閉混淆

-dontobfuscate

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

-optimizationpasses 5

混淆時(shí)不使用大小寫(xiě)混合類(lèi)名

-dontusemixedcaseclassnames

不忽略庫(kù)中的非public的類(lèi)

-dontskipnonpubliclibraryclasses

不忽略庫(kù)中的非public的類(lèi)成員

-dontskipnonpubliclibraryclassmembers

輸出詳細(xì)信息

-verbose

不做預(yù)校驗(yàn)熙涤,預(yù)校驗(yàn)是作用在Java平臺(tái)上的阁苞,Android平臺(tái)上不需要這項(xiàng)功能,去掉之后還可以加快混淆速度

-dontpreverify

保持指定包下的類(lèi)名祠挫,不包括子包下的類(lèi)名

-keep class com.xy.myapp*

保持指定包下的類(lèi)名那槽,包括子包下的類(lèi)名

-keep class com.xy.myapp**

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

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

保持所有繼承于指定類(lèi)的類(lèi)

-keep public class * extends android.app.Activity

其它keep方法:

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

如果我們要保留一個(gè)類(lèi)中的內(nèi)部類(lèi)不被混淆則需要用$符號(hào)等舔,如下例子表示保持MyClass內(nèi)部類(lèi)JavaScriptInterface中的所有public內(nèi)容骚灸。

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

保持指定類(lèi)的所有方法

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

保持指定類(lèi)的所有字段

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

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

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

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

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

類(lèi)文件除了定義類(lèi),字段慌植,方法外甚牲,還為它們附加了一些屬性,例如注解蝶柿,異常丈钙,行號(hào)等,優(yōu)化操作會(huì)刪除不必要的屬性交汤,使用-keepattributes可以保留指定的屬性

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

使指定的類(lèi)不輸出警告信息

-dontwarn com.squareup.okhttp.**

常用混淆模版

# 指定代碼的壓縮級(jí)別
-optimizationpasses 5     

# 不忽略庫(kù)中的非public的類(lèi)成員
-dontskipnonpubliclibraryclassmembers 

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

# 避免混淆Annotation雏赦、內(nèi)部類(lèi)、泛型、匿名類(lèi)
-keepattributes *Annotation*,InnerClasses,Signature,EnclosingMethod

# 拋出異常時(shí)保留代碼行號(hào)
-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下的所有類(lèi)及其內(nèi)部類(lè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 接口的類(lèi)成員
-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構(gòu)建項(xiàng)目后會(huì)在模塊下的build\outputs\mapping\release文件夾下輸出下列文件:

  • dump.txt:說(shuō)明 APK 中所有類(lèi)文件的內(nèi)部結(jié)構(gòu)喉誊。
  • mapping.txt:提供原始與混淆過(guò)的類(lèi)邀摆、方法和字段名稱之間的轉(zhuǎn)換。
  • seeds.txt:列出未進(jìn)行混淆的類(lèi)和成員伍茄。
  • usage.txt:列出從 APK 移除的代碼栋盹。

必須保持的代碼

  • AndroidManifest.xml引用的類(lèi)。
  • JNI調(diào)用的方法敷矫。
  • 反射用到的類(lèi)例获。
  • WebView中JavaScript使用的類(lèi)。
  • Layout文件引用的自定義View曹仗。

混淆心得

?我們?cè)陂_(kāi)發(fā)過(guò)程中榨汤,可以先記錄下必須保持的類(lèi)及方法,后面在做混淆時(shí)怎茫,維度可以不用做的那么細(xì)致收壕,當(dāng)然如果有安全、規(guī)范要求轨蛤,那就還是一步一步的走吧蜜宪。只要細(xì)心一點(diǎn),混淆并不復(fù)雜祥山。

參考文章

混淆壓縮官方指導(dǎo)文檔
Android代碼壓縮工具R8詳解
Android使用R8壓縮圃验,混淆,優(yōu)化App

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缝呕,一起剝皮案震驚了整個(gè)濱河市澳窑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌供常,老刑警劉巖摊聋,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異话侧,居然都是意外死亡栗精,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)瞻鹏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悲立,“玉大人,你說(shuō)我怎么就攤上這事新博⌒较Γ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵赫悄,是天一觀的道長(zhǎng)原献。 經(jīng)常有香客問(wèn)我馏慨,道長(zhǎng),這世上最難降的妖魔是什么姑隅? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任写隶,我火速辦了婚禮,結(jié)果婚禮上讲仰,老公的妹妹穿的比我還像新娘慕趴。我一直安慰自己,他們只是感情好鄙陡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布冕房。 她就那樣靜靜地躺著,像睡著了一般趁矾。 火紅的嫁衣襯著肌膚如雪耙册。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天毫捣,我揣著相機(jī)與錄音详拙,去河邊找鬼。 笑死蔓同,一個(gè)胖子當(dāng)著我的面吹牛溪厘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牌柄,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼侧甫!你這毒婦竟也來(lái)了珊佣?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤披粟,失蹤者是張志新(化名)和其女友劉穎咒锻,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體守屉,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡惑艇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拇泛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滨巴。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖俺叭,靈堂內(nèi)的尸體忽然破棺而出恭取,到底是詐尸還是另有隱情,我是刑警寧澤熄守,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布蜈垮,位于F島的核電站耗跛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏攒发。R本人自食惡果不足惜调塌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惠猿。 院中可真熱鬧羔砾,春花似錦、人聲如沸紊扬。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)餐屎。三九已至檀葛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腹缩,已是汗流浹背屿聋。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藏鹊,地道東北人润讥。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像盘寡,于是被迫代替她去往敵國(guó)和親楚殿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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

  • “風(fēng)送花香紅滿地竿痰,雨滋春樹(shù)碧連天脆粥。”是的影涉,世界很美变隔,不僅是因?yàn)橛写旱臒煵ó?huà)船,有夏的朝云暮卷蟹倾,有秋的云霞絢爛匣缘,有冬...
    十四橋閱讀 664評(píng)論 0 5
  • 【日精進(jìn)打卡第18天】 515期反省二組(寧波) 【知~學(xué)習(xí)】 1:誦讀六項(xiàng)精進(jìn)大綱共164遍; 2: 誦讀六項(xiàng)精...
    雨澤之字閱讀 168評(píng)論 0 0
  • 雨來(lái)了鲜棠, 別憂郁肌厨, 人生四季漫漫旅途, 那有不遇風(fēng)雨豁陆。 雨來(lái)了夏哭, 別憂郁, 疾風(fēng)驟雨雖然吹落花枝献联, 也必將催生新的...
    小蜜蜂耶閱讀 77評(píng)論 2 2