原創位址:http://blog.csdn.net/tl792814781/article/details/51447255
原創作者:迷途開發者的部落格
代碼混淆
代碼混淆(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>
以上是在項目中的一些心得,謝謝。