最全的 iOS 包大小技術總結

前言

包大小是衡量 APP 性能的一項重要指標,它直接影響用戶的下載點擊率(包太大不想下)、下載安裝成功率(下載慢不用了)、APP 卸載率(太佔空間先刪掉)。

包大小的計算邏輯很簡單,它是各種類型的文件佔用磁盤大小相加。APP 瘦身的技術卻很複雜,代碼文件的複雜度和編譯器策略決定了可執行文件的大小,業務功能和工程架構決定了代碼文件的複雜度。iOS APP 瘦身,需要掌握的技能有 XCode 構建技術、LLVM 編譯器技術、CocoaPods 構建技術、圖片壓縮技術、持續集成技術。

本文總結提煉了 Alibaba.com App 的瘦身的技術和策略,系統化地介紹 APP 瘦身的業務價值、分析技術、瘦身技術、防劣化機制,讓讀者可以系統化地瞭解 APP 瘦身的技術體系。本文還基於實踐經驗,介紹各種瘦身技術的 ROI,讓讀者可以避免踩雷,將資源浪費在效果不佳的技術上。希望對你有所幫助。

業務價值

包體大小每上升 6MB,應用下載轉化率就會下降 1%

在 2019 谷歌開發者大會上,谷歌給出了一個很詳細的數據,包體大小每上升 6MB,應用下載轉化率就會下降 1%。不同地區轉化率略有差異,APK 包體大小每減少 10MB ,全球平均下載轉化率會提升 1.75%,新興國家代表印度和巴西下載轉化率提升 2.0% 以上,高端市場代表美國和德國下載轉化率提升 1.5%。

上圖標題:APK 減少 10MB,在不同國家轉化率增長

數據來源:google play 內部數據

詳細材料:白鯨出海:2019 谷歌開發者大會首日看點:Google Play 的新變化 [1];googleplaydev:Shrinking APKs, growing installs[2]

上述數據調研分析報告是 2019 年以前,已經有所滯後,僅供參考

包大小影響下載轉化率可能有 3 個原因:

  1. 蜂窩網絡環境下,用戶不願意支付流量費用。包大小超過 200MB 時,App Store 會彈框提醒用戶下載可能會產生流量費用

  2. 下載時間太長,用戶不願意等就取消了

  3. 下載過程中出現網絡連接問題

雖然 Google Play 沒有給出不同 APP 類目的數據,但是從以上三個原因推斷,不同類目包大小對下載轉化率的影響估計差不多。App Store 的用戶人羣比較高端,可以參考美國和德國的數據。

20% 的人因爲存儲空間有限而卸載應用程序

clevertap 在 2021 年做了一項調查,他們調查了 2000 多個移動應用程序用戶,詢問了他們卸載移動應用程序的主要原因,其中有 20% 的人因爲存儲空間有限而卸載應用程序。

最主要的 3 個原因是:

  1. 他們不再使用該應用程序

  2. 有限的存儲空間

  3. 太多的廣告。

詳細材料:clevertap:Why Users Uninstall Apps[3]

App Store 發佈和下載限制

兼容 iOS8 的 App,主二進制文件的 Text 段不能超過 60MB, 否則將無法提交 App Store。App Store 下載包超過 200MB,無法使用蜂窩流量下載和更新。

分析技術

APP 瘦身最終目標是減少 App Store 的安裝包大小和下載包大小,但研發階段對比 XCode 構建包大小會更方便,需要理清楚他們之間的口徑差異。

結果指標:App Store 安裝包大小和下載包大小

查看路徑是 App Store Connect->TestFlight-> 交付版本 -> 構建版本元數據 ->App Store 文件大小

過程指標:XCode 構建包大小

XCode 構建產物 ipa 包的大小和 App Store 的安裝大小口徑差異很大,通過模擬 Apple 處理的流程可以得到它們的關係。開發者上傳的 ipa 包裏有多個架構的產物,多套尺寸的圖片資源,蘋果會進行裁剪和二次分發,轉化爲 App Store 下載的 ipa 包。

