靜態庫和動態庫的製作以及Bundle資原始檔的使用

前兩天因為公司業務上的需要,我們需要和聯通公司那邊進行業務整合,考慮到一些業務上的隱私性,我們將提供的內容打包成了一個靜態庫,只為對方提供了一些介面,今天正好有空整理一下,填一下這個過程中遇到的一些坑,以方便日後查閱。
什麼是庫?
庫是程式程式碼的集合,是共享程式程式碼的一種方式。我們根據原始碼的公開情況,可以將庫分為 2 種型別
開源庫:公開原始碼,我們能看到程式碼的具體實現,比如SDWebImage、AFNetworking等;如何將自己的程式碼釋出到程式碼託管平臺中,然後藉助CocoaPods供別人使用,我們在上一篇文章中已經講過,這裡不再細說。
閉源庫:不公開原始碼,是經過編譯後的二進位制檔案,看不到程式碼的具體實現。閉源庫主要分為:靜態庫、動態庫
靜態庫和動態庫的存在形式以及使用上的區別
存在形式:
靜態庫:.a 和 .framework
動態庫:.dylib 和 .framework
區別:
靜態庫:連結時,靜態庫會被完整地複製到可執行檔案中, 被多次使用就有多份冗餘拷貝 ,如下圖:

靜態庫
動態庫:連結時不復制,程式執行時由系統動態載入到記憶體,供程式呼叫,系統只載入一次,多個程式共用,以節省記憶體,具體形式如下圖所示:

動態庫
靜態庫的使用場景:
專案開發中我們經常使用到的極光推送、百度地圖、友盟分享等等。這些大公司都有自己的核心業務,同時又希望我們去使用他們提供的技術,但是又不想暴露他們的程式碼,因此他們採用"閉源"的方式來讓我們整合。
將MRC的專案放到ARC環境下,我們可以如下圖去操作

MRC->ARC
但是如果檔案特別多,我們這樣一個個去操作是不是很麻煩?其實我們可以將MRC的專案,打包成靜態庫, 可以在ARC下直接使用, 不需要轉換,非常方便;
知識準備:
我們都知道模擬器下的靜態庫和真機下的靜態庫是不能混用的,那為什麼呢?其實主要原因是模擬器和真機的CPU架構不一樣(各個模擬器型號之間架構也不一樣)不同機型的CPU, 對應的架構不同;
模擬器:
4s和5使用的是i386
5s-6sPlus使用的是x86_64
真機:
3gs---4s :armv7
5/5c :armv7s(armv7相容armv7s)
5s---6sPlus:arm64
我們可以分別選中不同的模擬器, 進行編譯,然後利用lipo -info xxx.a檢視靜態庫所支援的架構, 如下圖所示:

檢視靜態庫支援架構
因為CPU架構的不同,這就造成了一個問題,如果我是在6s環境下編譯生成的靜態庫執行到5上面就會編譯不通過, 怎樣可以一次編譯支援多個架構的的靜態庫呢?
可以通過Build Settings -> Build Active -> NO,表示不止編譯活躍的架構, 讓所有的架構都編譯,如下圖所示:

編譯所有架構
.a靜態庫的製作步驟
新建專案-> 選擇 “Cocoa Touch Static Library”

新建靜態庫
新增庫需要包含的原始碼,並且設定需要暴露的標頭檔案:

3.png
引入製作的靜態庫所需要的網路框架(有些會自動引入,有些需要手動引入,根據編譯報錯,可以檢查。)

引入框架
設定支援所有架構:

設定支援架構
編譯前檢查一下是debug模式還是release模式,選擇release模式。在模擬器和真機中分別編譯後,libzpstaticLibrary.a就由紅色變成了黑色,Show in Finder在目錄中檢視:

Release模式
.framework靜態庫的製作步驟
新建專案-> 選擇 “Cocoa Touch Framework”

Framework
新增庫需要包含的原始碼,並且設定需要暴露的標頭檔案:

暴露標頭檔案
如果使用者需要匯入的標頭檔案過多怎麼辦?我們可以使用一個主標頭檔案包含其他標頭檔案, 讓使用者只匯入一個主標頭檔案。
編譯時, 設定編譯所有架構

設定編譯架構
因為預設製作的是動態庫,我們 需要設定連結型別target -> Build Settings-> 搜尋 Mach-o Type ;改為靜態庫

設定型別
如果沒有這一步,我們在測試的時候會報一個錯誤:

錯誤提示
這個錯誤是因為我們預設生成的是一個動態庫,如果我們把它當成一個動態庫來用的話 就需要在測試工程中General->Embedded Binaries中匯入我們這個動態庫,這樣就不會報這個錯誤了。

