Android 代碼混淆心得!

代碼混淆

代碼混淆(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

  1. <span style="font-family:FangSong_GB2312;font-size:12px;color:#333333;">#指定代碼的壓縮級別  
  2. -optimizationpasses 5  
  3. #包明不混合大小寫  
  4. -dontusemixedcaseclassnames  
  5. #不去忽略非公共的庫類  
  6. -dontskipnonpubliclibraryclasses  
  7.  #優化  不優化輸入的類文件  
  8. -dontoptimize  
  9.  #預校驗  
  10. -dontpreverify  
  11.  # 混淆時所採用的算法  
  12. -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*  
  13. #保護註解  
  14. -keepattributes *Annotation*  
  15.   
  16.   
  17. # 保持哪些類不被混淆  
  18. -keep public class * extends android.app.Fragment  
  19. -keep public class * extends android.app.Activity  
  20. -keep public class * extends android.app.Application  
  21. -keep public class * extends android.app.Service  
  22. -keep public class * extends android.content.BroadcastReceiver  
  23. -keep public class * extends android.content.ContentProvider  
  24. -keep public class * extends android.app.backup.BackupAgentHelper  
  25. -keep public class * extends android.preference.Preference  
  26. -keep public class com.android.vending.licensing.ILicensingService  
  27. #如果有引用v4包可以添加下面這行  
  28. #-keep public class * extends android.support.v4.app.Fragment  
  29. -keep public class * extends android.support.** { *; }  
  30. #如果引用了v4或者v7包  
  31. -dontwarn android.support.*  
  32. #忽略警告  
  33. -ignorewarning  
  34.   
  35.   
  36. #####################記錄生成的日誌數據,gradle build時在本項目根目錄輸出################  
  37.  #混淆時是否記錄日誌  
  38. -verbose  
  39. #apk 包內所有 class 的內部結構  
  40. -dump class_files.txt  
  41. #未混淆的類和成員  
  42. -printseeds seeds.txt  
  43. #列出從 apk 中刪除的代碼  
  44. -printusage unused.txt  
  45. #混淆前後的映射  
  46. -printmapping mapping.txt  
  47.   
  48.   
  49. #####################記錄生成的日誌數據,gradle build時 在本項目根目錄輸出-end################  
  50.   
  51.   
  52. #####混淆保護自己項目的部分代碼以及引用的第三方jar包library - start #######  
  53.   
  54.   
  55. #如果不想混淆 keep 掉  保留一個完整的包  
  56. #-keep class com.lippi.recorder.iirfilterdesigner.** {*; }  
  57. #項目特殊處理代碼  
  58. #忽略警告  
  59. #-dontwarn com.lippi.recorder.utils**  
  60.   
  61.   
  62. #如果用用到Gson解析包的,直接添加下面這幾行就能成功混淆,不然會報錯。  
  63. #//原因分析,可能是高版本的 sdk 通過 proguard 混淆代碼時默認已經將 lib目錄中的 jar 都已經添加到打包腳本中,所以不需要再次手動添加  
  64. # 混淆jar  
  65. #-libraryjars libs/gson-2.2.4.jar  
  66. # 混淆類  
  67. #-keep class sun.misc.Unsafe { *; }  
  68. # 混淆包  
  69. #-keep class com.google.gson.examples.android.model.** { *; }  
  70. #dialog  
  71. -keep class me.drakeet.materialdialog.** { *; }  
  72. #加載框  
  73. -keep class com.kaopiz.kprogresshud.** { *; }  
  74. #下拉刷新  
  75. -keep class in.srain.cube.views.ptr.** { *; }  
  76. #實體類不混淆  
  77.   
  78.   
  79. -keep class com.ousrslook.shimao.commen.ioc.** { *; } #不能混淆 否則註解無效  
  80. -keep class com.ousrslook.shimao.model.** { *; } #不能混淆  
  81. -keep class com.ousrslook.shimao.net.XaResult{ *; }#統一返回的實體類泛型不能混淆  
  82. #-keep class com.ousrslook.shimao.net.** { *; }  
  83.   
  84.   
  85. ####混淆保護自己項目的部分代碼以及引用的第三方jar包library-end####  
  86.   
  87.   
  88. -keep public class * extends android.view.View {  
  89.     public <init>(android.content.Context);  
  90.     public <init>(android.content.Context, android.util.AttributeSet);  
  91.     public <init>(android.content.Context, android.util.AttributeSet, int);  
  92.     public void set*(...);  
  93. }  
  94.   
  95.   
  96. #保持 native 方法不被混淆  
  97. -keepclasseswithmembernames class * {  
  98.     native <methods>;  
  99. }  
  100.   
  101.   
  102. #保持自定義控件類不被混淆  
  103. -keepclasseswithmembers class * {  
  104.     public <init>(android.content.Context, android.util.AttributeSet);  
  105. }  
  106.   
  107.   
  108. #保持自定義控件類不被混淆  
  109. -keepclassmembers class * extends android.app.Activity {  
  110.    public void *(android.view.View);  
  111. }  
  112.   
  113.   
  114. #保持 Parcelable 不被混淆  
  115. -keep class * implements android.os.Parcelable {  
  116.   public static final android.os.Parcelable$Creator *;  
  117. }  
  118.   
  119.   
  120. #保持 Serializable 不被混淆  
  121. -keepnames class * implements java.io.Serializable  
  122.   
  123.   
  124. #保持 Serializable 不被混淆並且enum 類也不被混淆  
  125. -keepclassmembers class * implements java.io.Serializable {  
  126.     static final long serialVersionUID;  
  127.     private static final java.io.ObjectStreamField[] serialPersistentFields;  
  128.     !static !transient <fields>;  
  129.     !private <fields>;  
  130.     !private <methods>;  
  131.     private void writeObject(java.io.ObjectOutputStream);  
  132.     private void readObject(java.io.ObjectInputStream);  
  133.     java.lang.Object writeReplace();  
  134.     java.lang.Object readResolve();  
  135. }  
  136.   
  137.   
  138. #保持枚舉 enum 類不被混淆 如果混淆報錯,建議直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可  
  139. -keepclassmembers enum * {  
  140.   public static **[] values();  
  141.   public static ** valueOf(java.lang.String);  
  142. }  
  143.   
  144.   
  145. -keepclassmembers class * {  
  146.     public void *ButtonClicked(android.view.View);  
  147. }  
  148.   
  149.   
  150. #不混淆資源類  
  151. -keepclassmembers class **.R$* {  
  152.     public static <fields>;  
  153. }  
  154.  -keep class **.R$* { *; }  
  155. #避免混淆泛型 如果混淆報錯建議關掉  
  156. -keepattributes Signature</span>  


以上是在項目中的一些心得,謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章