首頁>技術>

開源專案專題系列

(四)

1.開源專案名稱:Zucker

2.github地址:

https://github.com/wuba/Zucker

3.簡介:Zucker是基於APP模組的,一個簡單無侵害計算AAR獨有大小的工具。

APP模組化大小自動分析工具是用來解構Apk大小構成的一種分析方式,它可以在不侵入使用者程式碼的情況下,自動分析出當前專案的構建方式、依賴結構,通過計算獨有依賴的大小從而精準的計算出一個模組在Apk中所佔的大小。

Zucker於2020年3月份開源,它在行業內的特點如下:

首款從程式碼結構模組化分析統計Apk大小的工具;利用使用者自身的執行環境即可執行,具有一定的通用性;使用指令碼即可實現,無需入侵使用者程式碼,靈活性高、擴充套件性強;對比原有的統計方法,通過自動化,實現提效;控制Apk大小的措施工作左移,在整合階段,甚至在更早的需求開發階段發現問題,把控APP的品質風險;為什麼要使用Zucker

一款Android APP,應用市場的評分是使用者衡量下載意願的關鍵參考標準,絕大部分使用者會在同類產品中願意優先選擇評分較高的APP。然而,調查顯示:APP評分越高,使用者下載量越高;APP安裝包體積越小,使用者下載量越高。那麼,如何有效的控制APP安裝包體積也是提高使用者下載意願的措施。下圖是58APP近兩年來的版本變化:

圖一 58APP大小變化趨勢

業界內的有很多人都致力於研究在當前的APP狀態下,對其進行縮減優化,效果也很顯著,典型的有:使用TinyPNG或者WebP優化圖片資源、使用lint對於無用程式碼進行檢測、AndResGuard、7Zip壓縮等等。我們發現,業界的普遍解決思路:在既有的APP上想辦法縮減。

那麼有沒有什麼方法,是可以在APP正式產出之前,就能對其監控呢?業內的一個典型的案例:大圖片檢測。對整個Apk進行解析,將圖片資源按大小進行排序,找到前50個大圖片,再使用TinyPNG或者WebP等優化手段。但是,仔細想一下,這個圖片來源於哪個需求?這個需求來源於哪個模組?這個模組現在在Apk中的佔比是多少?所以,僅僅從拆解Apk的角度去分析還遠遠不夠。

我們知道,導致APP增大的最直接因素是需求的迭代,在現有的需求開發中,一個需求可能涉及到一個或者多個模組,比如:各個業務線,又或者是登入、認證、微聊、視訊、定位等模組。假如認證模組引入了一個導致APP增大5MB的第三方庫,當我們嘗試使用業內普通的解決思路時,對其優化可能收效甚微。但是使用Zucker,由於它對於認證模組進行監控,它可以在該需求正式被打包進APP之前發出警告。從根源監控,將這個5M的第三方庫用其他更小的庫替代或者通過自實現的方式,都可以減少它的大小。

針對這個問題,我們也嘗試了很多種辦法,我們現在已經有基於需求層面來分析Apk的組成,它已經在58APP服役兩年多的時間,監控了近30多個版本,反響非常好。

現在我們更進一步,利用模組化的思路,把Apk的統計分析工作進一步完善,將控制Apk大小的措施工作左移,在整合階段,甚至更早的需求開發階段提早發現程式碼品質問題,從而更好地保證APP的品質。

整體架構

Apk依賴的模組目前大多是由AAR組成,統計Apk中模組的大小本質上是在統計AAR的大小。由於Apk在打包過程中,會利用AIDL和AAPT進行程式碼、資源壓縮、混淆等操作,所以,只計算AAR的大小是不準確的,實際上需要統計的是AAR在Apk中進行壓縮、混淆之後的實際大小。此外,一個模組可以包含多個AAR,這時候需要對整個APP的依賴關係進行分析,從而找到目標AAR的獨有依賴關係。最後,為了實現模組的自動分析統計,我們利用Python實現了對於專案工程輕量級、微侵入的統計方式。

Zucker的整體架構劃分如下:自動化打包統計、依賴分析、目標AAR模擬:

圖二 Zucker專案整體架構

自動化打包統計

對一個給定的目標工程避免產生侵害和改動,需要對原始碼工程做拷貝處理,然後利用該拷貝的工程計算依賴關係推理出獨有依賴。再克隆一個工程用於替換獨有依賴的目標AAR,再對克隆工程進行打包。最後,通過打出的兩個克隆工程的包的大小差值,可以得到目標AAR的大小。

1. 克隆工程

為了實現無侵害計算,需要修改工程的gradle指令碼來實現自動模擬AAR以及計算包大小,將原有工程進行克隆再分析模擬AAR及打包統計。使用Python指令碼檔案需要放置目標工程的同級目錄,執行指令碼在同級目錄產生一個output目錄,統一存放拷貝的工程檔案。

圖三 工程克隆

2. 編譯過程

整個編譯過程包括以下步驟:初始化工程→自動尋路查詢工程入口→清除flavors→插入計算指令碼→執行打包命令。通過此流程,可完整實現自動化尋路APP入口並修改配置來實現基礎包打包和計算包體積大小任務。

圖四 打包編譯過程分析

依賴分析

在上文中提到獲取使用者輸入的AAR,分析工程中各模組依賴關係。獲取AAR的相互依賴關係,對於計算AAR大小起到關鍵作用。首先明確兩個依賴關係概念。

