對于矢量圖的調(diào)研, 最開始是始于對其占用iOS App的空間的好奇。筆者好奇一個問題: 利用矢量圖能不能幫助iOS App減少整體空間?
iOS其實在很早的時候就已經(jīng)支持矢量圖的應(yīng)用(XCode 6時代開始支持), 只不過因為大部分開發(fā)者沿用了以前@1x、@2x、@3x格式圖的習(xí)慣, 并沒有一個地方專門普及使用矢量圖。當(dāng)然, 還有另外一個原因就是iOS對復(fù)雜的矢量圖支持的不是很好。
本文并沒有特別深入的技術(shù)點, 僅僅只是筆者做的幾個實驗的總結(jié)和矢量圖基礎(chǔ)使用的教程普及~
矢量圖和iOS
關(guān)于矢量圖在iOS中的使用早在15年2月就有一篇博文介紹了它的使用 - iOS使用矢量圖的總結(jié)。筆者按照它的用法操作了一遍, 基本大同小異~ 針對該文章沒有涉及到的一些細節(jié), 筆者進行一定程度的補充。
iOS中矢量圖的使用方法
筆者為了做一下簡單的矢量圖實驗, 使用Sketch隨意拖了一個星星出來并導(dǎo)出一個PDF。(實際上UI繪制矢量圖的工具有很多很多, 這里不贅述。如果讀者懶得自己去導(dǎo)出, 可以直接挪用)
XCode支持矢量圖一定要放置在xcasset文件中才能夠生效, 操作步驟如下:
- 拖拽提前制作的PDF進入
XXX.xcassets中。 - 選擇
Image Set下的參數(shù)選項Scale Factors為Single Vector或Vector With Overrides - 如果圖形不在框框中, 拖入框框中(XCode某些版本不能自動對號入座)

Vector With Overrides是Single Vector的增強, 可以在放置完矢量圖之后繼續(xù)放置@1x、@2x和@3x的png格式的圖片。放置的png會優(yōu)先覆蓋矢量圖, 未放置對應(yīng)倍率圖片的設(shè)備才會使用矢量圖對應(yīng)生成的圖片。
矢量圖在iOS中的應(yīng)用原理
iOS對矢量圖的支持其實只是一種方便開發(fā)者的選擇, 本質(zhì)上在XCode編譯的階段矢量圖會自動生成對應(yīng)Target的@1x,@2x和@3x的png格式圖像。在iOS實際運行中使用的圖片實際上已經(jīng)是png格式的圖片了~

通俗的理解 - 放置在xcassets里的矢量圖會自動根據(jù)設(shè)備編譯成對應(yīng)尺寸的圖片, 如果是Generic iOS Device則會自動生成全尺寸的同名圖片。
PS: 自動生成的@1x圖會和矢量圖的原始尺寸保持一致。
下圖為利用ThemeEngine打開的基于Generic iOS Device編譯出來的Assets.car文件

矢量圖能否減少空間
回歸到最初的問題, 到底使用矢量圖能不能幫助iOS App減少空間呢?
筆者用簡單粗暴的實驗來對比說明, 步驟如下:
- 使用pdf原始文件編譯生成通用IPA
- 從生成的IPA文件中提取Asset.car文件
- 利用iOS Image Extractor提取Asset.car文件
- 將提取出來的@1x、@2x、@3x放置回工程, 并刪除原始pdf中重新編譯
- 對比步驟1生成的car文件和步驟4生成的car文件大小
- 步驟一編譯car大小(僅PDF) - 115KB
- 步驟四編譯car大小(僅3張圖) - 86KB
- 測試PDF尺寸 - 20KB
在iOS8.3以下, 相同壓縮比例的條件下, 矢量圖是無法幫助App減少空間。但是在iOS8.3以上, 利用xcassets可以避免多余的資源圖片下載, 只下載對應(yīng)的倍率的圖片。因此, 嚴格意義下, 利用矢量圖并不能幫助App節(jié)省空間。
其實筆者使用的簡單粗暴的方式在蘋果新的瘦身機制下是不成立的, 因為編譯生成的最終包不一定就是設(shè)備最終安裝的包。引用官方文檔App Thinning中Slicing章節(jié)中的一段話:
In Xcode, specify target devices and provide multiple resolutions of images in the asset catalog.
You must use the asset catalog in order for resources to be sliced.
筆者未能完全參透這句話的意思, 只知道xcasset會根據(jù)不同的設(shè)備會有不同的解決方案, 但是不知道粒度會達到什么樣的程度。筆者嘗試過針對不同的模擬器編譯, 只會生成對應(yīng)的倍率圖, 但是上傳給App Store是通用格式的, 難道下載的過程中進行了一定的處理? 這個就需要一臺越獄設(shè)備去驗證了, 就靠各位讀者大大了~
PS: 對iOS如何控制多余資源圖片下載感興趣的童鞋們, 可以找一臺越獄設(shè)備, 將iOS 8.3以上的App給提取出來分析分析哈~ 記得分享哇~ \(o)/
題外探究之提取原理
筆者在對比大小的時候使用的iOS Image Extrator。 在使用過程中, 筆者對該工具的提取原理產(chǎn)生了那么一點點的好奇。筆者好奇xcasset的格式應(yīng)該是封閉不開放的, 該工具是怎么從Asset.car中提取圖片的, 難道該工具破解了Asset.car的格式?
既然iOS Image Extrator是開源的, 那么筆者就有必要去看一看究竟了~ iOS Image Extrator其實是基于開源庫iOS Asset Extrator開發(fā)實現(xiàn)的, 核心提取的功能是在iOS Asset Extrator庫下提取的, 筆者通過閱讀其源碼, 找到兩個核心方法exportToDirectory:和exportThemeRendition:
通過閱讀這兩個方法的源代碼可以了解到這個庫的基本實現(xiàn)。exportToDirectory:方法有該庫核心的提取圖片的所有邏輯代碼。而exportThemeRendition:可以看出該庫支持的所有格式, 并且通過蘋果內(nèi)置的各個格式的Rendition類提取導(dǎo)出。
iOS Asset Extrator庫本質(zhì)上調(diào)用的是蘋果的私有API。在該系列API中, CUICommonAssetStorage負責(zé)存儲Asset資源的關(guān)鍵key, CUICatalog是承載了具體資源圖片信息的登記目錄。
<font color="red">回歸主題, 開源庫底層既然是蘋果API, 那么就基本是一個黑盒子了。筆者既不能從暴露的API中分析出car的格式, 又不能判斷iOS設(shè)備是否在執(zhí)行中解壓, 只好放棄</font>~
總結(jié)
矢量圖嚴格意義上并不能幫助減少App的空間, 但是卻使用起來非常的方便, 建議使用。iOS本質(zhì)上并不支持矢量圖, 但是在編譯階段會將矢量圖轉(zhuǎn)化成目標(biāo)設(shè)備對應(yīng)的尺寸圖, 同時會利用xcassets的特性在iOS8.3以上設(shè)備下支持部分資源下載, 帶到包瘦身的效果。每次都要讓UI給多個尺寸的圖, 肯定沒有給一張方便吧? 當(dāng)然, 前提是UI的童鞋是基于矢量圖工具制作的圖片的前提下~