天天看點

ProGuard代碼混淆技術詳解

    受《APP研發錄》啟發,裡面講到一名Android程式員,在工作一段時間後,會感覺到迷茫,想進階的話接下去是看Android系統源碼呢,還是每天繼續做應用,畢竟每天都是畫UI和利用MobileAPI處理Json還是蠻無聊的,做着重複的事情,沒有技術的上提升空間的。是以,根據裡面提到的Android應用開發人員所需要精通的20個技術點,寫篇文章進行總結,一方面是梳理下基礎知識和鞏固知識,另一方面也是彌補自我不足之處。

    那麼,今天就來講講ProGuard代碼混淆的相關技術知識點。

ProGuard簡介

ProGuard工作原理

如何編寫一個ProGuard檔案

其他注意事項

小結

因為Java代碼是非常容易反編碼的,況且Android開發的應用程式是用Java代碼寫的,為了很好的保護Java源代碼,我們需要對編譯好後的class檔案進行混淆。

ProGuard是一個混淆代碼的開源項目,它的主要作用是混淆代碼,殊不知ProGuard還包括以下4個功能。

壓縮(Shrink):檢測并移除代碼中無用的類、字段、方法和特性(Attribute)。

優化(Optimize):對位元組碼進行優化,移除無用的指令。

混淆(Obfuscate):使用a,b,c,d這樣簡短而無意義的名稱,對類、字段和方法進行重命名。

預檢(Preveirfy):在Java平台上對處理後的代碼進行預檢,確定加載的class檔案是可執行的。

總而言之,根據官網的翻譯:Proguard是一個Java類檔案壓縮器、優化器、混淆器、預校驗器。壓縮環節會檢測以及移除沒有用到的類、字段、方法以及屬性。優化環節會分析以及優化方法的位元組碼。混淆環節會用無意義的短變量去重命名類、變量、方法。這些步驟讓代碼更精簡,更高效,也更難被逆向(破解)。

ProGuar由shrink、optimize、obfuscate和preveirfy四個步驟組成,每個步驟都是可選的,我們可以通過配置腳本來決定執行其中的哪幾個步驟。

ProGuard代碼混淆技術詳解

混淆就是移除沒有用到的代碼,然後對代碼裡面的類、變量、方法重命名為人可讀性很差的簡短名字。

那麼有一個問題,ProGuard怎麼知道這個代碼沒有被用到呢?

這裡引入一個Entry Point(入口點)概念,Entry Point是在ProGuard過程中不會被處理的類或方法。在壓縮的步驟中,ProGuard會從上述的Entry Point開始遞歸周遊,搜尋哪些類和類的成員在使用,對于沒有被使用的類和類的成員,就會在壓縮段丢棄,在接下來的優化過程中,那些非Entry Point的類、方法都會被設定為private、static或final,不使用的參數會被移除,此外,有些方法會被标記為内聯的,在混淆的步驟中,ProGuard會對非Entry Point的類和方法進行重命名。

那麼這個入口點怎麼來呢?就是從ProGuard的配置檔案來,隻要這個配置了,那麼就不會被移除。

有個三步走的過程:

基本混淆

針對APP的量身定制

針對第三方jar包的解決方案

混淆檔案的基本配置資訊,任何APP都要使用,可以作為模闆使用,具體如下。

1,基本指令

 2,需要保留的東西

1,保留實體類和成員被混淆

對于實體,保留它們的set和get方法,對于boolean型get方法,有人喜歡命名isXXX的方式,是以不要遺漏。如下:

 一種好的做法是把所有實體都放在一個包下進行管理,這樣隻寫一次混淆就夠了,避免以後在别的包中新增的實體而忘記保留,代碼在混淆後因為找不到相應的實體類而崩潰。

2,内嵌類

内嵌類經常會被混淆,結果在調用的時候為空就崩潰了,最好的解決方法就是把這個内嵌類拿出來,單獨成為一個類。如果一定要内置,那麼這個類就必須在混淆的時候保留,比如如下:

這個$符号就是用來分割内嵌類與其母體的标志。

3,對WebView的處理

4,對JavaScript的處理

 其中JSInterface是MainActivity的子類

5,處理反射

在程式中使用SomeClass.class.method這樣的靜态方法,在ProGuard中是在壓縮過程中被保留的,那麼對于Class.forName("SomeClass")呢,SomeClass不會被壓縮過程中移除,它會檢查程式中使用的Class.forName方法,對參數SomeClass法外開恩,不會被移除。但是在混淆過程中,無論是Class.forName("SomeClass"),還是SomeClass.class,都不能蒙混過關,SomeClass這個類名稱會被混淆,是以,我們要在ProGuard.cfg檔案中保留這個類名稱。

