Proguard 部分類不混淆的技巧
兩年前在 Proguard 語法及常用 proguard.cfg 程式碼 中介紹過一些 Proguard 的基礎知識,其中提到一些類不能混淆,比如實現了 Serializable 介面的,否則反序列化時會出錯。這種情況我們可以簡單的通過在 proguard-rules.pro 配置檔案中新增配置,對於較早 Android 專案預設配置檔案可能為 proguard.cfg,如下:
-keepnames class * implements java.io.Serializable -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; !static !transient <fields>; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); }
表示所有實現了 Serializable 介面的類及其成員都不進行混淆。
但有時我們可能需要防止一些沒有明顯共同特徵的類被混淆,比如個別控制層類需要反射、個別實體類需要 JSON 化存本地,這時我們怎麼做呢,一個個新增到 proguard-rules.pro(或 proguard.cfg) 中嗎?
這樣會導致 proguard 配置檔案變得雜亂無章,同時需要團隊所有成員對其語法有所瞭解。
這裡分享個小技巧,通過給這些類、屬性、函式新增共同標識,然後統一過濾。
二、解決方法
package cn.trinea.android.common.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * NotProguard, Means not proguard something, like class, method, field<br/> * * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2015-08-07 */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD}) public @interface NotProguard { }
NotProguard
是個編譯時註解,不會對執行時效能有任何影響。可修飾類、方法、建構函式、屬性。
2. 在 Proguard 配置檔案中過濾被這個註解修飾的元素
表示不混淆被 NotProguard 修飾的類、屬性和方法。# keep annotated by NotProguard -keep @cn.trinea.android.common.annotation.NotProguard class * {*;} -keep class * { @cn.trinea.android.common.annotation.NotProguard <fields>; } -keepclassmembers class * { @cn.trinea.android.common.annotation.NotProguard <methods>; }
3. 使用
(1) 整個類不混淆
Java123 | @NotProguardpublicclassUser{} |
(2) 單個屬性不混淆
Java1 2 3 | @NotProguard publicintid; |
(3) 單個方法不混淆
Java1 2 3 4 5 | @NotProguard publicbooleanisValid(){ … } |
這樣我們便解決了每個類都需要在 proguard 配置檔案中配置的問題。
三、關於混淆
混淆一般在 Release 模式生效,主要有三個作用:
(1) 壓縮、優化、刪除程式碼;
(2) 一定程度上提高反編譯後被讀懂的難度;
(3) 通過刪除程式碼功能實現的特殊作用。
比如在 Proguard 語法及常用 proguard.cfg 程式碼 中介紹的利用 Progurad 使得線上版本不列印 Log.d 和 Log.v 的技巧,防止除錯的敏感資訊被洩露。
一些應用的程式碼可能從來都沒混淆過,雖說這些程式碼實際價值可能不大,本身可能也是開原始碼湊起來的,再者該破解的還是能破解,但本著做事要專業的態度,還是混淆吧。