1. 程式人生 > >在Android Studio中的混淆debug與release

在Android Studio中的混淆debug與release

一.有關混淆:

什麼是程式碼混淆

Java是一種跨平臺的、解釋型語言,Java原始碼編譯成中間“位元組碼”儲存於class檔案中。由於跨平臺的需要,Java位元組碼中包含了很多原始碼資訊,如變數名、方法名,並且通過這些名稱來訪問變數和方法,這些符號帶有許多語義資訊,很容易被反編譯成Java原始碼。為了防止這種現象,我們可以使用Java混淆器對Java位元組碼進行混淆。
混淆就是對釋出出去的程式進行重新組織和處理,使得處理後的程式碼與處理前程式碼完成相同的功能,而混淆後的程式碼很難被反編譯,即使反編譯成功也很難得出程式的真正語義。被混淆過的程式程式碼,仍然遵照原來的檔案格式和指令集,執行結果也與混淆前一樣,只是混淆器將程式碼中的所有變數、函式、類的名稱變為簡短的英文字母代號,在缺乏相應的函式名和程式註釋的情況下,即使被反編譯,也將難以閱讀。同時混淆是不可逆的,在混淆的過程中一些不影響正常執行的資訊將永久丟失,這些資訊的丟失使程式變得更加難以理解。
混淆器的作用不僅僅是保護程式碼,它也有精簡編譯後程序大小的作用。由於以上介紹的縮短變數和函式名以及丟失部分資訊的原因,編譯後jar檔案體積大約能減少25%,這對當前費用較貴的無線網路傳輸是有一定意義的。

二.在Android Studio中混淆做以下總結:

首先,需要在app/proguard-rules.pro檔案中,新增混淆檔案;

然後,在build.gradle中去開啟混淆:
buildTypes {  
        debug {  
            //啟用程式碼混淆  
            minifyEnabled true  
            //混淆規則配置檔案  
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
            //  
            signingConfig signingConfigs.debug  
        }  
        release {  
            //是否優化zip  
            zipAlignEnabled true  
            // 移除無用的resource檔案  
            shrinkResources true  
            //啟用程式碼混淆  
            minifyEnabled true  
            //混淆規則配置檔案  
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
            //  
            signingConfig signingConfigs.release  
        }  
    }


三.混淆模版:

-optimizationpasses 5          # 指定程式碼的壓縮級別
-dontusemixedcaseclassnames   # 是否使用大小寫混合
-dontpreverify           # 混淆時是否做預校驗
-verbose                # 混淆時是否記錄日誌

-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*  # 混淆時所採用的演算法

-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    # 保持哪些類不被混淆

# 保留support下的所有類及其內部類
-keep class android.support.** {*;}	
# 保留R下面的資源
-keep class **.R$* {*;}

-keepclasseswithmembernames class * {  # 保持 native 方法不被混淆
    native <methods>;
}
-keepclasseswithmembers class * {   # 保持自定義控制元件類不被混淆
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {# 保持自定義控制元件類不被混淆
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity { # 保持自定義控制元件類不被混淆
    public void *(android.view.View);
}
-keepclassmembers enum * {     # 保持列舉 enum 類不被混淆
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆
    public static final android.os.Parcelable$Creator *;
}
-dontwarn android.net.**  #忽略某個包的警告
-keep class android.net.SSLCertificateSocketFactory{*;}
-keepattributes *Annotation*

-keep class xx   #保持自己定義的類不被混淆(如json,model,webview等等)


#第三方依賴庫不被混淆(部分)
(對於引用第三方庫的情況,可以採用下面方式避免打包出錯:
  -dontwarn com.xx.yy.**    
  -keep class com.xx.yy.** { *;}
《引數來保持第三方庫中的類而不亂,-dontwarn和-keep 結合使用,意思是保持com.xx.yy.**這個包裡面的所有類和所有方法而不混淆,接著還叫ProGuard不要警告找不到com.xx.yy.**這個包裡面的類的相關引用。
》) #Gson #如果有用到Gson解析包的,直接新增下面這幾行就能成功混淆,不然會報錯。 -keepattributes Signature # Gson specific classes -keep class sun.misc.Unsafe { *; } # Application classes that will be serialized/deserialized over Gson -keep class com.google.gson.** { *; } -keep class com.google.gson.stream.** { *; } #高德定位 -dontwarn com.amap.api.** -keep class com.amap.api.** {*;} #Fresco -dontwarn com.facebook.** -keep class com.facebook.** {*;} #科大訊飛 -dontwarn com.iflytek.** -keep class com.iflytek.** {*;}

四.在混淆過程中出現的問題:

混淆release打包後,執行出現crach,並報錯:
java.lang.SecurityException: Permission Denial: get/set setting for user asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
                                                    at com.android.server.am.ActivityManagerService.handleIncomingUser(ActivityManagerService.java:13175)
                                                    at android.app.ActivityManager.handleIncomingUser(ActivityManager.java:2044)
                                                    at com.android.providers.settings.SettingsProvider.callFromPackage(SettingsProvider.java:615)
                                                    at android.content.ContentProvider$Transport.call(ContentProvider.java:279)
                                                    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:273)
                                                    at android.os.Binder.execTransact(Binder.java:388)
                                                    at dalvik.system.NativeStart.run(Native Method)



百度這個問題許久都沒有得出解決辦法,後來在同學的幫助下給出思路,先在debug模式下混淆執行,看看有問題否,能不能成功。

結果按此方法,在執行下發現問題,去除錯誤的混淆,解決掉問題,最終混淆release打包成功。

注意:混淆出錯80%是因為你混淆了不該混淆的類!!