初探Matrix Android ApkChecker

Tsissan發表於2022-02-16

背景

因為我所在的專案是做投放包,對安卓包的大小很敏感,經常會優化包的大小,所以想引入工具靜態檢測包大小,看能不能找到其中可以優化的地方,防患於未然。Matrix是微信終端自研和正在使用的一套APM(Application Performance Management)系統。 Matrix-ApkChecker作為Matrix系統的一部分,是針對android安裝包的分析檢測工具,根據一系列設定好的規則檢測apk是否存在特定的問題,並輸出較為詳細的檢測結果報告,用於分析排查問題以及版本追蹤。Matrix-ApkChecker以一個jar包的形式提供使用,通過命令列執行 java -jar ApkChecker.jar 即可執行。

Matrix-ApkChecker的使用

在git上下載matrix-apk-canary-0.4.10.jar
直接在命令列執行

java -jar ApkChecker.jar

即可以檢視Matrix-ApkChecker的使用說明 (注意:下面所說的路徑為完整路徑,非相對路徑)

Matrix-ApkChecker的命令列引數比較多,主要包括global引數和option引數兩類:

  • global
  --apk   輸入apk檔案路徑(預設檔名以apk結尾即可)
  --mappingTxt   程式碼混淆mapping檔案路徑 (預設檔名是mapping.txt)
  --resMappingTxt   資源混淆mapping檔案路徑(預設檔名是resguard-mapping.txt)
  --input   包含了上述輸入檔案的目錄(給定--input之後,則可以省略上述輸入檔案引數,但上述輸入檔案必須使用預設檔名)
  --unzip   解壓apk的輸出目錄
  --output   輸出結果檔案路徑(不含字尾,會根據format決定輸出檔案的字尾)
  --format   結果檔案的輸出格式(例如 html、json等)
  --formatJar   實現了自定義結果檔案輸出格式的jar包
  --formatConfig   對結果檔案輸出格式的一些配置項(json陣列格式)

global 引數之後緊跟若干個 Option,這些 Option 是可選的,一個 Option 表示針對 apk 的一個檢測選項。

  • option引數
    • manifest 從AndroidManifest.xml檔案中讀取apk的全域性資訊,如packageName、versionCode等。
    • fileSize 列出超過一定大小的檔案,可按檔案字尾過濾,並且按檔案大小排序
    --min   檔案大小最小閾值,單位是KB
    --order   按照檔案大小升序(asc)或者降序(desc)排列
    --suffix   按照檔案字尾過濾,使用","作為多個檔案字尾的分隔符
    
    • countMethod 統計方法數
    group   輸出結果按照類名(class)或者包名(package)來分組
    
    • checkResProguard 檢查是否經過了資源混淆 (AndResGuard)
    • findNonAlphaPng 發現不含alpha通道的png檔案
    • checkMultiLibrary 檢查是否包含多個ABI版本的動態庫
    • uncompressedFile 發現未經壓縮的檔案型別(即該型別的所有檔案都未經壓縮)
    suffix   按照檔案字尾過濾,使用","作為多個檔案字尾的分隔符
    
    • countR 統計apk中包含的R類以及R類中的field count
    • duplicatedFile 發現冗餘的檔案,按照檔案大小降序排序
    • checkMultiSTL 檢查是否有多個動態庫靜態連結了STL
    • unusedResources 發現 apk 中包含的無用資源
    rTxt   R.txt檔案的路徑(如果在全域性引數中給定了--input,則可以省略)
    ignoreResources   需要忽略的資源,使用","作為多個資源名稱的分隔符
    
    • unusedAssets 發現apk中包含的無用assets檔案
    • ignoreAssets 需要忽略的assets檔案,使用","作為多個檔案的分隔符
    • unstrippedSo 發現apk中未經裁剪的動態庫檔案

除了直接在命令列中帶上詳細引數外,也可以將引數配置以 json 的格式寫到一個配置檔案中,然後在命令列中使用
指定配置檔案的路徑。一個典型的配置檔案格式如下:

