天天看點

Android Studio 代碼混淆

在Android studio 進行代碼混淆配置。

proguard 配置

-keepclasseswithmembers 指定的類和類成員被保留,假如指定的類成員存在的話。

-dontwarn 預設proguard 會檢查每一個引用是否正确,但是第三方庫裡面往往有些不會用到的類,沒有正确引用。如果不配置的話,系統就會報錯。

-keep 指定的類和類成員被保留作為 入口 。

-keepclassmembers 指定的類成員被保留。

proguard 問題和風險

代碼混淆後雖然有混淆優化的好處,但是它往往也會帶來如下的幾點問題

混淆錯誤,用到第三方庫的時候,必須告訴 proguard 不要檢查,否則proguard 會報錯。

運作錯誤,當code 不能混淆的時候,我們必須要正确配置,否則程式會運作出錯,這種情況問題最多。

調試苦難,出錯了,錯誤堆棧是混淆後的代碼 ,自己也看不懂。

不能混淆的代碼

下面這樣代碼混淆的時候要注意保留。

Android系統元件,系統元件有固定的方法被系統調用。

被Android Resource 檔案引用到的。名字已經固定,也不能混淆,比如自定義的View 

Android Parcelable ,需要使用android 序列化的。

Java序列化方法,系統序列化需要固定的方法。

枚舉 ,系統需要處理枚舉的固定方法

本地方法,不能修改本地方法名

annotations 注釋

資料庫驅動

有些resource 檔案

用到反射的地方

其他Anroid 官方建議 不混淆的,如

android.app.backup.BackupAgentHelper

android.preference.Preference

com.android.vending.licensing.ILicensingService

混淆配置

proguard 參數

-include {filename}    從給定的檔案中讀取配置參數 

-basedirectory {directoryname}    指定基礎目錄為以後相對的檔案名稱 

-injars {class_path}    指定要處理的應用程式jar,war,ear和目錄 

-outjars {class_path}    指定處理完後要輸出的jar,war,ear和目錄的名稱 

-libraryjars {classpath}    指定要處理的應用程式jar,war,ear和目錄所需要的程式庫檔案 

-dontskipnonpubliclibraryclasses    指定不去忽略非公共的庫類。 

-dontskipnonpubliclibraryclassmembers    指定不去忽略包可見的庫類的成員。 

保留選項 

-keep {Modifier} {class_specification}    保護指定的類檔案和類的成員 

-keepclassmembers {modifier} {class_specification}    保護指定類的成員,如果此類受到保護他們會保護的更好

-keepclasseswithmembers {class_specification}    保護指定的類和類的成員,但條件是所有指定的類和類成員是要存在。 

-keepnames {class_specification}    保護指定的類和類的成員的名稱(如果他們不會壓縮步驟中删除) 

-keepclassmembernames {class_specification}    保護指定的類的成員的名稱(如果他們不會壓縮步驟中删除) 

-keepclasseswithmembernames {class_specification}    保護指定的類和類的成員的名稱,如果所有指定的類成員出席(在壓縮步驟之後) 

-printseeds {filename}    列出類和類的成員-keep選項的清單,标準輸出到給定的檔案 

壓縮 

-dontshrink    不壓縮輸入的類檔案 

-printusage {filename} 

-whyareyoukeeping {class_specification}    

優化 

-dontoptimize    不優化輸入的類檔案 

-assumenosideeffects {class_specification}    優化時假設指定的方法,沒有任何副作用 

-allowaccessmodification    優化時允許通路并修改有修飾符的類和類的成員 

混淆 

-dontobfuscate    不混淆輸入的類檔案 

-printmapping {filename} 

-applymapping {filename}    重用映射增加混淆 

-obfuscationdictionary {filename}    使用給定檔案中的關鍵字作為要混淆方法的名稱 

-overloadaggressively    混淆時應用侵入式重載 

-useuniqueclassmembernames    确定統一的混淆類的成員名稱來增加混淆 

-flattenpackagehierarchy {package_name}    重新包裝所有重命名的包并放在給定的單一包中 

-repackageclass {package_name}    重新包裝所有重命名的類檔案中放在給定的單一包中 

-dontusemixedcaseclassnames    混淆時不會産生形形色色的類名 

-keepattributes {attribute_name,...}    保護給定的可選屬性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses. 

-renamesourcefileattribute {string}    設定源檔案中給定的字元串常量

