iOS 靜態(tài)庫(kù) 和 bundle

  • 開源庫(kù)
    公開源代碼,能看到具體實(shí)現(xiàn),如SDWebImage,AFNetworking

  • 閉源庫(kù)
    不公開源代碼,是經(jīng)過(guò)編譯后的二進(jìn)制文件,看不到具體實(shí)現(xiàn),主要分為靜態(tài)庫(kù) 和動(dòng)態(tài)庫(kù)

  • 靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)的區(qū)別
    1、 形式上
    靜態(tài)庫(kù)是.a 和 .framework。 動(dòng)態(tài)庫(kù)是.dylib和 .framework ,xcode8 為.tbd ,本質(zhì)是.dylib
    2、使用上:
    靜態(tài)庫(kù),鏈接時(shí),會(huì)被完整的復(fù)制到可執(zhí)行文件中,如果多個(gè)APP 使用了同一個(gè)靜態(tài)庫(kù),就會(huì)有多次拷貝,會(huì)占用更多的內(nèi)存。
    動(dòng)態(tài)庫(kù),鏈接時(shí)不復(fù)制,程序運(yùn)行時(shí)由系統(tǒng)動(dòng)態(tài)的加載到內(nèi)存,供程序調(diào)用,系統(tǒng)只加載一次,多個(gè)程序共用,節(jié)省內(nèi)存。

  • 靜態(tài)庫(kù)的使用場(chǎng)景
    1、制作SDK - 軟件開發(fā)工具包。

    • 如“百度地圖”,它想讓開發(fā)者在程序中集成百度地圖,但是百度又不想公開自己的技術(shù)
    • 百度將自己的核心代碼編譯成靜態(tài)庫(kù),對(duì)外暴露統(tǒng)一的接口,開發(fā)者集成靜態(tài)庫(kù),并且調(diào)用靜態(tài)庫(kù)即可集成

2、公司在開發(fā)項(xiàng)目時(shí)的核心代碼

  • 公司一般在開發(fā)一個(gè)項(xiàng)目時(shí),肯定有一部分代碼是核心代碼

  • 如果任何人都可以拿到這個(gè)核心代碼,那么一旦有人離職,公司的核心代碼就會(huì)被泄露,那么如何防止這種情況的發(fā)生

  • 公司一般都會(huì)抽出一部分核心團(tuán)隊(duì)成員,專門開發(fā)這部分核心代碼。開發(fā)完成后,將核心代碼編譯成靜態(tài)庫(kù)給其他的程序員調(diào)用。

  • 創(chuàng)建靜態(tài)庫(kù)
    在創(chuàng)建靜態(tài)庫(kù)時(shí),有以下兩種選擇


    image.png
看一下 framework 和 Static Library 的區(qū)別
  • framework 既可以制作靜態(tài)庫(kù),也可以制作動(dòng)態(tài)庫(kù)。
  • Static Library 制作靜態(tài)庫(kù)
  • framework 實(shí)際上為一站式分享方案,其實(shí)是一個(gè)文件夾,其中包含代碼簽名,頭文件,二進(jìn)制執(zhí)行文件,靜態(tài)資源文件等,
  • static Library 的產(chǎn)出物只是一個(gè).a 文件,為二進(jìn)制執(zhí)行文件。分享給別人的時(shí)候,頭文件,靜態(tài)文件需要另外提供
  • staticLibrary 需要設(shè)置頭文件搜索路徑,framework 不需要
對(duì)外部代碼依賴庫(kù)的區(qū)別
  • staticLibrary 能夠只引用外部庫(kù)的頭文件,調(diào)用外部庫(kù)的公開方法,而不引入其庫(kù)實(shí)現(xiàn),實(shí)現(xiàn)與引用庫(kù)的分離部署
  • framework 要引用一個(gè)外部庫(kù),就必須要將此外部庫(kù)的實(shí)現(xiàn)放入framework內(nèi)編譯才行。如果想要達(dá)到StaticLibrary 的效果,可以使用運(yùn)行時(shí)方式調(diào)用。
運(yùn)行環(huán)境的區(qū)別
  • staticLibrary 共享其運(yùn)行環(huán)境,假如其運(yùn)行環(huán)境中包含庫(kù)中的一個(gè)類,會(huì)發(fā)生代碼沖突,必須隔離其中一方的此類,然后共享此類。
  • framework,與其運(yùn)行環(huán)境隔離,假如其運(yùn)行環(huán)境中包含庫(kù)中同一個(gè)類,不會(huì)發(fā)生沖突,同名的兩個(gè)類會(huì)在各自的環(huán)境中獨(dú)立運(yùn)行,互不干擾,哪怕是單利類