{
    "--apk": "/xxx",
    "--formatConfig": [
        {
            "group": [
                {
                    "name": "Android System",
                    "package": "android"
                },
                {
                    "name": "java system",
                    "package": "java"
                },
                {
                    "name": "xxx",
                    "package": "com.xxx"
                }
            ],
            "name": "-countMethod"
        }
    ],
    "--format": "mm.html,mm.json",
    "options": [
        {
            "name": "-manifest"
        },
        {
            "--suffix": "png, jpg, jpeg, gif, arsc",
            "--min": "10",
            "name": "-fileSize",
            "--order": "desc"
        },
        {
            "--group": "package",
            "name": "-countMethod"
        },
        {
            "name": "-checkResProguard"
        },
        {
            "--min": "10",
            "name": "-findNonAlphaPng"
        },
        {
            "name": "-checkMultiLibrary"
        },
        {
            "--suffix": "png, jpg, jpeg, gif, arsc",
            "name": "-uncompressedFile"
        },
        {
            "name": "-countR"
        },
        {
            "name": "-duplicatedFile"
        },
        {
            "name": "-unusedAssets",
            "--ignoreAssets": [
                "*.so"
            ]
        }
    ],
    "--output": "/xxx"
}

其中,mm.html 和 mm.json 是微信使用的自定義輸出格式,Matrix-ApkChecker 預設提供 html 、json、mm.html 以及 mm.json 四種輸出格式。
要注意的是所有路徑都必須是絕對路徑,如果是windows系統的話複製資料夾的路徑是反斜槓(),會報轉義錯誤,改為正斜槓(/)

使用配置檔案命令如下:

java -jar matrix-apk-canary-0.4.10.jar --config 配置檔案路徑

輸出這麼一串程式碼就代表執行成功

Matrix-ApkChecker的功能

  • 讀取manifest的資訊

從AndroidManifest.xml檔案中讀取apk的全域性資訊,如packageName、versionCode等

  • 按檔案大小排序列出apk中包含的檔案

列出超過一定大小的檔案,可按檔案字尾過濾,並且按檔案大小排序

  • 統計方法數

統計dex包含的方法數,並支援將輸出結果按照類名(class)或者包名(package)來分組

  • 檢查是否經過了資源混淆(AndResGuard)

檢查apk是否經過了資源混淆,推薦使用資源混淆來進一步減小apk的大小

  • 搜尋不含alpha通道的png檔案

對於不含alpha通道的png檔案,可以轉成jpg格式來減少檔案的大小

  • 檢查是否包含多個ABI版本的動態庫

so檔案的大小可能會在apk檔案大小中佔很大的比例,可以考慮在apk中只包含一個ABI版本的動態庫

  • 搜尋未經壓縮的檔案型別

某個檔案型別的所有檔案都沒有經過壓縮,可以考慮是否需要壓縮

  • 統計apk中包含的R類以及R類中的field count

編譯之後,程式碼中對資源的引用都會優化成int常量,除了R.styleable之外,其他的R類其實都可以刪除

  • 搜尋冗餘的檔案

對於兩個內容完全相同的檔案,應該去冗餘

  • 檢查是否有多個動態庫靜態連結了STL

如果有多個動態庫都依賴了STL,應該採用動態連結的方式而非多個動態庫都去靜態連結STL

  • 搜尋apk中包含的無用資源

apk中未經使用到的資源,應該予以刪除

  • 搜尋apk中包含的無用assets檔案

apk中未經使用的assets檔案,應該予以刪除

  • 搜尋apk中未經裁剪的動態庫檔案

動態庫經過裁剪之後,檔案大小通常會減小很多

示例分析

下面,我們對一個示例apk使用Matrix-ApkChecker進行檢查,並根據檢查的結果進行鍼對性的減包優化。
從Matrix-ApkChecker的輸出結果中可以看到示例apk的相關全域性資訊如下圖所示:

示例 apk 中包含的檔案按型別統計如下圖所示:

png檔案(不包括 .9.png)未經壓縮,可以考慮一定程度的壓縮

存在一些冗餘的檔案,檔案內容相同的檔案應該只保留一份

存在無用資源,包括未使用的系統support包中的資源、第三方資源包中的無用資源以及示例app定義的資源

存在無用的assets資源,應該刪除

後續

瞭解完Matrix-ApkChecker的基本功能後,後續考慮整合到jenkins中,每次編譯產出Apk時執行指令碼記錄apk的總大小值,對比每個版本的包大小總值,dex、so、圖片資源各自佔比、是否有重複資源、是否有圖片未壓縮等,如果能每個版本檢查出上述問題並提出優化建議,那麼在持續整合中價值就比較大

參考
https://github.com/Tencent/matrix/wiki/Matrix-Android-ApkChecker

相關文章