優(yōu)化安裝包大小

前言

周末跟朋友交流 app 新功能時,發(fā)現(xiàn)還沒更新,于是打開 app store 準備更新,發(fā)現(xiàn)由于包太大了(下載大于 150M),無法使用蜂窩數(shù)據(jù)下載,周圍又沒有 WIFI,非常尷尬。這件事讓我意識到包大小對 app 運營的影響。本篇文章基于這次優(yōu)化安裝包大小的實踐,整理了幾個的可行方案,并將圖片的優(yōu)化做了自動化腳本 AppThinning

AppThinning

IPA 安裝包構成

想要優(yōu)化安裝包,最直接的想法就是分析下安裝包的構成,做針對性的優(yōu)化。

image

整理歸類后大致如下:

  • 可執(zhí)行文件(Mach-O)
  • 資源文件
    • 圖片:png、jpg、bundle、Assets.car 等
    • xib、storyboard
    • 其他資源:音視頻、文本、網(wǎng)頁等
  • Framework

App Thinning

了解完安裝包構成,接下來我們應該找些方法來解決它。下面先介紹下蘋果的方案 App Thinning。

App Thinning 是 iOS 9 之后引入的一項優(yōu)化,主要包括三項功能:Slicing、Bitcode、On-Demand Resources。

Slicing

image

根據(jù)蘋果官方文獻的描述「Slicing 是為應用捆綁包創(chuàng)建、分發(fā)不同變體以適應不同目標設備的過程。一個變體只包含針對某個目標設備的可執(zhí)行架構與資源?!?換句話說,App Slicing 僅向設備傳送與之相關的資源(取決于屏幕分辨率,架構等等),具體如下圖所示。

image

需要注意的是,圖片資源需要放在 Asset Catalog 中才能實現(xiàn) App Slicing。

Bitcode

Bitcode 是一種程序中間碼。包含 Bitcode 配置的程序將會在 App store 上被編譯和鏈接。Bitcode 使用最新的編譯器自動編譯 app 并且針對特定架構進行優(yōu)化。Bitcode 不會下載應用針對不同架構的優(yōu)化,而僅下載與特定設備相關的優(yōu)化,同時與前文所述的 App Slicing 配合實現(xiàn),使得下載量更小。這部分都是在服務端自動完成的,所以假如以后 Apple 推出了新的 CPU 架構或者以后 LLVM 推出了一系列優(yōu)化,我們也不再需要為其發(fā)布新的安裝包了,Apple Store 會為我們自動完成這步,然后提供對應的 variant 給具體設備。

image

需要注意的是,開啟 Bitcode 需要全部支持,包括依賴的靜態(tài)庫、動態(tài)庫。

On Demand Resources

On-Demand Resource,就是將一部分資源放置在蘋果的服務器上,不隨著 App 的下載而下載,直到用戶真正進入到某個頁面時才下載這些資源文件。這種模式非常適合游戲的解鎖關卡

image
image

關于 On Demand Resources,目前還未實踐過,這里不深入介紹,感興趣的可以查看蘋果的文檔。

包實際大小

當我們上傳包到 App Store Connect 后,需要等到 completed processing 后才能查看 app。而這段時間,蘋果服務器幫我們做 App Thinning 的一些操作,生成各類設備對應的包。在活動-》所有構建版本中可以看到實際的下載和安裝大小。

image

優(yōu)化方案

優(yōu)化包大小問題,我們很自然能想到的幾個方案是:

  • ”刪”:刪除無用文件
  • “壓”:壓縮大文件
  • “改”:改變資源獲取方式、存儲方式等

圖片資源

圖片資源占用的空間是最大的, 應優(yōu)先考慮處理圖片資源。

“刪”

FengNiao

image

LSUnusedResources

image

需要注意的是,這類工具存在一點問題,會出現(xiàn)誤報,不過可以作為參考,幫助找出無用文件。

“壓”

壓縮工具

ImageOptim