構建產物 ipad 包大小:靜態庫二進制文件(arm64、armv7)、動態庫(arm64、armv7)、asset.car(@2x、@3x)、其他資源文件

App Store 的安裝大小:靜態庫二進制文件(單架構)、動態庫(單架構)、asset.car(單尺寸)、其他資源文件

使用 lipo 工具拆分單架構

lipo "originalExecutable" -thin arm64 -output "arm64Executable"

使用 assetutil 工具拆分 asset

xcrun --sdk iphoneos assetutil --scale 3 --output "$targetFolder/Assets3.car" "$sourceFolder/Assets.car"

構建包組成

學習如何治病前,得先了解人體的構成。同樣的道理,我們首現要了解 iOS 工程結構和 IPA 包結構。

iOS 工程結構: iOS 工程由殼工程和 Pod 模塊組成,模塊有靜態庫和動態庫兩種類型。殼工程的構成有主 Target、Apple 插件 Target。模塊內部的構成有源代碼文件(OC、C、C++ 的. h 和. m)、nib、bunlde、xcassets、多語言文件、各種配置文件 (plist、json)。

IPA 包結構:iOS 上傳到 App Store 是 IPA 包,IPA 包解壓後是一個文件夾,內部由各種類型的文件構成,主要包括 MachO 可執行文件、.framework(動態庫)、Assets.car、.appex(Apple 插件)、.strings(多語言)、.bundle、nib、json、png...。

從 iOS 工程到 IPA 包:iOS 工程構建爲 IPA 包,核心的變化是編譯和文件拷貝,靜態庫裏的源代碼會被編譯爲 MachO 可執行文件,xcassets 文件夾會被轉化爲 Assets.car,其他都可以簡單理解爲文件拷貝。

通過分析構建包的組成,可以判斷有哪些優化空間。如果動態庫佔比太高,就可能有大量可裁剪代碼。建議根據資源大小敏感程度劃分,比如:MachO executeable(包含所有靜態庫)、動態庫、Apple Extension、assets.car、bundle、nib、音頻、視頻。

Pod 模塊大小

APP 瘦身會涉及大量業務模塊,離不開業務團隊的參與。因此,我們需要分析出每個 Pod 模塊的大小,從而可以橫向比較各個業務團隊的包大小佔比。靜態庫和動態庫計算的原理不同。對於靜態庫,先解析 linkmap 數據,計算出 Pod 模塊代碼大小,在解析 Pods-targetName-resource.sh 的資源拷貝代碼,計算出拷貝到 Pod 模塊的資源大小。對於動態庫,先使用 lipo 拆分動態庫的二進制文件,計算出單架構的代碼大小,然後再計算動態庫 framework 內的資源文件,得到動態庫的資源文件大小。

運行時 Objc 類覆蓋率

如果能知道 App 運行時有哪些類被使用過,就可以下線掉無用的模塊或代碼文件,Objc 類覆蓋率指標可以幫到我們。APP 運行時,某 1 個 Pod 模塊被加載的類數量除以所有類數量,可以稱爲這個模塊的 Objc 類覆蓋率。核心技術是判斷一個類是否被加載過,下面介紹一個經過線上驗證的輕量級方案。ObjC 的類第一次被使用時會調用 + initialize 方法,類被加載過後 cls->isInitialized 會返回 True。isInitialized 方法讀取了 metaClass 的 data 變量裏的 flags,如果 flags 裏的第 29 位爲 1,則返回 True。

// objc-class.mm
Class class_initialize(Class cls, id inst) {
    if (!cls->isInitialized()) {
        initializeNonMetaClass (_class_getNonMetaClass(cls, inst));
    }
    return cls;
}

// objc-runtime.h
#define RW_INITIALIZED        (1<<29)
bool isInitialized() {
    return getMeta()->data()->flags & RW_INITIALIZED;
}

