代碼混淆
代碼混淆(Obfuscated code)亦稱花指令,是將計算機程序的代碼,轉換成一種功能上等價,但是難於閱讀和理解的形式的行爲。
將代碼中的各種元素,如變量,函數,類的名字改寫成無意義的名字。比如改寫成單個字母,或是簡短的無意義字母組合,
甚至改寫成“__”這樣的符號,使得閱讀的人無法根據名字猜測其用途。
對於支持反射的語言,代碼混淆有可能與反射發生衝突。代碼混淆並不能真正阻止反向工程,只能增大其難度。
因此,對於對安全性要求很高的場合,僅僅使用代碼混淆並不能保證源代碼的安全。但是可以在一定程度上保護自己的勞動成果。(例子在末尾)
忽略混淆的文件(規則):
- Android系統組件,系統組件有固定的方法被系統調用。
- 被Android Resource 文件引用到的。名字已經固定,也不能混淆,比如自定義的View 。
- Android Parcelable ,需要使用android 序列化的。
- 其他Anroid 官方建議 不混淆的,如
- android.app.backup.BackupAgentHelper
- android.preference.Preference
- com.android.vending.licensing.ILicensingService
- Java序列化方法,系統序列化需要固定的方法。
- 枚舉 ,系統需要處理枚舉的固定方法。
- 本地方法,不能修改本地方法名
- annotations 註釋
- 數據庫驅動
- 有些resource 文件
- 用到反射的地方
心得:
1.grade構建必須沒有warn和error,不然刷入的版本依舊是上一個版本,這裏要特別注意warn!
2.ClassNotFoundException,NoSuchMethodError
原因:這種異常會在好多情況下出現,比如:本地代碼通過反射調用其他的類,但是經過了混淆之後,就會出現如上異常;調用了JNI之後,C或者C++和java代碼進行交互的時候找不到java的類或者方法,導致發生了異常......等等,還有好多。
解決辦法:只需要將被調用的Java類標註爲不混淆即可。 -keep class package.classname{*;}
3.ExceptionInInitializerError
原因:這是由於類初始化的時候發生了異常。
解決辦法:找到具體是哪裏的類哪個方法哪個類初始化的時候發生的異常,然後解決問題。
注:遇到這個錯誤,首先要確認是不是因爲第三方的jar包導致的。如果不是的話,就找本地代碼,看是不是寫的有問題。如果確實是因爲第三方jar包的代碼導致的,儘量找到源碼或者反編譯,查看問題到底是什麼引起的,然後找到相應的配置在proguard裏面配置。
例如:我們項目中碰到過一個問題,就是因爲第三方的jar包裏面有一個字段初始化的時候報了空指針,然後導致我們的代碼報了上面的錯。當時很奇怪,爲什麼第三方的jar包還能報錯,最後調查了之後才發現,是因爲人家用到了類的註解,而proguard在混淆優化的時候把註解去掉了,所以報了空指針,只需要在proguard裏面加上保護註解就可以了-keepattributes *Annotation*
4.ClassCastException
原因:類強制轉換的時候出錯。
解決辦法:找到代碼,看是代碼寫的問題,還是混淆後的問題。如果沒有混淆正常運行的話,一般都是因爲混淆後遇到了各種問題才報的錯。我們項目中遇到的問題是因爲沒有讓proguard保持泛型,所以強轉的時候報錯。只需要在proguard文件裏面加上泛型即可-keepattributes Signature
5.Resources$NotFoundException(resource not found)
資源沒有找到,是因爲第三方jar包或者自己的代碼是通過反射獲得R文件中的資源,所以需要將R文件屏蔽掉
原因:代碼進行了混淆,R文件沒有了,所以通過反射獲取的R文件找不到
解決辦法:在proguard文件裏設置不混淆R文件 -keep class **.R$* { *; }
6. Missing type parameter. or java.lang.ExceptionInInitializerError
可能是泛型混淆了 泛型即可-keepattributes Signature
混淆例子:
[java] view plain copy
- <span style="font-family:FangSong_GB2312;font-size:12px;color:#333333;">#指定代碼的壓縮級別
- -optimizationpasses 5
- #包明不混合大小寫
- -dontusemixedcaseclassnames
- #不去忽略非公共的庫類
- -dontskipnonpubliclibraryclasses
- #優化 不優化輸入的類文件
- -dontoptimize
- #預校驗
- -dontpreverify
- # 混淆時所採用的算法
- -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
- #保護註解
- -keepattributes *Annotation*
- # 保持哪些類不被混淆
- -keep public class * extends android.app.Fragment
- -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
- #如果有引用v4包可以添加下面這行
- #-keep public class * extends android.support.v4.app.Fragment
- -keep public class * extends android.support.** { *; }
- #如果引用了v4或者v7包
- -dontwarn android.support.*
- #忽略警告
- -ignorewarning
- #####################記錄生成的日誌數據,gradle build時在本項目根目錄輸出################
- #混淆時是否記錄日誌
- -verbose
- #apk 包內所有 class 的內部結構
- -dump class_files.txt
- #未混淆的類和成員
- -printseeds seeds.txt
- #列出從 apk 中刪除的代碼
- -printusage unused.txt
- #混淆前後的映射
- -printmapping mapping.txt
- #####################記錄生成的日誌數據,gradle build時 在本項目根目錄輸出-end################
- #####混淆保護自己項目的部分代碼以及引用的第三方jar包library - start #######
- #如果不想混淆 keep 掉 保留一個完整的包
- #-keep class com.lippi.recorder.iirfilterdesigner.** {*; }
- #項目特殊處理代碼
- #忽略警告
- #-dontwarn com.lippi.recorder.utils**
- #如果用用到Gson解析包的,直接添加下面這幾行就能成功混淆,不然會報錯。
- #//原因分析,可能是高版本的 sdk 通過 proguard 混淆代碼時默認已經將 lib目錄中的 jar 都已經添加到打包腳本中,所以不需要再次手動添加
- # 混淆jar
- #-libraryjars libs/gson-2.2.4.jar
- # 混淆類
- #-keep class sun.misc.Unsafe { *; }
- # 混淆包
- #-keep class com.google.gson.examples.android.model.** { *; }
- #dialog
- -keep class me.drakeet.materialdialog.** { *; }
- #加載框
- -keep class com.kaopiz.kprogresshud.** { *; }
- #下拉刷新
- -keep class in.srain.cube.views.ptr.** { *; }
- #實體類不混淆
- -keep class com.ousrslook.shimao.commen.ioc.** { *; } #不能混淆 否則註解無效
- -keep class com.ousrslook.shimao.model.** { *; } #不能混淆
- -keep class com.ousrslook.shimao.net.XaResult{ *; }#統一返回的實體類泛型不能混淆
- #-keep class com.ousrslook.shimao.net.** { *; }
- ####混淆保護自己項目的部分代碼以及引用的第三方jar包library-end####
- -keep public class * extends android.view.View {
- public <init>(android.content.Context);
- public <init>(android.content.Context, android.util.AttributeSet);
- public <init>(android.content.Context, android.util.AttributeSet, int);
- public void set*(...);
- }
- #保持 native 方法不被混淆
- -keepclasseswithmembernames class * {
- native <methods>;
- }
- #保持自定義控件類不被混淆
- -keepclasseswithmembers class * {
- public <init>(android.content.Context, android.util.AttributeSet);
- }
- #保持自定義控件類不被混淆
- -keepclassmembers class * extends android.app.Activity {
- public void *(android.view.View);
- }
- #保持 Parcelable 不被混淆
- -keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
- }
- #保持 Serializable 不被混淆
- -keepnames class * implements java.io.Serializable
- #保持 Serializable 不被混淆並且enum 類也不被混淆
- -keepclassmembers class * implements java.io.Serializable {
- static final long serialVersionUID;
- private static final java.io.ObjectStreamField[] serialPersistentFields;
- !static !transient <fields>;
- !private <fields>;
- !private <methods>;
- private void writeObject(java.io.ObjectOutputStream);
- private void readObject(java.io.ObjectInputStream);
- java.lang.Object writeReplace();
- java.lang.Object readResolve();
- }
- #保持枚舉 enum 類不被混淆 如果混淆報錯,建議直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可
- -keepclassmembers enum * {
- public static **[] values();
- public static ** valueOf(java.lang.String);
- }
- -keepclassmembers class * {
- public void *ButtonClicked(android.view.View);
- }
- #不混淆資源類
- -keepclassmembers class **.R$* {
- public static <fields>;
- }
- -keep class **.R$* { *; }
- #避免混淆泛型 如果混淆報錯建議關掉
- -keepattributes Signature</span>
以上是在項目中的一些心得,謝謝。