在app檔案夾下的build.gradle檔案中修改buildTypes

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}      
在proguard_rules.pro檔案中編寫自己的proguard 混淆代碼,常用的混淆代碼如下:      
#指定代碼的壓縮級别
    -optimizationpasses 5
    
    #包明不混合大小寫
    -dontusemixedcaseclassnames
    
    #不去忽略非公共的庫類
    -dontskipnonpubliclibraryclasses
    
     #優化  不優化輸入的類檔案
    -dontoptimize
    
     #預校驗
    -dontpreverify
    
     #混淆時是否記錄日志
    -verbose
    
     # 混淆時所采用的算法
    -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
    
    #保護注解
    -keepattributes *Annotation*
    
    # 保持哪些類不被混淆
    -keep public class * extends android.app.Fragment
    -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 com.android.vending.licensing.ILicensingService
    #如果有引用v4包可以添加下面這行
    -keep public class * extends android.support.v4.app.Fragment
    
    
    
    #忽略警告
    -ignorewarning
    
    ##記錄生成的日志資料,gradle build時在本項目根目錄輸出##
    
    #apk 包内所有 class 的内部結構
    -dump class_files.txt
    #未混淆的類和成員
    -printseeds seeds.txt
    #列出從 apk 中删除的代碼
    -printusage unused.txt
    #混淆前後的映射
    -printmapping mapping.txt
    
    ########記錄生成的日志資料,gradle build時 在本項目根目錄輸出-end######
    
    
    #####混淆保護自己項目的部分代碼以及引用的第三方jar包library#######
    
    #-libraryjars libs/umeng-analytics-v5.2.4.jar
    
    #三星應用市場需要添加:sdk-v1.0.0.jar,look-v1.0.1.jar
    #-libraryjars libs/sdk-v1.0.0.jar
    #-libraryjars libs/look-v1.0.1.jar
    
    #如果不想混淆 keep 掉
    -keep class com.lippi.recorder.iirfilterdesigner.** {*; }
    #友盟
    -keep class com.umeng.**{*;}
    #項目特殊處理代碼
    
    #忽略警告
    -dontwarn com.lippi.recorder.utils**
    #保留一個完整的包
    -keep class com.lippi.recorder.utils.** {
        *;
     }
    
    -keep class  com.lippi.recorder.utils.AudioRecorder{*;}
    
    
    #如果引用了v4或者v7包
    -dontwarn android.support.**
    
    ####混淆保護自己項目的部分代碼以及引用的第三方jar包library-end####
    
    -keep public class * extends android.view.View {
        public <init>(android.content.Context);
        public <init>(android.content.Context, android.util.AttributeSet);
        public <init>(android.content.Context, android.util.AttributeSet, int);
        public void set*(...);
    }
    
    #保持 native 方法不被混淆
    -keepclasseswithmembernames class * {
        native <methods>;
    }
    
    #保持自定義控件類不被混淆
    -keepclasseswithmembers class * {
        public <init>(android.content.Context, android.util.AttributeSet);
    }
    
    #保持自定義控件類不被混淆
    -keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
    }
    
    #保持 Parcelable 不被混淆
    -keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
    }
    
    #保持 Serializable 不被混淆
    -keepnames class * implements java.io.Serializable
    
    #保持 Serializable 不被混淆并且enum 類也不被混淆
    -keepclassmembers class * implements java.io.Serializable {
        static final long serialVersionUID;
        private static final java.io.ObjectStreamField[] serialPersistentFields;
        !static !transient <fields>;
        !private <fields>;
        !private <methods>;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
    }
    
    #保持枚舉 enum 類不被混淆 如果混淆報錯,建議直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可
    #-keepclassmembers enum * {
    #  public static **[] values();
    #  public static ** valueOf(java.lang.String);
    #}
    
    -keepclassmembers class * {
        public void *ButtonClicked(android.view.View);
    }
    
    #不混淆資源類
    -keepclassmembers class **.R$* {
        public static <fields>;
    }
    
    #避免混淆泛型 如果混淆報錯建議關掉
    #–keepattributes Signature
    
    #移除log 測試了下沒有用還是建議自己定義一個開關控制是否輸出日志
    #-assumenosideeffects class android.util.Log {
    #    public static boolean isLoggable(java.lang.String, int);
    #    public static int v(...);
    #    public static int i(...);
    #    public static int w(...);
    #    public static int d(...);
    #    public static int e(...);
    #}
    
    #如果用用到Gson解析包的,直接添加下面這幾行就能成功混淆,不然會報錯。
    #gson
    #-libraryjars libs/gson-2.2.2.jar
    -keepattributes Signature
    # Gson specific classes
    -keep class sun.misc.Unsafe { *; }
    # Application classes that will be serialized/deserialized over Gson
    -keep class com.google.gson.examples.android.model.** { *; }
           

繼續閱讀