未被使用的圖片資源

技術原理是先解析出所有拷貝到構建產物的資源文件,再解析出代碼中實際引用到的資源文件,兩者的差集就是無用資源。

第一步獲取全量資源文件。在 Cocoapos 工程中,“Pods-targetName-resource.sh” 腳本負責拷貝 Pod 裏的文件資源到構建產物,包括所有文件類型 bundle、xcassets、json、png。解析該腳本可以得到每個 Pod 模塊都拷貝了哪些圖片資源。

// Pods-targetName-resource.sh
install_resource "${PODS_ROOT}/APodName/APodName.framework/APodName.bundle"
install_resource "${PODS_ROOT}/BPodName/BPodName.framework/BPodName.xcassets"
install_resource "${PODS_ROOT}/BPodName/BPodName.framework/xxx.png"

第二步,獲取代碼中實際引用到的資源文件。OC 代碼中引用資源文件都是以字符串字面量的形式聲明,構建後存放在 Mach-O 文件 "__cstring" section。利用 strings 解析 framework 的二進制文件就可以得到代碼中所有的字符串聲明,然後基於代碼的各種引用方式匹配 “xxx”,"xxx@2x.png","xxx.png","xxx.bundle/xxx.png"

strings executable | grep 'xxx' > cstrings.txt

編譯時未被引用的類

iOS 編譯的產物是 Mach-o 格式的,文件裏 __DATA __objc_classrefs 段記錄了所有引用過的類的地址,__DATA __objc_classlist 段記錄了所有類的地址,兩者 Differ 可以得到未被引用類的地址。然後將地址符號化,就可以得到未被引用類信息。因爲 Objc 是動態語言,如果使用 runtime 動態調用某個 class,這種情況掃描不出來。(比如 Target Action 和 JS Core)

otool -v -s __DATA __objc_classrefs xxxMainClient  #讀取__DATA Segment中section爲__objc_classrefs的符號
otool -v -s __DATA __objc_classlist xxxMainClient #讀取__DATA Segment中section爲__objc_classlist的符號
nm -nm xxxMainClient

掃描未使用類的開源工具 [4]

瘦身技術

包大小瘦身可以從純技術視角瘦身,也可以從邏輯視角瘦身。

從純技術視角有兩種思路,第一種思路是優化編譯邏輯, 第二種思路是刪減各種其他類型(非編譯產物)的文件。編譯優化對業務邏輯無侵入式,風險和成本比較低,但收益通常也不高。刪減文件則比較複雜,刪減資源文件收益高但成本不小,逐個刪減源碼文件風險高且收益小。

相比而言,從邏輯的視角瘦身效果會更明顯。站在邏輯的視角,工程是由許多功能模塊組成的,主要可以分爲業務功能模塊(首頁、搜索、收銀臺、訂單)、基礎功能模塊(網絡庫、圖片庫、中間件、各種三方庫...)。大型工程通常幾百甚至上千個模塊組成,小模塊的有幾十 KB,大的模塊有 1MB~10+MB。功能模塊內聚性強,當某個功能模塊可以廢棄或被替代時,整體下線的風險和成本比較低,ROI 很高。

瘦身技術大圖

根據項目經驗,我梳理出各種優化方法的 ROI,下面依次介紹。

組件瘦身

組件瘦身的 ROI:類加載率 0% 的組件 > 無用功能組件 > 重複功能組件

“類加載率 0% 的組件” 是一個完整的 Pod 模塊,模塊的代碼和資源可以被整體刪除,ROI 最高。“無用功能組件” 通常是模塊內某個文件目錄,需要處理一些耦合,梳理資源的歸屬,ROI 其次。“重複功能組件” 需要適當重構,遷移成本和風險最高,ROI 相對較低。

類加載率 0% 的組件

“類加載率 0% 的組件” 是指運行時沒有任何一個類被加載過的組件,它在運行過程中完全沒有用到,可以整體下線。統計類加載率時一般會進行採樣,有些低頻業務組件可能會誤報,下線前需要和業務 Owner 二次確認。