image

ImageOptim 支持 PNG/JPEG/GIF 動畫,本質是各種影像優(yōu)化工具的圖形前端:AdvPNG、OptiPNG、Pngcrush、JpegOptim、jpegtran、Gifsicle 和 PNGOUT 素材。

  • 優(yōu)點:無損、 小巧
  • 缺點:壓縮比一般、壓縮速度一般

另外 ImageOptim 提供了命令行工具 ImageOptim-CLI

tinypng

在線圖片壓縮平臺,特點是速度快,壓縮比高。

image
  • 優(yōu)點:壓縮比高(正??蛇_ 50% ~ 70%)、壓縮速度快
  • 缺點:每次最多只能處理 20 張圖片、每張圖片不能超過 5MB、圖層較多時有可能出現(xiàn)像素損失情況(但概率很低)

另外 tinypng 提供了 api 調用形式,每個月免費 500 張。

經(jīng)實踐,tinypng 的壓縮比和速度都較優(yōu)秀,強烈建議優(yōu)先使用 tinypng 壓縮。當 tinypng 不能滿足要求時,可以選擇 ImageOptim。

Bundle

優(yōu)先壓縮 Bundle 內的圖片,因為 Bundle 里面的圖片不支持 App Slicing。

Assets.car

安裝包中,除了在 Bundle 中的圖片,其他的圖片主要包含在 Assets.car 中。
Assets.car 是 Assets.xcassets 經(jīng)過編譯后的文件。通過分析 Assets.car 文件,可以幫助我們找出大文件。

AssetCatalogTinkerer

[圖片上傳失敗...(image-d3d4a8-1568800701765)]

AssetCatalogTinkerer 是一款開源的查看和提取 car 文件中的圖片工具。

image

導出所有圖片后,就可以根據(jù)大小排序找到大文件,進行對應的壓縮處理。

assetutil

assetutil 是 xcode 自帶的命令行工具。使用 assetutil 分析 Assets.car 可以獲取到圖片更詳盡的數(shù)據(jù),比如:AssetType、Colorspace、SizeOnDisk 等。

