Android程式碼混淆的實踐

Web開發者發表於2012-07-16

  開發apk的時候當然要考慮保護好自己的程式碼,Android環境就提供了ProGuard來進行程式碼混淆,確實是一個非常有用的工具,但用起來也確實夠折騰的。

Android程式碼混淆的實踐

1. 基本配置

  eclipse下建立android工程,就會生成proguard.cfg和project.properties,在後面的檔案追加proguard.config=proguard.cfg即可讓前面的配置檔案在export時生效。預設的那個檔案有一些內容,這裡給一個更通用點的。

##—————Begin: proguard configuration common for all Android apps ———-
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable 

# 以下兩個命令配合讓類的路徑給刪除了
-allowaccessmodification
-repackageclasses ” 

# 記錄生成的日誌資料,在proguard目錄下
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt 

# 異常都可以忽略就開啟
#-dontwarn 

-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
-dontnote com.android.vending.licensing.ILicensingService 

-keepnames class * implements java.io.Serializable 

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn’t save them.
-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();
} 

# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
native ;
} 

-keepclasseswithmembernames class * {
public (android.content.Context, android.util.AttributeSet);
} 

-keepclasseswithmembernames class * {
public (android.content.Context, android.util.AttributeSet, int);
} 

# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
public static ;
} 

# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
} 

-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
} 

# 如果你的工程是對外提供方法呼叫就開啟
#-keep public class * {
# public protected *;
#} 

##—————End: proguard configuration common for all Android apps ———- 

2. 解決export打包的報錯

  這個時候export提示“conversion to Dalvik format failed with error 1”錯誤,網上說法有好多種,最後我還是把proguard從4.4升級到4.8就解決了。官方地址是http://proguard.sourceforge.net。上面的配置檔案引數可以在這裡查閱。

  升級辦法很簡單,就是把android sdk目錄下的tool/proguard目錄覆蓋一下即可。

3. 打包出來的程式如何除錯

  一旦打包出來,就不能用eclipse的logcat去看了,這裡可以用android sdk中ddms.bat的tool來看,一用就發現和logcat其實還是一個東西,就是多了個裝置的選擇。

4. 使用 gson 需要的配置

  當Gson用到了泛型就會有報錯,這個真給鬱悶了半天,提示“Missing type parameter”。最後找到一個資料給了一個解決辦法,參考:http://stackoverflow.com/questions/8129040/proguard-missing-type-parameter。

  另外我又用到了JsonObject,提交的Object裡面的members居然被改成了a。所以上面給的東西還不夠,還要加上

# 用到自己拼接的JsonObject
-keep class com.google.gson.JsonObject { *; }  

  我個人建議減少這些依賴包混淆帶來的麻煩,乾脆都全部保留不混淆。例如

-keep class com.badlogic.** { *; }
-keep class * implements com.badlogic.gdx.utils.Json*
-keep class com.google.** { *; } 

5. 使用libgdx需要的配置

  參考http://code.google.com/p/libgdx-users/wiki/Ant

6. 驗證打包效果

  我是利用了apktool的反編譯工具,把打包檔案又解壓了看了一下,如果包路徑、類名、變數名、方法名這些變化和你期望一致,那就OK了。命令:

apktool.bat d xxx.apk destdir 

總結

  這個東西用起來也不是很簡單,特別是你程式用到的高階特性多,就更容易出問題。另外proguard的引數看起來確實也有點不好理解,打包過程慢,測試也比較浪費時間。東西雖好,但真不是那麼容易上手。

相關文章