動態庫
經過以上步驟後我們就可以成功的生成了一個.Framework的靜態庫或者是動態庫了。
靜態庫的操作
合併靜態庫
因為靜態庫針對於模擬器和真機生成了不同版本(支援不同架構), 所以沒法同時執行,但是我們可以將二者進行合併,合併後的.a大小大約是不合並的2倍左右。
cd 到一個目錄,然後通過
lipo -create Debug-iphoneos/libTools.a Debug-iphonesimulator/libTools.a -output libTools.a
進行合併,合併後的架構如下圖所示:

分解合併庫
既然有合併靜態庫,那麼對應的也有分解合併庫,例如我們在釋出的時候只想要使用arm64架構,那麼我們可以通過下面這行命令來達到我們目的:
lipo -thin arm64 靜態庫 -output 新的靜態庫名稱
如下圖所示:

檢視分解之後的庫可以發現該庫已經非常小了
從合成庫中移除某個架構
如果合成庫中的某一個架構我們用不到了,想要移除,那麼我們可以通過下面的命令,例如我們想要將合成庫中的i386移除
lipo -remove i386 靜態庫 -output 靜態庫名稱
執行命令後我們可以發現,合成的靜態庫中已經沒有了i386這個架構了

總結
.a靜態庫和.framework靜態庫的區別?
我們都知道靜態庫包括.a和.framework,那麼二者之間到底有什麼區別呢?
.a是一個純二進位制檔案, 而.framework中除了有二進位制檔案之外還有資原始檔,比如Bunle、Plist等。
.a檔案不能直接使用, 至少要有.h檔案的配合;.framework檔案可以直接使用
.a + .h + sourceFile = .framework
建議使用.framework
靜態庫的除錯
因為靜態庫只提供了一些標頭檔案,實現程式碼都是經過二進位制化的,如果我們想對靜態庫進行斷點除錯如何做呢?
我們可以建立複合專案來對靜態庫進行除錯:
建立一個測試工程,選中TARGETS,點選下面的➕按鈕,新增一個靜態庫,如下圖所示

複合專案
設定主工程檔案和靜態庫的依賴關係。

新增依賴關係
經過以上兩步後我們就可以對要製作的靜態庫檔案進行除錯開發了,是不是很爽,至於製作靜態庫就和上面的步驟一樣了。
Bundle封裝XIB、圖片等資原始檔
建立Bundle檔案
因為我是新建了一個複合測試工程,所以在這裡為了方便我們直接在複合測試工程中新增了一個子工程,因為iOS框架中沒有bundle,要選中macOS框架找到bundle,如下圖為我們的Bundle命名為STWNetPay

image
Bundle的本質其實是一個目錄,我們完全可以建立一個資料夾,然後把需要封裝的資原始檔拷貝到該目錄下,然後將字尾名為改成bundle即可,但是如果我們想要將XIB檔案封裝到Bundle檔案中的話,這種方法就不可以了. 考慮到xib是文字檔案,編譯後要被序列化為二進位制的nib檔案,使用時將nib檔案反序列化,就可以正常顯示介面了。而bundle本身是靜態的,其內部的資源包不參與專案的編譯,所以,此處必須建立工程把xib序列化為二進位制的nib,否則的話,直接建立資料夾後改名就可以了。
設定Bundle
1.建立好之後我們發現裡面只有一個Info.plist檔案,經測試該檔案不能刪掉,如果刪掉之後編譯Bundle檔案會報錯:bundle format unrecognized, invalid, or unsuitable
2.iOS Deployment Target改為你支援的最低版本

image
3.設定base SDK 為latest iOS

image
4.COMBINE_HIDPI_IMAGES設定為NO
因為iOS建立Bundle時放入的圖片資源(.png)在預設配置下會被轉為.tiff格式,使用的時候找不到。所以找到bundle的工程,Buld Settings > COMBINE_HIDPI_IMAGES設定為NO

image
5.Skip Install 設定為NO

image
6."Build Active Architecture Only" 設定為 NO
向Bundle中新增資原始檔

image
一切就緒,按快捷鍵"Command + B"編譯,編譯成功後,我們的Bundle檔案即由紅色變成了黑色,表示編譯成功,這個時候找到我們的Bundle檔案,顯示報內容,如下圖所示:

