Android R8代碼混淆

?Android Gradle插件升級至3.4.0版本之后,帶來一個新特性-新一代混淆工具R8,做為D8的升級版替代Proguard;在應用壓縮、應用優化方面提供更極致的體驗。

R8 和 Proguard

?R8 一步到位地完成了所有的縮減(shrinking),去糖(desugaring)和 轉換成 Dalvik 字節碼(dexing )過程。

縮減(shrinking)過程實現以下三個重要的功能:

  • 代碼縮減:從應用及其庫依賴項中檢測并安全地移除未使用的類、字段、方法和屬性。
  • 資源縮減:從封裝應用中移除不使用的資源,包括應用庫依賴項中的不使用的資源。
  • 優化:檢查并重寫代碼,以進一步減小應用的 DEX 文件的大小。
  • 混淆:縮短類和成員的名稱,從而減小 DEX 文件的大小。

?R8 和當前的代碼縮減解決方案 Proguard 相比,R8 可以更快地縮減代碼,同時改善輸出大小。下面將通過幾張數據圖來對比(數據源自于 benchmark):


shrinkingTime.png
dexSize.png

apkSize.png

R8混淆使用

?R8的使用非常簡單,使用方式與Proguard并無差異,Android Studio創建項目時默認是關閉的,因為這會加長工程打包時間,所以開發階段不建議開啟。開啟方式如下:

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

?可以看到gradle中加載了兩個混淆配置文件, 其中 proguard-rules.pro 供開發者自定義混淆規則;proguard-android-optimize.txt 這是默認的配置文件,包含一些通用的混淆規則,在sdk/tools/proguard目錄下,其中包含的內容如下:

# 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常用規則

關閉壓縮

-dontshrink

關閉代碼優化

-dontoptimize

關閉混淆

-dontobfuscate

指定代碼優化級別,值在0-7之間,默認為5

-optimizationpasses 5

混淆時不使用大小寫混合類名

-dontusemixedcaseclassnames

不忽略庫中的非public的類

-dontskipnonpubliclibraryclasses

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

-dontskipnonpubliclibraryclassmembers

輸出詳細信息

-verbose

不做預校驗,預校驗是作用在Java平臺上的,Android平臺上不需要這項功能,去掉之后還可以加快混淆速度

-dontpreverify

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

-keep class com.xy.myapp*

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

-keep class com.xy.myapp**

保持指定包下的類名以及類里面的內容

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

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

-keep public class * extends android.app.Activity

其它keep方法:

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

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

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

保持指定類的所有方法

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

保持指定類的所有字段

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

保持指定類的所有構造器

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

保持用指定參數作為形參的方法

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

類文件除了定義類,字段,方法外,還為它們附加了一些屬性,例如注解,異常,行號等,優化操作會刪除不必要的屬性,使用-keepattributes可以保留指定的屬性

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

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

-dontwarn com.squareup.okhttp.**

常用混淆模版

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

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

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

# 避免混淆Annotation、內部類、泛型、匿名類
-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下的所有類及其內部類
-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);
}

# 保持所有實現 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構建項目后會在模塊下的build\outputs\mapping\release文件夾下輸出下列文件:

  • dump.txt:說明 APK 中所有類文件的內部結構。
  • mapping.txt:提供原始與混淆過的類、方法和字段名稱之間的轉換。
  • seeds.txt:列出未進行混淆的類和成員。
  • usage.txt:列出從 APK 移除的代碼。

必須保持的代碼

  • AndroidManifest.xml引用的類。
  • JNI調用的方法。
  • 反射用到的類。
  • WebView中JavaScript使用的類。
  • Layout文件引用的自定義View。

混淆心得

?我們在開發過程中,可以先記錄下必須保持的類及方法,后面在做混淆時,維度可以不用做的那么細致,當然如果有安全、規范要求,那就還是一步一步的走吧。只要細心一點,混淆并不復雜。

參考文章

混淆壓縮官方指導文檔
Android代碼壓縮工具R8詳解
Android使用R8壓縮,混淆,優化App

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容

  • “風送花香紅滿地,雨滋春樹碧連天。”是的,世界很美,不僅是因為有春的煙波畫船,有夏的朝云暮卷,有秋的云霞絢爛,有冬...
    十四橋閱讀 686評論 0 5
  • 【日精進打卡第18天】 515期反省二組(寧波) 【知~學習】 1:誦讀六項精進大綱共164遍; 2: 誦讀六項精...
    雨澤之字閱讀 173評論 0 0
  • 雨來了, 別憂郁, 人生四季漫漫旅途, 那有不遇風雨。 雨來了, 別憂郁, 疾風驟雨雖然吹落花枝, 也必將催生新的...
    小蜜蜂耶閱讀 82評論 2 2