無用功能組件

“無用功能組件” 是邏輯上已經沒用的組件,它可能代碼還有耦合,但邏輯已經沒用,通過重構就可以下線。比如 AB 實驗沒效果的業務代碼、往年大促的業務代碼、業務改版後遺留的老業務、已經過時的三方庫。

重複功能組件

對於大規模團隊,不同業務線可能會引入 “重複功能組件”,比如圖片選擇器、緩存庫、UI 組件。重複的功能組件會帶來不必要的包大小壓力,同時也會帶來維護成本。

資源瘦身

資源瘦身 ROI:大資源 > 有損壓縮 > 重複資源 > iconfont > 多語言文案瘦身 > 無用資源

大資源

對大資源進行單點優化收益很大,優先分析 100KB 以上的資源。比如音頻文件,我們工程中音頻鈴聲 900KB,優化後去掉了 700KB。

有損壓縮

XCode 構建時會做 “compile asset catalog”,會重新對圖片進行無損壓縮。因此使用 imageoptim 等工具進行無損壓縮效果不明顯,其中壓縮 png 圖片沒有效果,壓縮 jpg 圖片有一定效果。根據實踐經驗,icon 做有損壓縮並不影響視覺體驗,壓縮率可以達到 70%~80%。比如使用 tinypng 算法壓縮一張 425.9 KB 的 png 圖片,壓縮後 79.8 KB,壓縮率達到 81%。業界有不少 png 壓縮工具,我們使用到的有 tinypng[5]、pngquant[6]、pngcrush[7]、optipng(無損)[8]、advpng[9]。實測發現不同的圖片,壓縮效果最好的工具是不一樣,所以壓縮圖片時可以用每個工具嘗試,然後取效果最好的。需要注意的是,壓縮 APNG 圖片可能會變成非動圖,儘量避免對 APNG 圖片進行壓縮,壓縮前先識別是否 APNG 圖片。

# 判斷是否APNG格式,APNG格式不壓縮
function isApng() {
    ret=`grep "acTL" "$1"`
    lastWord="${ret##* }"
    if [[ $lastWord == "matches" ]]; then
        echo "YES"
    else
        echo "NO"
    fi
}
# 使用各種工具壓縮png圖片
# pngquant
pngquant  256 -s5 --quality 70 --output "${tmpFileName}" -- "${tmpOrigName}" 
# pngcrush
pngcrush -brute -rem alla -nofilecheck -bail -blacken -reduce -cc -- "$tmpOrigName" "$tmpFileName"
# optipng
optipng -o6 -i0 -out "$tmpFileName" -- "$tmpOrigName"
# advpng
cp "$tmpOrigName" "$tmpFileName"
advpng -4 -z -- "$tmpFileName"

# 逐個比較壓縮效果,保留效果最好的壓縮圖片
sizeBefore=`stat -f%z "${tmpOrigName}"`
sizeBefore=`expr $sizeBefore`
sizeNow=`stat -f%z "${tmpFileName}"`
sizeNow=`expr $sizeNow`

if [ "$sizeNow" -lt "$sizeBefore" ]; then
  # 大小變小了
  echo "[advpng] $tmpOrigName"
  retImg="$tmpFileName"
fi

# 記錄hash值
img_sum=`/usr/bin/shasum -a 256 "$retImg" | cut -d " " -f1`
cache_file="$cacheFolder/$img_sum.png"

無用資源

業務長期迭代會積累許多無用的資源。通過代碼靜態掃描,可以分析出沒有被引用的圖片資源。我們有工程無用資源有 12MB,其中有 20 個模塊無用資源超過 100KB。

重複圖標

不同業務需求會引入重複資源,長期積累也會造成很大浪費。解決方案是在構建時計算資源的哈希值,去重相同哈希資源,並保留源文件名和哈希值的映射表。運行時 Hook 資源加載的”imageNamed“方法,根據映射表替換資源名稱。