xcrun --sdk iphoneos assetutil --info Assets.car
[
  {
    "AssetStorageVersion" : "IBCocoaTouchImageCatalogTool-10.0",
    "Authoring Tool" : "@(#)PROGRAM:CoreThemeDefinition  PROJECT:CoreThemeDefinition-346.29\n",
    "CoreUIVersion" : 498,
    "DumpToolVersion" : 498.4,
    "Key Format" : [
      "kCRThemeAppearanceName",
      "kCRThemeScaleName",
      "kCRThemeIdiomName",
      "kCRThemeSubtypeName",
      "kCRThemeDeploymentTargetName",
      "kCRThemeIdentifierName",
      "kCRThemeElementName",
      "kCRThemePartName",
      "kCRThemeDimension1Name",
      "kCRThemeDimension2Name"
    ],
    "MainVersion" : "@(#)PROGRAM:CoreUI  PROJECT:CoreUI-498.40.1\n",
    "Platform" : "ios",
    "PlatformVersion" : "9.0",
    "SchemaVersion" : 2,
    "StorageVersion" : 15
  },
  {
    "AssetType" : "Vector",
    "Colorspace" : "srgb",
    "Height" : 500,
    "Idiom" : "universal",
    "Name" : "next-joystick-progress",
    "RenditionName" : "next-joystick-progress",
    "SizeOnDisk" : 9324,
    "Width" : 1246
  },
  {
    "AssetType" : "Vector",
    "Colorspace" : "srgb",
    "Height" : 100,
    "Idiom" : "universal",
    "Name" : "next-success-icon-1",
    "RenditionName" : "next-success-icon",
    "SizeOnDisk" : 4385,
    "Width" : 100
  }
  ...

若圖片較多,可導出到文本查看

xcrun --sdk iphoneos assetutil Assets.car -I -o out.text

“改”

圖片管理方式

因圖片資源需要放在 Asset Catalog 中才能實現(xiàn) App Slicing。因此,圖片盡量使用 Asset Catalog 管理。

圖片格式

細心的朋友在分析 Assert.car 的時候會發(fā)現(xiàn),在 Assets.xcassets 放的 pdf 文件在編譯后生成了 png 文件放在 Assert.car 中。
有些尺寸較大的 pdf 文件,本身文件大小很小,但是編譯生成的 png 文件卻很大。
下圖樣式的 pdf 文件,大小為 10K,編譯生成后的 png 確是 2M 多。

image

Why I don’t use PDFs for iOS assets 中也講述了 pdf 的一些壞處。

那 pdf 就一定不好嗎?
答案是否定的。蘋果之所以支持 pdf,是因為向后兼容的問題。圖片使用 pdf 格式,編譯后自動生成 1x 和 2x 以及 3x png 圖片,若以后屏幕質量提升了,出現(xiàn)了 4x 設備,那使用 pdf 的 app 就會生成 4x 的圖自動適配,跟 BitCode 的思想如出一轍。

那何時使用 pdf 何時使用 png 呢?
pdf 生成 png 的規(guī)則是,按 pdf 的原始尺寸作為 1x 的大小。因此,尺寸較大的圖片不適合使用 pdf 格式。
經(jīng)實踐,發(fā)現(xiàn)若圖片是使用矢量工具直接畫出來的圖片(可矢量化),且尺寸較小的圖片,比較適合 pdf 格式;若圖片是拍攝的渲染圖則推薦使用 png。

存儲方式

包內不適合存放大圖片,大圖盡量使用網(wǎng)絡形式獲取。

其他資源

“刪”

參考處理圖片資源的工具,找到無用的資源文件,進行刪除。

“壓”

網(wǎng)頁資源

讓前端人員使用 webpack 打包并壓縮代碼后,再加入 iOS 工程。

音頻文件

mp3smaller

視頻文件

How To Compress a Video File Without Losing Quality

可執(zhí)行文件(Mach-O)

這部分的優(yōu)化,主要包含兩部分:

  • 文件優(yōu)化
  • 編譯優(yōu)化

文件優(yōu)化

  • 使用 FengNiao 和 LSUnusedResources 查找并刪除無用類
  • 刪除無用方法、引用
  • 刪除重復代碼

工具推薦:

  • fui 幫助查找無用引用。
  • PMD 靜態(tài)代碼掃描工具幫助查找重復代碼。
    image
  • AppCode 幫助查找無用的類、無用的方法甚至是無用的 import ,但是無法掃描通過字符串拼接方式來創(chuàng)建的類和調用的方法。
    image
  • LinkMap 幫助檢查到底是哪個類、哪個第三方庫占用了太多空間
    image

這部分的優(yōu)化非常有限,因為類文件都是文本,對于包的體積幫助很小,但是對于 Clean Code 卻顯得很重要,這里就不再贅述。

編譯優(yōu)化

  • Architectures
image

若項目不需要再支持 32 位,可以去除 armv7,這樣可執(zhí)行文件以及庫的大小,必然會大大減小。

  • Generate Debug Symbols

Generate Debug Symbols 決定是否生成調試符號。開啟時會生成 symbols 文件,關閉時 ipa 中不會生成 symbol 文件,可以減少 ipa 大小,但會影響到崩潰的定位。

推薦:保持默認開啟或者 debug 關閉、release 開啟。

  • Swift Compiler - Code Generation

    • Optimization Level
image
分為 6 個級別:

- None[-O1]:代碼沒有優(yōu)化,編譯時間最快。
- Fast[-O,O1]:適度優(yōu)化,沒有顯著的降低編譯時間,在編譯過程中使用更多的內存。
- Faster[-O2]:幾乎全面優(yōu)化,生成高度優(yōu)化的代碼,編譯器不執(zhí)行循環(huán)展開或函數(shù)內聯(lián),編譯時間較慢。
- Fastest[-O3]:全面優(yōu)化,編譯器執(zhí)行內聯(lián)函數(shù)。**這個選項通常不推薦。有關更多信息,請參見[避免過度內聯(lián)函數(shù)](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/CodeFootprint/Articles/CompilerOptions.html#//apple_ref/doc/uid/20001861-131770)**。
- Fastest,Smallest[-Os]:全面優(yōu)化,優(yōu)化程序的空間使用,通常不增加代碼大小,并且更小的內存占用。
- Fastest,Aggressive Optimizations[-Ofast]:蘋果文檔上無詳細說明。

詳見[蘋果文檔](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/CodeFootprint/Articles/CompilerOptions.html#//apple_ref/doc/uid/20001861-CJBJFIDD)

推薦:debug 模式下選擇 None 保證編譯速度;release 模式下選擇 Fastest,Smallest[-Os]。

  • Compilation Mode
image
有兩個選項:

- Incremental:逐個文件進行優(yōu)化,它的好處是對于**增量編譯的項目來說,它可以減少編譯時間**,對沒有更改的源文件,不用每次都重新編譯。并且可以充分利用多核 CPU,并行優(yōu)化多個文件,提高編譯速度。但它的缺點就是對于一些需要**跨文件的優(yōu)化操作,它沒辦法處理**。如果某個文件被多次引用,那么對這些引用方文件進行優(yōu)化的時候,會反復的重新處理這個被引用的文件,如果你項目中類似的交叉引用比較多,就會影響性能。
- Whole Module:將項目所有的文件看做一個整體,不會產(chǎn)生 Incremental 模式對同一個文件反復處理的問題,并且可以進行最大限度的優(yōu)化,包括跨文件的優(yōu)化操作。缺點是,不能充分利用多核處理器的性能,并且對于增量編譯,每次也都需要重新編譯整個項目。

推薦:debug 模式下選擇 Incremental;release 模式下選擇 Whole Module。

其他選項,大家可以參考蘋果文檔的 Managing Code Size 章節(jié)。

Framework

image

在 Framework 中可以看到系統(tǒng)的 dylib 和第三方的 framework。這部分可以根據(jù)項目的功能,查找未使用的庫并刪除。
如果使用了 Swift,則項目會加入 swift 的 dylib。關于這點,有些 iOSer 放棄了 swift 回退到了 oc。個人覺得這個選擇并不明智,swift 有許多優(yōu)秀的特性,如果僅僅因為 swift 庫的大小而轉向 oc 太不值當了。

自動化

基于本次實踐,本人寫了一個腳本 AppThinning,幫助自動找到大文件,然后進行圖片壓縮(imageOptim、TinyPng 可選),目前只支持圖片文件的壓縮,后續(xù)會加上更多類型的壓縮,以將安裝包大小的問題自動化。當然,更推薦大家將腳本放到持續(xù)集成中,當成集成的一部分。

總結

至此,常見的優(yōu)化安裝包大小的方法都已介紹完畢。大家可以根據(jù)自己項目的特點,合理選擇。從本次優(yōu)化的實踐,個人覺得,首先應該優(yōu)化圖片資源,這是最簡單,也是最有效的。其次,刪除無用的文件、方法等不但可以減少體積,而且可以讓代碼變得更 Clean。持續(xù)集成中有一句老話,“如果你遇到一件很痛苦的事情,似乎比較好的建議就是更頻繁地做這件事情”。所以我們不妨把 Clean Code 作為習慣,這樣代碼永遠都是干凈的,也就不需要想著什么時候優(yōu)化大小的問題。最后一點,不要做一個只會碼代碼的程序員,學點產(chǎn)品思維,或許砍需求是最有效的優(yōu)化安裝包大小的方法

感謝

iOS 瘦包,常見方式梳理
干貨|今日頭條iOS端安裝包大小優(yōu)化—思路與實踐

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容