Android Proguard混淆打包經驗總結

mlc0202 8年前發布 | 22K 次閱讀 Java 安卓開發 Android開發 移動開發

作為一名 Android 開發,應該了解并嘗試給自己的項目進行Proguard混淆打包。項目經過Proguard混淆打包后,會發現apk包體積會變小,也就是混淆可以使得apk瘦身;并且反編譯apk的時候會發現, 項目中的源碼都被處理過,進一步保障了apk的安全;這就是我所理解的Proguard混淆打包的兩個優點。不過,想要真正給自己的項目進行Proguard混淆打包,可不是一件容易的事情,真正嘗試去做了,才會發現有好多問題需要去解決,畢竟,混淆打包是針對特定的項目,每個項目需要混淆的代碼都是有區別的。不過,所有apk混淆打包,也有一些通用的規則處理,像這些規則,就可以自己記錄下來,這樣其他項目混淆打包的時候就可以復制粘貼使用混淆代碼了。好了,進入正題,如何給自己的項目量身定制一套Proguard混淆代碼了?

關于Proguard混淆,給APP瘦身,Google官方也給出了文檔給了大致解釋,大家有興趣可以看看,純英文(夠嗆),不過怎么在Android Studio配置Proguard混淆,還是可以看懂的:

我們可以從這些方面對apk瘦身:

1)冗余的代碼,比如多余的jar包代碼;

2)未使用的靜態代碼;

3)資源代碼的冗余;

4)native code

5)圖片資源的優化和壓縮

ProGuard混淆打包,解決的問題主要針對第一點,一般項目進行ProGuard混淆打包后,apk的體積會減小200-500KB左右。

一、在Android Studio中配置Proguard混淆

buildTypes {
        release {
            //混淆
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

配置很簡單,只需要把minifyEnabled的狀態改成true即可,然后,當進行apk打包時,編譯工具首先會讀取proguar-rules.pro文件。所有混淆規則,即項目的專屬混淆配置代碼就寫在該文件里面。

二、編寫ProGuard文件

proguar-rules.pro文件目錄位置

1、ProGuard混淆配置文件通用配置

這里形容的通用配置,也就是需要添加一些不需要混淆的代碼,比如Android的四大組件的相關代碼,自定義View相關代碼,項目中引用的第三方jar包相關代碼等等;

1)ProGuadr混淆代碼屬性配置代碼

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-dontwarn
-dontskipnonpubliclibraryclassmembers
-ignorewarnings
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*


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

# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}


# 泛型與反射
-keepattributes Signature
-keepattributes EnclosingMethod
-keepattributes *Annotation*

以上屬性基本配置代碼中,配置了ProGuard混淆代碼壓縮比例等基本屬性,配置了本地native方法、泛型與反射、注解、內部類、異常處理等相關代碼的混淆配置,保證這些相關的代碼不被混淆,基本上所有項目都可以通用。

1)四大組件ProGuard配置代碼

-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
-keep public class * extends android.os.IInterface

2)項目中的activity、constants、model、bean等混淆配置

比如我的項目結構如下

針對我的項目配置相關配置代碼如下:

-keep class com.example.proguard.model.** {*;}
-keep class com.example.proguard.activity.** {*;}
-keep class com.example.proguard.adapter.** {*;}
-keep class com.example.proguard.constants.**{*;}
-keep class com.example.proguard.base.**{*;}
-keep class com.example.proguard.model.**{*;}
-keep class com.example.proguard.service.**{*;}
-keep class com.example.proguard.weidgt.**{*;}
-keep class com.example.proguard.utils.** {*;}
-keep class com.example.proguard.network.api** {*;}

3)第三方jar包混淆配置代碼

比如我的項目中涉及到的第三方jar包如下:

compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.0.0'
    compile 'com.android.support:design:23.1.1'
    compile 'com.squareup.okhttp3:okhttp:3.2.0'
    compile 'com.squareup.retrofit2:retrofit:2.0.0'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
    compile 'com.jakewharton:butterknife:7.0.1'
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'io.reactivex:rxandroid:1.1.0'
    compile 'io.reactivex:rxjava:1.0.10'
    compile 'com.jakewharton.rxbinding:rxbinding:0.4.0'
    compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.4.0'
    compile 'com.jakewharton.rxbinding:rxbinding-design:0.4.0'
    compile 'com.非死book.fresco:fresco:0.8.1+'
    compile 'com.非死book.fresco:drawee:0.5.0+'
    compile 'com.非死book.fresco:fbcore:0.5.0+'
    compile 'com.非死book.fresco:imagepipeline:0.5.0+'
    compile 'com.google.code.gson:gson:2.7'
    compile 'com.orhanobut:logger:1.8'
    compile 'com.非死book.stetho:stetho:1.3.1'
    compile 'de.greenrobot:greendao:1.3.7'
    //  時間日期選擇控件 里面包含nineold動畫jar包
    compile 'com.github.flavienlaurent.datetimepicker:library:0.0.2'
    //Android 6.0f權限檢查
    compile 'gun0912.ted:tedpermission:1.0.0'

我需要的ProGuard配置代碼如下:

#保持第3方jar包不混淆
-keep class com.alibaba.sdk.android.** {*;}
-keep class com.squareup.okhttp.** {*;}
-keep class com.squareup.okhttp3.** {*;}
-keep class com.squareup.retrofit2.** {*;}
-keep class com.jakewharton.** {*;}
-keep class io.reactivex.** {*;}
-keep class rx.** {*;}
-keep class com.jakewharton.rxbinding.** {*;}
-keep class com.非死book.** {*;}
-keep class com.butterknife.** {*;}
-keep class com.google.code.gson.** {*;}
-keep class com.orhanobut.** {*;}
-dontwarn de.greenrobot.daogenerator.**
-keep class de.greenrobot.** {*;}
-keep class com.github.flavienlaurent.datetimepicker.** {*;}
-keep class gun0912.ted.** {*;}

4)針對support4包的配置

-dontwarn android.support.**
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v4.app.Fragment

針對supportv7包的配置一樣

5)針對butterknife的配置

#####butterknife#######
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-dontwarn butterknife.**
-keepclasseswithmembernames class * {
    @butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
    @butterknife.* <methods>;
}

6)針對gson的配置

-keep class com.google.gson.** {*;}
#-keep class com.google.**{*;}
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.google.** {
    ;
    ;
}
-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();
}
-dontwarn com.google.gson.**

7)針對greenDao數據庫的配置

-keep class de.greenrobot.dao.** {*;}
#保持greenDao的方法不被混淆 用來保持生成的表名不被混淆
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
 public static java.lang.String TABLENAME;
}
 -keep class **$Properties

8)針對okhttp的配置

# OkHttp
-dontwarn com.squareup.okhttp.**
-keep class com.squareup.okhttp.** {*;}
-keep interface com.squareup.okhttp.** {*;}
-dontwarn okio.**

等等,針對某個jar包的具體混淆配置,大家可以去Google,這里我就列舉這些了。

至此,針對你項目的專屬ProGuard配置文件就出來了,打個正式包看看apk包有沒有瘦身吧。

三、ProGuard混淆打包過程的問題

當你配置好項目的ProGuard文件后,打包過程可能就報錯了,這些錯誤需要我們一一去解決,這里列出幾個我在打包過程遇到的幾個錯誤及解決方法:

1) java.lang.UnsupportedOperationException: Unknown ASTNode child: LambdaExpression

2)如果配置好ProGuard文件后,并且打包也順利進行,打包成功了,但是當你運行瘦身后的apk,會發現apk會出現崩潰的情況,如果出現這種情況,說明配置的ProGuard文件還有問題,有些地方的代碼混淆配置還需要更改,這時候就需要我們定位到具體報錯的代碼位置了,去發現并定位混淆配置錯誤的代碼。Android Studio在debug模式下運行的程序,是沒有經過ProGuard混淆配置的,所以我們沒法通過debug模式定位混淆出錯的位置。但是我們該如何定位到代碼崩潰的代碼位置了,解決的方法就是在debug模式下,我們也讓程序跑ProGuard文件,進行debug模式下的混淆打包。

buildTypes {
        release {
            //混淆
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug{
            //混淆
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

這樣,在debug模式下,就可以定位到程序崩潰或異常的代碼了,進而可以查詢到混淆配置錯誤的代碼進行修改調整。

好了,以上就是我在項目中配置ProGuard文件的經驗總結,希望大家也能針對自己的項目做一份特制的ProGuard文件,讓apk瘦身成功。

 

來自:http://www.androidchina.net/5678.html

 

 本文由用戶 mlc0202 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!