獨有依賴:對於某一AAR,內部引用庫僅被當前AAR所依賴,再無其他依賴關係,則這個庫被稱為AAR的獨有依賴。公有依賴庫:不同於獨有依賴,一個庫可能被多個AAR所引用,則這個庫被稱為公有依賴。

回到上面說的,若要統計AAR在APP包大小中的佔比,除了它自己還不夠,還要分析該AAR的獨有依賴才能正確計算引入該AAR後的大小。

1. 依賴樹轉化

在專案的Gradle檔案中可以找到該專案的依賴引用,專案執行./gradlew dependencies命令後會獲取當前專案的依賴樹結構,為了方便處理,將專案中的依賴庫簡化成A,B,C來表示,如圖所示,A,A1,A2表示專案直接引用的AAR依賴。B,C是A的子依賴,同時C,D是A1的子依賴。根據上文所述,A的內部依賴B沒有其他的被依賴關係,因此稱B為A的獨有依賴。另外的由於C同時被A和A1依賴,因此稱C為公有依賴。

圖五 依賴關係分析

理解依賴樹結構特點,可將依賴樹形結構轉化成列表來顯示。由上述分析可知一個依賴庫可能被多個庫依賴,產生依賴關係。同時依賴關係是單向有序的,箭頭指向表示A依賴B:A是B的父依賴,B是A的子依賴。現挑出A,A1,C作為例子分析,將A,A1作為一個父節點,節點內部同時維護兩個列表,父節點列表(parents)和子節點列表(children)。依次就可以將依賴樹中所有的依賴關係放置在節點型別的資料結構中。另外root節點是工程總節點,它是A,A1和A2的父節點。通過此步驟,得到依賴列表,記錄工程中所有依賴節點:

圖六 依賴關係處理

2. 獨有依賴分析

統計目標AAR大小時,不僅要統計目標AAR還要包括它的獨有依賴。通過上文步驟獲取到了專案所有AAR列表,在輸入目標依賴名稱後,我們在列表中遍歷找到該目標,檢查其子依賴然後獲取最後的獨有依賴,檢查流程如下:

羅列目標依賴下的所有子依賴,並且遍歷子依賴的子依賴,將它們記錄到新列表中;採用深度便演算法來逐一去判斷新列表中的依賴,判斷其父依賴是否僅在該列表中,如果父依賴全部都在該列表中則保留,否則從列表中可刪除該依賴;經過步驟2後的篩選,剩下的節點則為目標依賴的獨有依賴。

下面我們以上文圖中的節點A1為例,將A1節點所有的子節點記錄到列表。首先獨有依賴包括它自身,故A1保留。C節點的父父節點有A和A1,A不在當前列表中,因此C不是獨有依賴,將C移除。D的父節點僅有A1且在列表中,因此D是獨有依賴。以此類推,在判斷I節點時,由於C節點已被移除不在列表中,因此I也不是A1的獨有依賴。節點獨有依賴尋找流程:

圖七 獨有依賴的獲取

目標AAR模擬

在專案打包生成Apk過程中,會利用Gradle快取特性,工程編譯前,獲取使用者輸入的目標AAR,指令碼通過目標AAR名稱在快取目錄下自動尋找。然後將本地的目標AAR檔案進行模擬處理,打包時將該模擬後的AAR打入Apk中。模擬替換目標AAR流程:

圖八 目標AAR的模擬

我們知道AAR是二進位制歸檔檔案,也是壓縮檔案,只不過它是AAPT打包命令中的一個結果,通常會壓縮:資原始檔、類檔案、系統檔案等。所以找到該AAR後,我們進行“解剖”,步驟如下:

將目標AAR在當前目錄下備份一份;將AAR檔案重新命名變成.zip檔案並進行解壓縮;遍歷解壓縮檔案目錄,當目標是檔案時,判斷其檔案型別是否為.xml或.9.png,是則跳過;否則,將其檔案大小置為0KB;解壓縮檔案完全按照步驟3處理完成後,將其重新壓縮為一個模擬的AAR檔案,參與打包計算;打包完成後,為了不影響後續打包任務,刪除模擬的AAR將備份的AAR檔案恢復;

修改build.gradle檔案,使用Gradle的打包特性配置所有all*.exclude移除對應的group和module;

未來規劃

目前已使用zucker統計了最近三個版本的模組大小,統計耗時已大幅度減少。基於上述流程可以快速完成統計目標AAR及其獨有依賴在Apk包體積大小佔比,接下來還有些方面亟需提高。

AAR大小列表展示,基於圖表形式展示,一目了然;版本具體需求功能結合展示,並形成相關性文件;如何貢獻&問題反饋

本次開源只是Zucker貢獻社群的一小步,我們誠摯地希望開發者向我們提出寶貴的意見和建議。您可以使用如下方式向我們反饋建議和問題:

在https://github.com/wuba/Zucker提PR或者Issue。

作者介紹

胡昊,Android資深開發工程師-負責Zucker專案整體架構、技術選型,主要參與目標AAR的模擬替換;

曾鵬,Android資深開發工程師-負責Zucker專案工程自動化打包統計;

李賀,Android高階開發工程師-負責Zucker專案中依賴關係轉化與Gradle快取處理;

楊文蛟,Android高階開發工程師-負責Zucker專案資料統計與調優;

想了解更多開源專案資訊?

與專案成員零距離交流?

一切應有盡有

  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 前端走向後臺 :Node.js 讓 JavaScript 執行在服務端