ODR

iOS 不能像 Android 一樣,運行時更新 Framework。iOS 的 ODR 技術(On Demand Resource)提供了運行時動態下載的能力。如果啓動用不到的資源文件,可以通過 ODR 處理。

iconfont

iconfont 支持縮放、修改顏色,它 size 小,適合用於箭頭、佔位圖等圖標場景,使用 iconfont 可以減少包大小也能提高開發視覺體驗的統一性。首先,基於設計規範出一套完整的 iconfont,封裝 iconfont 組件,提供易用的 API。然後禁止新業務場景增加圖片資源,團隊形成開發習慣後再逐步替換存量的圖片。

多語言文案

對於國際化 App,多語言文案也是大頭。我們 App 支持 20 個語種,每個語種 4000 多條文案,文案總大小 6MB,瘦身後減少了 2MB。

編譯優化

編譯優化 ROI:Optimization Level > 動態庫複用主二進制靜態庫 > 鏈接器產物壓縮

XCode 編譯優化選項中,Optimization Level 效果最明顯,建議所有模塊構建都開啓 Oz 選項。如果 APP 有動態庫,並且依賴了 openssl 等基礎靜態庫,建議和 APP 工程共享,並通過 EXPORTED_SYMBOLS_FILE 的選型,確保動態庫中需要用到的符號都在編譯過程保留。如果團隊技術儲備強,可以自研鏈接器產物壓縮技術,效果也很大。具體效果如下。

精簡編譯產物 Oz:Optimization Level

Optimization Level 多個級別,-Oz 比 - O3 的編譯產物體積小 10% 左右。設置 - Oz 以後,XCode 會優化連續的彙編指令,從而減少二進制大小,但副作用是執行速度會變慢。C++ 工程建議都開啓。

主工程Release
Optimization Level :-Oz

Framework工程
Optimization Level :-Oz

LTO(OC/C++)

LTO 是在 LLVM 鏈接時,優化跨模塊調用代碼。根據大家分享的經驗,它不同 APP 包大小優化效果差異較大,需要具體測試。另外它也有一些副作用,建議只在 Release 包開啓。

LTO 介紹 [10]

優點:

主工程Release
Link-Time Optimization 設置爲Incremental

framework工程Release
Link-Time Optimization 設置爲Incremental

動態庫複用主二進制靜態庫

C++ 動態庫經常用到一些基礎庫比如 openssl、libyuv、libcurl,他們一般是靜態庫。如果動態庫引用了靜態庫,它編譯時默認會內嵌靜態庫的所有符號。雖然我們可以在動態庫中設置只導出需要用到的靜態庫符號,但是有可能多個動態庫都用到了同一個基礎庫,這樣還是會造成基礎庫的冗餘。比如 openssl 大小 1MB,如果 A、B 兩個動態庫依賴了 openssl,APP 也引用了 openssl,最終 ipa 包實際有 3 個 openssl,有 2MB 大小是冗餘的。

這種場景下,最佳解決方案是共享符號表,讓動態庫可以調用主二進制的基礎庫符號,從而可以去掉內置的靜態庫。只要修改 XCode 的 Link 配置,無需額外的代碼開發。

動態庫工程:

  1. 設置當遇到未定義的函數時,動態查找 APP 主二進制符號表。

  2. 關閉 bitcode

Other Linker Flags -> -undefined dynamic_lookup
Enable Bitcode -> No
  1. 導出動態庫需要調用的外部符號,寫到一個文件 exported_symbols 內
nm -u  xxx.framework/xxx > exported_symbols.txt

APP 工程:

  1. 配置需要導出 exported_symbols 文件內的所有符號,避免編譯時動態庫需要用到的符號被 strip 掉。

  2. 關閉 bitcode。

// exported_symbols.txt是需要被導出的符號文件路徑
EXPORTED_SYMBOLS_FILE -> exported_symbols.txt
Enable Bitcode -> No

