Android Proguard

android的代碼混淆主要包括以下幾個方面:

總共分為四個步驟:

shrink: 檢測并移除沒有用到的類,變量,方法和屬性;

optimize: 優化代碼,非入口節點類會加上private/static/final, 沒有用到的參數會被刪除,一些方法可能會變成內聯代碼。

obfuscate: 使用短又沒有語義的名字重命名非入口類的類名,變量名,方法名。入口類的名字保持不變。

preverify: 預校驗代碼是否符合Java1.6或者更高的規范(唯一一個與入口類不相關的步驟)

Android studio配置

buildTypes {

release {

minifyEnabled true

proguardFiles getDefaultProguardFile('proguard-android.txt'),

'proguard-rules.pro'

}

}

proguardFiles可以配置多個混淆文件,proguard-android.txt是android自帶的混淆文件,在android sdk下的tools/proguard目錄下,里面是一些常用的混淆配置,如果工程沒有特殊的混淆配置,只使用這個文件就可以滿足。

常用的配置命令

-skipnonpubliclibraryclasses指定讀取引用庫文件的時候跳過非public類。這樣做可以提高處理速度并節省內存。一般情況下非public在應用內是引用不到的,跳過它們也沒什么關系。但是,在一些java類庫中中出現了public類繼承非public類的情況,這樣就不能用這個選項了。這種情況下,會打印一個警告出來,提示找不到類。

-dontskipnonpubliclibraryclasses跟上面的參數相對。版本4.5以上,這個是默認的選項。

-dontusemixedcaseclassnames指定在混淆的時候不使用大小寫混用的類名。默認情況下,混淆后的類名可能同時包含大寫字母和小寫字母。這樣生成jar包并沒有什么問題。只有在大小寫不敏感的系統(例如windows)上解壓時,才會涉及到這個問題。因為大小寫不區分,可能會導致部分文件在解壓的時候相互覆蓋。如果有在windows系統上解壓輸出包的需求的話,可以加上這個配置。

-verbose聲明在處理過程中輸出更多信息。添加這項配置之后,如果處理過程中出現異常,會輸出整個StackTrace而不是一條簡單的異常說明。

-dontoptimize聲明不優化代碼。Dex會自己優化的

-dontpreverify聲明不預校驗即將執行的類。默認情況下,在類文件的編譯版本為java micro 版本或者大于1.6版本時,預校驗是開啟的。目標文件針對java6的情況下,預校驗是可選的;針對java7的情況下,預校驗是必須的,除非目標運行平臺是Android平臺,設置它可以節省一點點時間。

-keepattributes *Annotation*表示對注解中的參數進行保留

-optimizationpasses代碼混淆壓縮比,在0~7之間,默認為5,一般不下需要修改

-printmapping混淆前后的映射

-optimizations指定混淆時采用的算法,后面的參數是一個過濾器

-keepattributes *SourceFile,LineNumberTable*拋出異常時保留代碼行號

-keepattributes *Signature*避免混淆泛型

-flattenpackagehierarchy保持packagename 不混淆

-ignorewarning忽略警告

keep命令

-keep [,modifier, ...] class_specification指定類和類的成員變量是入口節點,保護它們不被移除混淆。

-keepclassmembers [,modifier] class_specification保護的指定的成員變量不被移除、優化、混淆。

-keepclasseswithmembers [,modifier,...] class_specification擁有指定成員的類將被保護,根據類成員確定一些將要被保護的類。

-keep-keepnames的關系一開始理解的時候有些混亂。但是它們背后是有一定規則的,下面的表格展示了它們的聯系與不同

先看如下兩個比較常用的命令,很多童鞋可能會比較迷惑以下兩者的區別

-keep class com.xiaoka.test.**

-keep class com.xiaoka.test.*

一顆星表示只是保持該包下的類名,而子包下的類名還是會被混淆;兩顆星表示把本包和所含子包下的類名都保持;用以上方法保持類后,你會發現類名雖然未混淆,但里面的具體方法和變量命名還是變了,這時如果既想保持類名,又想保持里面的內容不被混淆,我們就需要以下方法了

-keep class com.xiaoka.test.* {*;}

混淆后生成的文件

mapping.txt:(配置指令:-printmapping)混淆前后代碼對照,在混淆之后如果出現問題,需要查找此文件進行定位---養成保存mapping.txt文件的習慣

dump.txt:(配置指令:-dump)APK內所有class文件結構

seeds.txt:(配置指令:-printseeds)沒有被混淆的類和成員

usage.txt:(配置指令:-printusage)源代碼中被刪除的代碼

不能混淆的類型

反射用到的類不混淆

JNI方法不混淆

Manifest中類不混淆

四大組件和Application子類、Framework層下所有類默認不混淆

Parcelable子類和Creator靜態成員變量不混淆(BadParcelableException,怕了吧)

GSon、FastJson等庫時,Json對象不混淆(注解可解決此問題)

第三方開源庫或引用其他第三方SDK,加入對應混淆規則(或者庫在打包aar時有指定consumerProguardFiles)

WebView的JS調用接口不混淆

library與組件化的混淆問題

現在的問題:所有的混淆規則都是加在app的proguard文件內,一旦library與組件化,需要調整時,必須調整app里的proguard規則

解決方法1:使用@keep,缺陷就是要標記很多地方

解決方法2:使用在build.gradle文件內的defaultConfig內的consumerProguardFiles,也就是把混淆規則傳遞過去,如下圖:

我們app開始用第一種方式,現在已改成第二種方式

模糊字典

-obfuscationdictionary dictionary.txt指定外部模糊字典

-classobfuscationdictionary filename指定class模糊字典

-packageobfuscationdictionary filename指定package模糊字典

指定這些字典后會使用字典里面的值當做混淆的類名,方法名或字段

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,287評論 25 708
  • 混淆(Proguard)用法 最近項目中遇到一些混淆相關的問題,由于之前對proguard了解不多,所以每次都是面...
    于曉飛93閱讀 56,870評論 38 230
  • Android 開發中為了代碼安全一般都會使用 ProGuard 進行代碼混淆,它可以把類名、屬性名和方法名變為毫...
    JohnnyShieh閱讀 4,312評論 2 13
  • Merit smaller APK size (20% ~ 40%) more difficult to reve...
    Wavky閱讀 1,338評論 0 0
  • 我將守候你 在清晨,在野花旁 冬日因你有了驕陽的氣息。 我將守候你 在路邊,在樹蔭下 吹過的冷風也充滿了愛意。 我...
    Sans_閱讀 171評論 0 2