android proguard使用心得和遇到的若干問題以及解決思路。

今天決定對項目使用混淆工具proguard。因而便開始找proguard究竟放在sdk的什麼地方,果不其然,我在sdk目錄的tools文件夾中找到了proguard的文件夾。
配置方法這裏簡單的說明一下。
打開要混淆的android項目,找到project.properties文件。
後面添加上proguard.config=android.pro
如今我來解釋說明一下這句話,後面的android.pro是proguard的配置文件,主要是告訴proguard應該怎麼混淆文件。那麼這個配置文件在哪裏呢?
網上都是直接複製的,沒有追其根源。咱們能夠在前面提到的proguard的文件夾裏面,找到proguard-android.txt。這個是默認的混淆配置,已經針對android的代碼作了優化了,可是並無添加咱們本身的混淆邏輯。
java

這個文件就是我後面的android.pro。我是這麼作的,把該文件複製到項目中,而後修更名字爲android.pro。
所以也就是告訴各位這個文件的名字沒有硬性要求的,只要是正確的配置文件就能夠了。
android

以後就開始立馬簽名文件了,而後本身反編譯文件,發現裏面都是abcd的類名,不禁得很開心。 json

以後立馬開始安裝,果真就開始報錯了。這裏咱們要分析錯誤的來源,才能正確開始添加咱們本身編寫的的配置代碼到配置文件中。有些機子是直接就死機的,那麼咱們沒法看到錯誤報告,有些是有系統自帶report的報告,咱們能夠看到相關的堆棧錯誤。那麼怎麼解決直接死機崩潰,沒有堆棧日誌的狀況呢?咱們能夠鏈接機子到電腦,在eclipse中看到設備,而後讓它死機,那麼咱們一樣能夠再logcat中看到死機的緣由。 服務器

這裏要搞清楚,咱們不是debug模式,所以報出的錯誤都是這樣的 app

後面是unkonw source。由於咱們沒有關聯相關的代碼,所以是和開發模式是不一樣的,是看不到具體在第幾行的。不過好在咱們能夠知道是什麼方法的名字出現了異常。所以咱們能夠反編譯混淆過的代碼,查看和對比沒有混淆的代碼。發現問題所在,接下來咱們才能夠添加咱們本身的混淆配置。接下來,我要舉例說明遇到的問題,和解決的思路,供你們參考。 框架

1.解決案例一:下面看一下部分的代碼。 eclipse

public abstract class Model {
	@Column(name = "Id")
	private Long mId = null;
//下面這個函數是另外一個類裏面的
private Field getIdField(Class<?> type) {
		if (type.equals(Model.class)) {
			try {
				return type.getDeclaredField("mId");
			}
			catch (NoSuchFieldException e) {
				Log.e("Impossible!", e);
			}
		}
		else if (type.getSuperclass() != null) {
			return getIdField(type.getSuperclass());
		}

		return null;
	}

若是咱們直接的混淆的話,那麼mId確定會變成了abcd之類的詞彙。
而在下面的方法中出現了反射方法。 ide

type.getDeclaredField("mId");

那麼咱們在混淆以後確定會報錯的。而且返回一個null,筆者當時就是報了個空指針異常,程序的主要做用是查找指定類,發現它的id,並把具備該性質的類放入集合中。
很好,咱們發現了這個錯誤。下面咱們就開始添加以下的配置:
-keepclassmembernames class *******************.Model{
java.lang.Long mId;
}
上面的一連串*號是個人包名。
筆者一開始是這麼寫的。
-keepclassmembernames class *******************.Model{
Long mId;
}
後來查看了proguard文件夾下面examples文件夾下面的許多pro文件,發現了他們的共性,發現不是基本類型是不能這麼寫的。 函數

後來在混淆以後,在項目中發現了這麼個文件夾proguard。這個文件夾是混淆過程當中產生的相關的日誌文件。
你們能夠再mapping.txt文件中找到proguard究竟給你混淆了什麼,同時保留了什麼。我對上面的Model類嘗試了搜索,看看mId是否是混淆了,仍是說保留了。 工具

***********.Model -> com.a.d:
    java.lang.Long mId -> mId

結果搜索到這些語句
能夠看到Model類已經被混淆成com.a.d了。而咱們但願保留的mId,也確實沒有混淆了。

2.解決案例二:
因爲筆者的項目使用了fastjson框架,發如今解析從服務器下來的數據的時候發生了異常。
你們都知道json數據裏面的成員變量是有具體的含義的,好比{username:'xiaoming',password:'dddddddd'};
而我本身寫的model,裏面對應的username確定是混淆的。所以咱們要解析json數據,確定是不但願它被混淆的。
所以咱們能夠在配置文件中添加以下:
-keep class com.xxxx.json.model.**{
*;
}
把json包下的實體類所有保留。

上面描述了兩個解決案例:更多的配置例子能夠查看sdk的proguard文件夾下面的examples目錄。

接下來解釋幾個配置參數加深你們對proguard的配置的理解

保留全部的本地native方法不被混淆。這點在咱們作ndk開發的時候很重要。
-keepclasseswithmembernames class * {
    native <methods>;
}


保留全部的set和get開頭的方法。
-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

咱們保留在activity中的方法參數是view的方法,這樣的話,咱們在xml裏面編寫onClick就不會被影響了。
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

接下來附上相關的proguard的配置解釋,是筆者從網上搜羅的。

-dontwarn 缺省proguard 會檢查每個引用是否正確,可是第三方庫裏面每每有些不會用到的類,沒有正確引用。若是不配置的話,系統就會報錯。
-keep 指定的類和類成員被保留做爲 入口 。
-keepclassmembers 指定的類成員被保留。

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

保留選項 
-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}    設置源文件中給定的字符串常量

最後謝謝各位的閱讀。
相關文章
相關標籤/搜索