講到了SDK開發(fā),這篇來講講iOS中伴隨SDK開發(fā)的Bundle包。
Bundle是什么?你可以理解為iOS中一種特殊的目錄,它可以包含各種資源文件,如:圖片、音頻、視頻、xib文件、storyboard文件等。
為什么會有bundle包?
App工程中引入bundle包主要由兩大來源:
- 提供庫文件的開發(fā)者,同時提供了bundle包。
- App開發(fā)者自己為了集中管理資源而打的bundle包
第二種比較好理解,我們不討論。這里主要討論第一種情況下這么做的本質原因。
提供庫的開發(fā)者,如果他們在庫中有使用到某些資源(聲音、視頻、圖片或圖標等),那么他們提供庫的同時,也是需要提供這些資源文件的。這樣他們的庫才能被我們正常使用。
下面是重點:
- 通常而言,只有打包為靜態(tài)庫的,如果有需要才應該打包一個配套的bundle文件。動態(tài)庫的資源文件應該內置到.framework文件內部的。因為.framework自身也是一個bundle,可以包含資源文件。
下面詳細分析下:
首先說明工程設置:
SDKDemo:制作SDK庫的工程
SDKApp:應用SDK庫的App工程
1. 靜態(tài)庫 VS 動態(tài)庫:
編譯App工程時,靜態(tài)庫會被編譯進App可執(zhí)行文件中,成為可執(zhí)行文件的一部分。而動態(tài)庫僅會在App可執(zhí)行文件中通過rpath記錄動態(tài)庫的鏈接加載路徑,在App啟動運行時,動態(tài)加載器dyld會根據rpath的值去正確的加載動態(tài)庫,其本身是不會被整合進App可執(zhí)行文件中的。
2. SDKDemo工程(僅是添加了三張圖片):




3. 將SDKDemo.framework導入SDKApp工程中,編譯SDKApp工程。在生成的SDKApp.app上右鍵顯示包內容:

從中我們沒有看到SDKDemo.framework中的圖片資源文件。要知道iOS App運行時所需的資源文件都是從.app文件中獲取的。既然圖片資源不在該目錄下,自然代碼中是引用不到的。所以為了解決這個問題,我們才需要單獨打包一個bundle文件,將所有的圖片等資源文件放入其中,然后把這個bundle文件導入App工程中,這樣編譯后的.app文件將會包含這個bundle文件。這樣只要代碼中引用對了這個bundle,圖片將會正確被加載顯示...
4. 再來看看將SDKDemo打包為動態(tài)庫:



和靜態(tài)framework文件不同的是,動態(tài)的framework文件是獨立存在的,其在App運行時,是作為一個整體鏈接進App的可執(zhí)行文件中的。并且Framework文件本身也是一個Bundle,通過如下接口可獲取特定的bundle:
- (NSBundle *)bundleForClass:(Class)aClass;
aClass: .framework中任何一個聲明類的類對象
返回值:返回參數(shù)aClass對應類聲明所在的.framework(是個bundle對象)
所以在代碼中,可直接通過+ (NSBundle *)bundleForClass:(Class)aClass;獲取到目標framework,然后通過bundle對象的- (nullable NSString *)pathForResource:(nullable NSString *)name ofType:(nullable NSString *)ext; 等接口方法獲取framework下面的各種資源文件
此乃動態(tài)framework文件不需要單獨bundle包的原因。根據模塊化、高內聚、低耦合等等這些設計要求,我們也應該盡量避免讓一個模塊中的東西分成兩個模塊來發(fā)布,此所謂越簡單越好。
5. 總結
靜態(tài)庫和動態(tài)庫對資源文件處理方式的不同,本質上是因為一個App運行時只能在自己的沙盒空間內加載引用可以找到的資源,對于找不到的資源就會出現(xiàn)加載不了的情況。通過上面的實踐可以知道,靜態(tài)framework中的圖片在打包App時是不會將它的圖片資源文件包含進來的。而動態(tài)庫最終會在.app文件內創(chuàng)建一個Frameworks目錄,里面是所有App引入的動態(tài)庫,只要定位到某個動態(tài)framework,自然就可以找到它下面的圖片等資源文件了...