性能優化總結4:組件化混淆需要注意的地方

1、混淆的好處
android studio 使用ProGuard來進行混淆,ProGuard是一個壓縮、優化和混淆java字節碼文件的工具,可以刪除無用的類,字段,方法和屬性,還可以刪除無用額註釋,最大限度的優化字節碼文件,規避64K方法數的問題,並且還可以使用剪短而且無意義的名字來重命名已經存在的類、字段、方法和屬性,增加逆向工程的難度。混淆可以減少APK文件的大小。
2、混淆包含:壓縮,優化,混淆,預校驗四個操作。
壓縮Shringking : 檢測和刪除無用的類,方法,字段和屬性
優化Optimize : 優化字節碼文件,刪除無用指令
混淆Obfuscation :使用無意義的名字來對類,字段,方法和屬性進行重命名
預校驗Preverification:對處理後的代碼進行校驗

proguard原理介紹可以看看proguard的官網
proguard
proguard流程:

3、build文件打開混淆

    buildTypes {
        release {
            minifyEnabled true		//打開混淆
            shrinkResources true	//打開資源壓縮
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//設置混淆文件的路徑,第一部分爲系統已經預先設置的混淆文件,第二部分是我們自己的混淆文件
        }
    }

當我們新建module的時候,是默認已經關閉混淆了的,要打開混淆只要設置minifyEnabled = true就可以

proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro

proguard-android.txt爲系統已經預先設置的混淆文件,proguard-rules.pro是我們自己的混淆文件

基本的混淆設置:

指定壓縮級別,0-7之間,默認爲5

-optimizationpasses 5

不使用大小寫混合類名,注意,windows用戶必須爲ProGuard指定該選項,因爲windows對文件的大小寫是不敏感的,也就是比如a.java和A.java會認爲是同一個文件。如果不這樣做並且你的項目中有超過26個類的話,那麼ProGuard就會默認混用大小寫文件名,導致class文件相互覆蓋。

-dontusemixedcaseclassnames

不跳過非公共的庫類

-dontskipnonpubliclibraryclasses

不跳過非公共的庫類的成員

-dontskipnonpubliclibraryclassmembers

指定不執行預檢,預校驗作用在Java平臺,android平臺不需要,所以去掉預校驗可以加快混淆速度

-dontpreverify

把所有信息都輸出,而不僅僅是輸出出錯信息

-verbose

輸出類名->混淆後類名的映射關係

-printmapping proguardMapping.txt

混淆時採用的算法

-optimizations !code/simplification/cast,!field/,!class/merging/

不混淆Annotation

-keepattributes Annotation,InnerClasses

不混淆泛型

-keepattributes Signature

保留行號

-keepattributes SourceFile,LineNumberTable

以下情況不能被混淆:

1.
反射中使用的元素,需要保證類名,方法名,屬性名不變,否則混淆後會反射不了
最好不要混淆bean對象
四大組件不建議混淆,自定義的Application不能被混淆,混淆以後類名會變,,而混淆後的類名沒有在manifest中註冊,所以不符合四大組件的註冊機制
外部程序可能使用組件的字符串類名,如果類名混淆,可能導致出現異常
-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
2.自定義view和自定義控件不能被混淆
-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);
}
3.枚舉類的values和valuesOf方法不能被混淆,因爲這兩個方法是靜態添加到代碼中運行,也會被反射使用,所以不能混淆這兩個方法
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
4.R類下面的資源不能被混淆
-keep class **.R$* {*;}
5.JNI調用java方法不能被混淆,需要通過類名和方法名構成的地址形成
6.webview中的js方法不能混淆
-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);
}
7.Java調用Native方法,Native方法是C/C++編寫的,方法是無法一同混淆的
-keepclasseswithmembernames class * {
    native <methods>;
}

8. 第三方庫建議使用其自身的混淆規則
9. Parcelable的子類和Creator的靜態成員變量不能混淆,否則序列化會出異常
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
10.保留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();
}
11.JS調用原生的方法不能被混淆
-keepattributes *JavascriptInterface*

以上是一些基本的不能被混淆的情況。
是不是有一種頭暈目眩的感覺呢?其實混淆不復雜,我們只需要記住一點:

混淆改變了Java路徑名,需要保持路徑名不變的不可以被混淆

只要牢記這個原則來添加自己不需要被混淆的類就可以啦。
另外support-annotation中提供了@Keep註解,可以保持類不被混淆,哪裏不想被混淆就"keep"那裏
proguard keep
要使用@Keep需要在proguard文件里加入:

-dontskipnonpubliclibraryclassmembers
-printconfiguration
-keep,allowobfuscation @interface android.support.annotation.Keep

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

那麼是否有更深層次的混淆呢?

ProGuard只能混淆java文件,實際上我們還可以混淆資源文件的文件路徑,其實質也是資源名的混淆。
這裏要提到AndResGuard混淆插件
github地址:
AndResGuard/README.zh-cn.md at master · shwenzhang/AndResGuard · GitHub
https://github.com/shwenzhang/AndResGuard/blob/master/README.zh-cn.md

它會重新修改apk的resource.arsc文件,不依賴源碼和編譯過程,可以使用zip壓縮。
具體的使用,大家可以參考官方git。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章