image
可以看到XIB檔案經過編譯已經變成了nib檔案,這就是我們想要的.
使用bundle裡的資原始檔
將編譯好之後的Bundle檔案拖入我們的靜態庫中,因為是要在靜態庫中使用Bundle檔案,而不是在MainBundle中,所以我們需要先找到我們Bundle所在的路徑才能使用它裡面的資源.
建立一個管理Bundle路徑的類BundleTools,專門用來獲取我們Bundle所在的路徑:
#import<Foundation/Foundation.h>#define BUNDLE_NAME @"STWNetPay"@interfaceBundleTools:NSObject+ (NSString*)getBundlePath: (NSString*) assetName;+ (NSBundle*)getBundle;@end
#import"BundleTools.h"@implementationBundleTools+ (NSBundle*)getBundle{NSURL*url= [[NSBundlebundleForClass:[selfclass]] URLForResource:BUNDLE_NAME withExtension:@"bundle"];NSBundle*bundle = [NSBundlebundleWithURL:url];returnbundle;}+ (NSString*)getBundlePath: (NSString*) assetName{NSBundle*myBundle = [BundleTools getBundle];if(myBundle && assetName) {return[[myBundle resourcePath] stringByAppendingPathComponent: assetName]; }returnnil;}@end
使用圖片
UIImage*image = [UIImageimageWithContentsOfFile: [BundleTools getBundlePath:@"nav_back"]];
使用XIB
控制器是XIB的情況,此時應該在控制器中重寫Init方法
- (instancetype)init{NSBundle*myBundle = [BundleTools getBundle];//從bundle中獲取介面檔案self= [superinitWithNibName: [NSStringstringWithUTF8String: object_getClassName(self)] bundle: myBundle];if(self) {// Custom initialization}returnself;}
否則
NSBundle*myBundle = [BundleTools getBundle];//從bundle中獲取介面檔案view = [myBundle loadNibNamed:@""owner:niloptions:nil].firstObject;
Swift打包動態庫
因為Swift專案是不支援靜態庫的,必須使用動態庫。所以我們在新建一個靜態庫的時候,一定要選擇Cocoa Touch Framework

建立動態庫
如果我們在專案中將target -> Build Settings-> 搜尋 Mach-o Type ;改為Static Library

靜態庫
Command+B編譯,系統會報一個錯,提示我們Swift is not supported for static libraries.如下圖:

靜態庫報錯
所以,如果在Swift專案中,我們必須使用動態庫;
因為Swift是沒有標頭檔案這個說法的,所以在Build Phases中我們也不用設定暴露標頭檔案了

11.png
確定支援模擬器或者真機中的所有架構

編譯架構
最重要的,因為swift沒有標頭檔案,所以如果我們想讓別人用到我們的方法,就用Public修飾符修飾。

暴露方法
這樣生成的動態庫中就會將我們的Swift方法轉換成了OC的方法
SWIFT_CLASS("_TtC10zpSwiftLib4Tool")@interfaceTool:NSObject+ (void)Log;- (nonnullinstancetype)init OBJC_DESIGNATED_INITIALIZER;@end
這樣將生成的動態庫拖入到我們的測試工程中就可以成功的使用了,但是和靜態庫有一點不同的是,我們需要在測試工程中General->Embedded Binaries中匯入我們這個動態庫即可。
連結:https://www.jianshu.com/p/f14553494d88
相關文章
- ios靜態庫和動態庫iOS
- android下java的靜態庫和動態庫AndroidJava
- iOS動態庫和靜態庫的運用iOS
- cmake:生成靜態庫和動態庫
- 簡述Linux下的靜態庫和動態庫Linux
- iOS中的動態庫,靜態庫和framework介紹iOSFramework
- linux下的靜態庫與動態庫Linux
- 靜態庫與動態庫
- 關於MNN工程框架編譯出來的靜態庫和動態庫的使用框架編譯
- 一、靜態庫和動態庫,Makefile專案管理專案管理
- 動靜態庫
- Linux共享庫、靜態庫、動態庫詳解Linux
- Android NDK祕籍--淺析靜態庫和動態庫Android
- C靜態庫的建立與使用--為什麼要引入靜態庫?
- [Linux]動靜態庫Linux
- linux 動態庫 靜態庫 函式覆蓋Linux函式
- 動態連結庫與靜態連結庫
- 編譯靜態庫的方式使用spdlog和fmt編譯
- linux下靜態連結庫和動態連結庫的區別有哪些Linux
- 動態庫的生成和使用(二)
- 偽靜態、靜態和動態的區別
- iOS的Framework靜態庫iOSFramework
- iOS動態庫的使用iOS
- 靜態資源公共庫
- 筆記: 判斷lib庫是動態庫還是靜態庫筆記
- 製作FFmpeg動態庫(make ffmpeg dynamic lib)
- 值得注意的: c++動態庫、靜態庫、弱符號__attribute__((weak))以及extern之間的關係C++符號
- CMake和靜態庫順序
- 靜態庫生成
- 動態庫使用
- 動態連結庫的生成和使用(二)
- 動態連結庫(DLL)的建立和使用
- Android NDK祕籍--編譯靜態庫、呼叫靜態庫Android編譯
- WPF:靜態、動態資源以及資源詞典
- 動態庫的建立和呼叫
- 資料庫靜態脫敏資料庫
- iOS 靜態庫 與私有庫iOS
- Android:JNI與NDK(二)交叉編譯與動態庫,靜態庫Android編譯