如何選擇兩種庫(kù)
  • 假如不想在同一個(gè)APP中包含多份三方庫(kù)(減小包大?。梢允褂胹taticLibrary,庫(kù)本身和APP共享第三方。但是產(chǎn)出物的結(jié)構(gòu)可能會(huì)比較亂
  • 假如不想考慮和APP的代碼沖突問(wèn)題,庫(kù)本身獨(dú)立使用需要的庫(kù),想提供比較好的庫(kù)結(jié)構(gòu),可以使用framework。假如庫(kù)本身和APP都使用了同一個(gè)三方庫(kù),會(huì)存在兩份三方庫(kù),會(huì)增加包大小。
framework 的結(jié)構(gòu)
image.png

制作 .framework 靜態(tài)庫(kù)(閉源庫(kù))

  • xcode打開,command+shift+N, 新建framework 工程


    image.png
  • 下面是framework 工程


    image.png
  • 配置工程, 選擇工程名-》General,選擇支持的系統(tǒng)和平臺(tái)


    image.png
  • 非必選屬性設(shè)置
    build settings > Dead Code Stripping -> NO , Link with Standard Libraries -> NO
    有的博客里說(shuō)要將這兩個(gè)屬性設(shè)置為NO,但在xcode7以后不需要再把它們?cè)O(shè)置為NO。
    Dead Code Stripping ,如果開啟此項(xiàng),就會(huì)對(duì)代碼的“dead”,“unreachable” 的代碼過(guò)濾,能起到一定的優(yōu)化作用,但是優(yōu)化效果一般,對(duì)于比較小的項(xiàng)目甚至沒(méi)有什么優(yōu)化提現(xiàn)。Dead Code Stripping 是對(duì)程序編譯出的可執(zhí)行二進(jìn)制文件中沒(méi)有被實(shí)際使用的代碼進(jìn)行剝離,也就是消除無(wú)效代碼。
    Link with Standard Libraries 如果激活此設(shè)置,那么編譯器在鏈接過(guò)程中會(huì)自動(dòng)使用通過(guò)標(biāo)準(zhǔn)庫(kù)的鏈接器。如果使用NO,需要配置Other Linker Flags 來(lái)指定鏈接器。
image.png
  • Generate Debug Symbols 在release 模式下設(shè)置為NO,debug 模式下設(shè)置為YES,是為了framework瘦身,為了進(jìn)行代碼調(diào)試,如果設(shè)置為NO,debug模式將不能進(jìn)行斷點(diǎn)調(diào)試,大約可以減少30%體積 (非必選)
image.png
  • 必選配置
    Build Settings >>Build Active Architecture Only -> NO,如果設(shè)置為YES,會(huì)導(dǎo)致編譯器只生成當(dāng)前CPU架構(gòu),這個(gè)適合在debug 模式下測(cè)試使用。
    如果設(shè)置為NO,模擬器編譯后生成的framework 同時(shí)包含x86_64 和 i386 架構(gòu)。真機(jī)包含 armv7,arm64 架構(gòu)。
  • 靜態(tài)庫(kù)配置
    Build Settings >> Mach-O Type >> Static Library
    對(duì)于Mach-O type 有兩種類型 Static Library 是靜態(tài)庫(kù),Relocatable Object File 是動(dòng)態(tài)庫(kù)。
image.png
  • 可測(cè)試后再配置
    Build Settings -> Excluded Architectures,在模擬器 模式下選擇該項(xiàng),添加arm64 架構(gòu),如果不設(shè)置此項(xiàng),在xcode12 生成的模擬器版本 framework 會(huì)多一個(gè)arm64架構(gòu),這和真機(jī)模式下的架構(gòu)有所沖突,會(huì)導(dǎo)致合并不成功。 真機(jī)模式下 不要添加此項(xiàng)。
image.png
  • 創(chuàng)建SDK需要的目錄和文件
image.png
  • 公開頭文件
    把你想要對(duì)外公開的.h 文件 放到public 中,不想公開的就放在project 中。然后不要忘記 在framework名稱.h里面導(dǎo)入你公開的頭文件。