如果 C++ 動態庫裏依賴了外部靜態庫,該靜態庫的符號默認會被全部導出。實際上動態庫只用了其中的部分符號,可以設置導出符號的白名單,從而減少導出沒有用到的靜態庫符號。

注意事項:

  1. APP 和 framwork 工程都要關閉 bitcode,否則編譯不過

  2. 如果多個動態庫都使用同一個基礎庫,導出的符號表需要取並集

  3. 動態庫升級要及時更新符號表,基礎庫升級要測試兼容性

鏈接器產物壓縮(黑科技)

iOS 工程構建產物是 MachO 文件,MachO 文件中的 TEXT 段存放了各種只讀的數據段,__cstring 段存放了普通的 C String,__objc_methtype 和__objc_methname 存放了 Objc 的方法簽名和方法名。比入 Objc 代碼中聲明的 @"Hello world",底層會產生一個 CFString,構建後存放在__cstring 中。這些數據很佔空間,一般工程至少會有 10MB 以上,壓縮的收益很可觀。我們上線後,App Store 安裝包大小從 191MB 優化到 174MB,減少了 16MB。

技術原理:鏈接時將 TEXT 段數據移到__DATA 段並壓縮,運行時先執行解壓代碼,解壓 TEXT 段數據存到自定義段中,將代碼中對字符串的引用的地址修正爲解壓後的自定義段。

剝離符號表:Strip Linked Product

Strip Linked Product 設置會剝離特定的符號,Debug 環境不要設置 YES,否則調試時看不到符號。

主工程Release
Deployment Postprocessing :YES
Strip Linked Product :YES
Strip Style :All Symbols(剝離所有符號表和重定向信息)

Framework工程
Deployment Postprocessing :YES
Strip Linked Product :YES
Strip Style :Non-Global Symbols(剝離包括調試信息等非全局的符號,保留外部符號)

說明:

  1. 靜態庫不能將 Strip Style 設置爲 All Symbols,因爲剝離了所有符號的靜態庫是無法被正常鏈接的

  2. 去除符號不影響 dSYM 文件中的符號信息,查看崩潰日誌時,可以從 dSYM 文件中找對應符號

Symbols Hidden by Default

Symbols Hidden by Default 用於設置符號默認可見性,如果設置爲 YES,XCode 會把所有符號都定義爲”private extern”,包大小會略有減少。動態庫設置爲 NO,否則會有鏈接錯誤。

主工程Release
Symbols Hidden by Default :Yes

Framework工程 靜態庫/動態庫
Symbols Hidden by Default :NO

剔除未引用的 C/C++/Swift 代碼:Dead Code Stripping

Dead Code Stripping 開啓後會在鏈接時移除未使用的代碼,它對靜態語言 C/C++/Swift 有效,對動態語言 OC 無效。

主工程
Dead Code Stripping :Yes

Asset Catalog Compiler

Optimization 有三個選項,空、time 和 Space,選擇 Space 可以優化包大小

主工程
Asset Catalog Compiler->Optimization設置爲space

C++ 只導出必要符號:Symbol Visibility

C++ 的靜態庫和動態庫都只導出必須的符號,默認設置爲隱藏所有符號,然後用 Visibility Attributes 單獨控制需要導出的符號

默認隱藏所有 C++ 符號

Other C++ Flags->添加-fvisibility=hidden

設置需要導出的符號

__attribute__((visibility("default"))) void MyFunction1() {} 
__attribute__((visibility("default"))) void MyFunction2() {} 
....

代碼下線

根據 Objc 類覆蓋率統計的結果,可以逐步下線掉未被使用的類。代碼文件的量級比較小,下線代碼需要仔細確認,避免引起功能問題或 crash,ROI 比較低。

Flutter 專項

Flutter 是單獨構建的,引入的內容包括 Flutter 引擎產物、Flutter 業務代碼產物。APP 如果引入 Flutter,需要對 Flutter 進行專項瘦身。

