針對目前公司業務子庫資源引用方式各異,包體大小超出正常值的問題,做出了一些調研.同時網上的部分說法可能隨着時間的推移和cocoapods的更新已通過時或不可用.本文展現了資源引用的各類方式,也防止你們走彎路.css
這篇文章介紹了關於CocoaPods的資源管理行爲,對於Pod庫做者是必須瞭解的知識。同時介紹了CocoaPods使用Asset Catalog的注意事項。若是已經瞭解某方面知識,能夠大體略過直接看結論。html
Asset Catalog,是Xcode提供的一項圖片資源管理方式。每一個Asset表示一個圖片資源,可是能夠對應一個或者多個實際PNG圖,好比能夠提供@1x
, @2x
, @3x
多張尺寸的圖以適配;,還能夠經過指定日間和夜間不一樣Appearances的兩套圖片。json
這種資源,在編譯時會被壓縮,而後在App運行時,能夠經過API動態根據設備scale factor來選擇對應的真實的圖片渲染。xcode
App Thinning,是蘋果平臺(iOS/tvOS/watchOS)上的一個用於優化App包下載資源大小的方案。在App包提交上傳到App Store後,蘋果後臺服務器,會對不一樣的設備,根據設備的scale factor,從新把App包進行精簡,這樣不一樣設備從App Store下載須要的容量不一樣,3x設備不須要同時下載1x和2x的圖。ruby
可是,這套機制直接基於Asset Catalog,換言之,只有在Asset Catalog中引入的圖片,才能夠利用這套App Thinning。直接拷貝到App Bundle中的散落圖片,全部設備仍是都會所有下載。所以如何儘可能提高Asset Catalog利用率,是一個很大的包大小優化點。服務器
CocoaPods是一個構建工具,它徹底基於Pods的spec文件規則,在Podfile引入後,生成對應構建Xcode Target。也就是它是一個聲明式構建工具(區別於Makefile這種過程式的構建工具)。對於資源的管理,目前有兩個方式進行聲明並引入,即resources
和resource_bundles
,參考podspec syntaxapp
雖然Podspec中包含全部待構建庫的聲明,但於CocoaPods也會根據Podfile的配置,動態調整最終的Xcode工程的配置,根據是否開啓use_framework!
,如下的資源聲明最終的行爲有所不一樣,這裏分開介紹。ide
爲了測試使用場景,咱們新建了三個工程 工程目錄以下:工具
主工程爲 CatalogTest ,測試
資源工程爲: ResourcesTest,ResourcesBubdlesTest
ResourcesTest 裏包含資源文件:
ResourcesBubdlesTest包含資源文件:
/Assets/**/*'
s.resources = 'ResourcesTest/Assets/**/*'
導入方式
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/**/*']
}
複製代碼
而經過resources 導入的文件直接會在根目錄導入兩份而且不會 通過Xcode的資源優化
bundle也會以bundle和裏面的全部文件在根目錄導入
經過resource_bundles 形式導入的文件會生成一個自命名的 budle ,bundle裏包含文件
結論: 按照**/*
導入的資源文件不管哪一種形式都存在被重複導入的問題,這種懶省事的方式應該被制止
/Assets/*.xcasset'
,/Assets/*.bundle
ResourcesTest:
xcasseets併入主工程 .car
Bundle 併入主目錄
s.resources = ['ResourcesTest/Assets/*.xcassets',
'ResourcesTest/Assets/*.bundle'
]
複製代碼
ResourcesBubdlesTest:
注意 bundle必須有本身的命名空間,不然仍是以文件形式導入
Bundle 文件會以命名空間爲名字放在主目錄下
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/*.xcassets'],
'BlankLoading1' => ['ResourcesBubdlesTest/Assets/BlankLoading.bundle']
}
複製代碼
爲了測試使用場景,咱們新建了三個工程 工程目錄以下:
主工程爲 CatalogTest ,
資源工程爲: ResourcesTest,ResourcesBubdlesTest
ResourcesTest 裏包含資源文件:
ResourcesBubdlesTest包含資源文件:
/Assets/**/*'
導入方式 s.resources = 'ResourcesTest/Assets/**/*'
xcassets 生成.car, bundle文件依然雙份
導入方式
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/**/*']
}
複製代碼
/Assets/*.xcasset'
,/Assets/*.bundle
每一個子工程有本身的 framework,也就是有本身的命名空間,不會出現命名衝突等問題
ResourcesTest:
xcasseets併入主工程 .car
Bundle 併入主目錄
s.resources = ['ResourcesTest/Assets/*.xcassets',
'ResourcesTest/Assets/*.bundle'
]
複製代碼
ResourcesBubdlesTest:
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/*.xcassets'],
'BlankLoading1' => ['ResourcesBubdlesTest/Assets/BlankLoading.bundle']
}
複製代碼
不管任何場景,禁止 使用 podspecName/assers/**/*
形式引入資源文件,存在嚴重的資源重複引入問題,會顯著增長包體大小!沒法享有任何 Xcode的優化.
resources
s.resources = ['ResourcesTest/Assets/*.xcassets',
'ResourcesTest/Assets/*.bundle'
]
複製代碼
使用 resource_bundles
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/*.xcassets'],
'BlankLoading1' => ['ResourcesBubdlesTest/Assets/BlankLoading.bundle']
}
複製代碼
當不使用use_framework!時,最終對Pod庫,會建立單獨的靜態連接庫.a
的Target,而後CocoaPods會對主工程App Target增長本身寫的腳原本幫助咱們拷貝Pod的資源。
resources
裏*.xcassets
資源會拷貝進入主目錄Assets.car
,*.bundle
文件放入主目錄下!
優勢:
最簡單暴力,並且因爲固定了資源的路徑在根路徑上,若是先前在主工程目錄中使用的代碼,不須要更改一行便可繼續使用。
缺點:
bundle
, js
, css
均可能存在這個問題,難以排查。並且因爲這種拷貝到根路徑的機制,這個問題不可從根源避免。resource_bundles
文件*.xcassets
會放入 命名空間.bundle
下的Assets.car
,*.bundle
放入主目錄下的命名空間.bundle
優勢:
解決了部分命名衝突問題,*.xcassets
存在本身的命名空間.
缺點:
當使用了use_framework!以後,CocoaPods會對每一個Pod單獨創建一個動態連接庫的Target,每一個Pod最後會直接以Framework集成到App中。而資源方面,因爲Framework自己就能承載資源,全部的資源都會被拷貝到Framework文件夾中而再也不使用單獨的腳本處理。
優勢:
不會存在命名衝突。由於在使用use_framework!的狀況下,因爲資源自己被拷貝到Framework中,已經能最大程度減小衝突,所以這時候通常不須要考慮名稱衝突問題.
都會使用Xcode的優化
缺點: 因爲最終的資源文件增減了一級父文件夾.因此資源引用方式要作出改變
結合咱們公司目前現狀不能使用動態庫.因此使用以下方案:
業務層使用resources
導入資源
資源文件使用 *.xcassets
*.bundle
*.text
方式導入,可是各子庫文件會存在命名衝突問題,好處是不用改變資源引用方式,
同時約定,各子庫的資源添加子庫名字縮寫的前綴,避免暴力拷貝問題
基礎服務層,和工具層使用resource_bundles
.plist
.json
.html
須要建一個bundleName.bunlde
,不然沒法導入!