image.png
image.png
創(chuàng)建bundle 文件
  • 第一種 直接創(chuàng)建文件夾,修改后綴名為.bundle
    bundle 文件是靜態(tài)的,不參與項(xiàng)目的編譯,而xib 是文本文件,編譯后要被序列化為二進(jìn)制的nib 文件,使用的時(shí)候?qū)ib 文件反序列化就可以使用了。如果你的bundle 里沒(méi)有xib 文件,只需要?jiǎng)?chuàng)建文件夾,修改后綴名就可以。 如果你的bundle里打算包含xib 文件,那么就必須使用第二種方法,創(chuàng)建工程的形式將xib 序列化為nib 文件。
  • 創(chuàng)建工程的形式
    iOS 創(chuàng)建bundle(xcode 13) http://www.itdecent.cn/writer#/notebooks/21593564/notes/57586788
在framework 中添加bundle 資源
  • 將上文中創(chuàng)建的bundle 文件 拖入到framework工程,拖入后 copy bundle resources 中會(huì)自動(dòng)引入。
image.png
  • command +B編譯工程,在debug 和release 模式下 分別選擇 真機(jī)和模擬器,在這里我用于測(cè)試,所以選的debug 模式,如果只為了測(cè)試 也可以只選擇真機(jī) 或者模擬器。兩個(gè)都選的話,后期要合并。
    上文中提到,在模擬器中 要添加 arm64(上文有步驟,也可以親自測(cè)試后再添加),防止合并中起沖突。

  • 編譯后 command +, 此圖為模擬器中的framework,可以查看它支持的架構(gòu)
    lipo -info “綠色框地址”,i386,x86_64

image.png
image.png
  • 同樣的方式在真機(jī)下編譯,查看架構(gòu)
image.png
image.png
  • 合并兩個(gè)靜態(tài)庫(kù),將合并后的輸出路徑 替換掉其中一個(gè)路徑(模擬器或真機(jī)下的 framework 路徑)
    合并命令lipo -create "模擬器路徑" “真機(jī)路徑” -output "真機(jī)路徑" (此處路徑都是以上截圖綠色框路徑)
image.png

此處我替換的是模擬器路徑,所以將替換后的framework拿出來(lái)就行了,也可以測(cè)試一下 合并后支持的架構(gòu)

image.png
image.png
在項(xiàng)目工程中導(dǎo)入framework
  • 直接拖入工程
image.png
  • 如果framework中包含了分類,那么要在使用framework的工程里配置一下
    build settings里為Other Linker Flags 添加 -ObjC
image.png
  • 如果framework有bundle 資源,選擇添加copy files
image.png
image.png
  • 項(xiàng)目工程中使用,在用的地方 導(dǎo)入 framework 的頭文件,就可以使用公開的頭文件 和 方法
image.png
  • 工程 和 framework 中使用bundle 資源
    NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"LHNetwork.framework/HLNetworkSource" ofType:@"bundle"];
    
    NSLog(@"bundlePath = %@",bundlePath);
    
    NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
    NSString *pic1 = [bundle pathForResource:@"bill_head_bg@2x" ofType:@"png"];
    
    NSLog(@"pic1 = %@",pic1);
    
    UIImage *image = [UIImage imageWithContentsOfFile:pic1];
    
    NSLog(@"image = %@",image);
  • 還有一種,framework 中不用引入bundle,直接把bundle 導(dǎo)入項(xiàng)目工程,手動(dòng)拖入就行
image.png

那么在工程和 framework中就可以用以下方式使用bundle中資源

    NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"HLNetworkSource" ofType:@"bundle"];

    NSLog(@"bundlePath = %@",bundlePath);

    NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];

    NSString *imagePath = [bundle pathForResource:@"bill_head_bg@2x" ofType:@"png"];

    NSLog(@"imagePath = %@",imagePath);

    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

    NSLog(@"image = %@",image);

    imageView.image = image;
另一種將framework 導(dǎo)入工程的方式

直接將xxx.framework SDK拖入工程不太方便測(cè)試,在工程中看不到源代碼,我們可以把framework的工程文件導(dǎo)入 ,就是創(chuàng)建的framework工程

image.png

至于導(dǎo)入的方式,可以參考我的另一篇文章 多工程聯(lián)編
這樣很方便的修改和調(diào)試。

注意

有的博客說(shuō),在上架App Store的時(shí)候,會(huì)有報(bào)錯(cuò)。可能需要把info.plist文件中的Excutable file刪除,大家可以試一下,我沒(méi)有實(shí)際操作。

補(bǔ)充說(shuō)明,設(shè)備CPU架構(gòu)
image.png

參考文章:
https://blog.csdn.net/jingcheng345413/article/details/54969324
https://www.cnblogs.com/mtystar/p/6082363.html

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容