精簡編譯產物 Oz:Optimization Level

-Oz 選項相比 Os,收益預估 11%,但首屏性能 1%~9% 的損耗

Dart 符號剔除和混淆

根據官方文檔,可以通過 --dwarf-stack-trace 選項去除 Dart 標準的調試符號。通過 --obfuscate 選項,可以將較長的符號替換爲短符號,副作用是符號會被混淆。實踐效果:Release 環境下,--dwarf-stack-trace 和 --obfuscate 選項開啓後減少 14% 的大小

Flutter icon 搖樹優化

--tree-shake-icons 實踐效果:Alibaba.com App 開啓後減少了 300KB 左右大小

去除 NOTICES 文件

實踐效果:壓縮前 700KB,壓縮後 80KB

防劣化機制

增量標準和集成卡口

包大小瘦身的技術就像各種減肥運動,跑步、跳舞、燃脂瑜伽。但想達到減肥的目標,只靠運動是不夠的,還得控制卡路里的攝入,管住嘴的人最後才能減肥成功。因此,我們還需要” 新增卡路里的規範”(包大小增量規範)和監工(集成卡口)。持續集成當中加入一個卡口插件,分析構建包的 linkemap 文件得到模塊的大小可,然後對比基線數據,如果違反了包大小增量標準,則禁止集成。

包大小增量規範(參考):

  1. 基線數據:基於特定版本,通過上文提到的” 計算模塊大小 “的方法,計算出每個模塊的基線數據

  2. 存量模塊:模塊增量超過基準數據 100KB 時禁止集成。設置補償機制,如果能對存量模塊瘦身,可以抵消新增的模塊大小。對於特殊情況可以走特殊審批,加入審批流程是啓發大家反思。增加那麼多是否有價值?有沒有帶入不必要的資源?

  3. 新模塊:新業務功能需要走審批流程,評估新業務價值和包大小增量是否合理。

橫向對比業務健康度

當包大小從技術層面已經優化到極致時,想要進一步瘦身,只能從業務價值的角度去挖掘。如果一個模塊磁盤尺寸大,用戶使用量卻少,那可以認爲它對業務的價值較小。因此我們可以定義一個技術指標來衡量模塊單位大小的業務貢獻度。基於容積率指標,我們就可以橫向對比各個業務,要求容積率低的業務做包大小瘦身,或下線不太重要的業務功能。

容積率 = Business PV / Business size

總結

總結一下包大瘦身的實施路徑。第一步,制定目標,跟蹤 APP 下載轉化率(App Store Connect Analytics)、APP 安裝包大小、XCode 構建包大小等結果指標。第二步,建設分析體系,包括 Pod 模塊大小分析、Objc 類覆蓋率分析、無用圖片資源分析等。第三步,根據 ROI 使用各項瘦身技術,組件瘦身 > 資源瘦身 > 編譯優化 > 代碼下線. 第四步,建設防劣化機制,包括增量標準、集成卡口能力、健康度分析。

參考資料

[1]

白鯨出海:2019 谷歌開發者大會首日看點:Google Play 的新變化: http://www.baijing.cn/article/24808

[2]

googleplaydev:Shrinking APKs, growing installs: https://medium.com/googleplaydev/shrinking-apks-growing-installs-5d3fcba23ce2

[3]

clevertap:Why Users Uninstall Apps: https://clevertap.com/blog/uninstall-apps/

[4]

掃描未使用類的開源工具: https://github.com/xuezhulian/classunref

[5]

tinypng: https://tinypng.com/developers/reference/python

[6]

pngquant: https://pngquant.org/

[7]

pngcrush: https://pmt.sourceforge.io/pngcrush/

[8]

optipng(無損): https://optipng.sourceforge.net/

[9]

advpng: http://www.advancemame.it/doc-advpng.html

[10]

LTO 介紹: https://zhuanlan.zhihu.com/p/384160632

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Oig_SENGhTVQbDb33QxXbQ