<code>Class.forName("SomeClass")</code>

<code>SomeClass.class</code>

<code>SomeClass.class.getField("someField")</code>

<code>SomeClass.class.getDeclaredField("someField")</code>

<code>SomeClass.class.getMethod("someMethod", new Class[] {})</code>

<code>SomeClass.class.getMethod("someMethod", new Class[] { A.class })</code>

<code>SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })</code>

<code>SomeClass.class.getDeclaredMethod("someMethod", new Class[] {})</code>

<code>SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })</code>

<code>SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class, B.class })</code>

<code>AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")</code>

<code>AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")</code>

<code>AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")</code>

在混淆的時候,要在項目中搜尋一下上述方法,将相應的類或者方法的名稱進行保留而不被混淆。

6,對于自定義View的解決方案

但凡在Layout目錄下的XML布局檔案配置的自定義View,都不能進行混淆。為此要周遊Layout下的所有的XML布局檔案,找到那些自定義View,然後确認其是否在ProGuard檔案中保留。有一種思路是,在我們使用自定義View時,前面都必須加上我們的包名,比如com.a.b.customeview,我們可以周遊所有Layout下的XML布局檔案,查找所有比對com.a.b的标簽即可。

我們在Android項目中不可避免要使用很多第三方提供的SDK,一般而言,這些SDK是經過ProGuard混淆的,而我們所需要做的就是避免這些SDK的類和方法在我們APP被混淆。

1,針對android-support-v4.jar的解決方案

 2,其他的第三方jar包的解決方案

這個就取決于第三方包的混淆政策了,一般都有在各自的SDK中有關于混淆的說明文字,比如支付寶如下:

值得注意的是,不是每個第三方SDK都需要-dontwarn 指令,這取決于混淆時第三方SDK是否出現警告,需要的時候再加上。

當然在使用ProGuard過程中,還有一些注意的事項,如下。

1,如何確定混淆不會對項目産生影響

測試工作要基于混淆包進行,才能盡早發現問題

每天開發團隊的冒煙測試,也要基于混淆包

發版前,重點的功能和子產品要額外的測試,包括推送,分享,打賞

2,打包時忽略警告

當導出包的時候,發現很多could not reference class之類的warning資訊,如果确認App在運作中和那些引用沒有什麼關系,可以添加-dontwarn 标簽,就不會提示這些警告資訊了

3,對于自定義類庫的混淆處理

比如我們引用了一個叫做AndroidLib的類庫,我們需要對Lib也進行混淆,然後在主項目的混淆檔案中保留AndroidLib中的類和類的成員。

4,使用annotation避免混淆

另一種類或者屬性被混淆的方式是,使用annotation,比如這樣:

5,在項目中指定混淆檔案

到最後,發現沒有介紹如何在項目中指定混淆檔案。在項目中有一個project.properties檔案,在其中寫這麼一句話,就可以確定每次手動打包生成的apk是混淆過的。

proguard.config=proguard.cfg

其中,proguard.cfg是混淆檔案的名稱。

總之ProGuard是一個比較枯燥的過程,但Android項目沒有了ProGuard就真不行了,這樣可以保證我們開發出的APK可以更健壯,畢竟很多核心代碼品質也算是一個APK的核心競争力吧。

源于對掌握的Android開發基礎點進行整理,羅列下已經總結的文章,從中可以看到技術積累的過程。

1,Android系統簡介

2,ProGuard代碼混淆

3,講講Handler+Looper+MessageQueue關系

4,Android圖檔加載庫了解

5,談談Android運作時權限了解

6,EventBus初了解

7,Android 常見工具類

8,對于Fragment的一些了解

9,Android 四大元件之 " Activity "

10,Android 四大元件之" Service "

11,Android 四大元件之“ BroadcastReceiver "

11,Android 四大元件之" ContentProvider "

13,講講 Android 事件攔截機制

14,Android 動畫的了解

15,Android 生命周期和啟動模式

16,Android IPC 機制

17,View 的事件體系

18,View 的工作原理

19,了解 Window 和 WindowManager

20,Activity 啟動過程分析

21,Service 啟動過程分析

22,Android 性能優化

23,Android 消息機制

24,Android Bitmap相關

25,Android 線程和線程池

26,Android 中的 Drawable 和動畫

27,RecylerView 中的裝飾者模式

28,Android 觸摸事件機制

29,Android 事件機制應用

30,Cordova 架構的一些了解

31,有關 Android 插件化思考 

32,開發人員必備技能——單元測試