寫在前面
過程有點長,但是比較細節(jié),看官各取所需。
創(chuàng)建靜態(tài)庫工程
可以先了解iOS庫 .a與.framework區(qū)別,靜態(tài)庫可以分為.a和.framework類型的的文件。Xcode創(chuàng)建的靜態(tài)庫工程,默認編譯后獲得的靜態(tài)庫文件是.a類型的。
Xcode(9.1)創(chuàng)建分為動態(tài)庫工程和靜態(tài)庫工程:

而我們又需要.framework類型的(而對bundle類型的TARGETS進行一些設置,即可得到一個輸出framework文件的工程)具體操作如下:
1)選擇上圖的靜態(tài)庫,創(chuàng)建一個靜態(tài)庫工程:

2)因為編譯生成.a文件,所以刪除默認的TRAGETS,后面重新添加一個bundle類型的即可。

3)有些教程說,在Product->Scheme->Manage Schemes中,需要刪除關(guān)聯(lián)的build項(其實只要新建的TARGETS的名稱相同,是不用刪除的,只要新建了,就會重新關(guān)聯(lián)上):

4)刪除工程文件:

5)這個時候可以新建一個bundle類型的TARGETS了(注意此處是bundle是屬于macOS類型的,后續(xù)需要一些設置):

上面說到,新建的時候使用與工程同名的來創(chuàng)建新的TARGETS,即可不用刪除默認的build關(guān)聯(lián)項:

6)創(chuàng)建完畢,可以看出,bundle在默認情況下,是適用于Mac OS的:

因此需要我們對這個bundle類型的TARGETS做一些設置:
創(chuàng)建bundle類型TARGETS的一些設置:
參考:ios 制作自已的framework
1)
Base SDK:Lstest iOS(iOS XX.XX)
2)指令集設置
Architectures:Standard architectures - $(ARCHS_STANDARD)默認之外,添加一個:armv7s
Valid Architectures: armv7 armv7s arm64
具體原因點這里

3)Dead Code Stripping用于刪除對象文件中不需要加載的符號,減小二進制文件大小(此處為何關(guān)閉,我也不知道原因,哪位大神知道的告知一聲)
Dead Code Stripping:NO
4)關(guān)聯(lián)標準庫(此處關(guān)閉,我也不知道原因,哪位大神知道的告知一聲)
Link with Standard Libraries:NO

5)庫類型
可參考:淺談 SDK 開發(fā)(一)五種 Mach-O 類型的凜冬之戰(zhàn)
Mac-O Type:Relocatable Object File

6)
在 Packaging 中,將 “Wrapper Extention” 改為“framework”

7)
info文件將 “Bundle OS Type Code” 改為 “FMWK”(Framework 的意思)

8)設置SDK支持的最低系統(tǒng)
Build Settings -> Deployment -> iOS Deployment Target 修改具體參數(shù)
也可在 General -> Deployment Info -> Deployment Target 處設置,兩處設置等效

至此,相關(guān)設置完成,即可選擇相應環(huán)境,Cmd+B 進行編譯,以獲得framework

打開StaticLibObject.framework所在的文件夾,發(fā)現(xiàn)這個:

編譯后的framework包,是真機環(huán)境和模擬器分開的,其實是因為二者所支持的指令集不同,具體得看你的Architectures設置,必要的時候,可以使用lipo命令來合并兩個文件成一個文件,使其即支持真機,又支持模擬器。
我們查看,或者合并的文件就是這里面的文件:

查看真機的(請看我上面的關(guān)于Architectures的設置):
$ lipo -info WxxStaticLibFramework
Architectures in the fat file: WxxStaticLibFramework are: armv7 armv7s arm64
查看模擬器的:
$ lipo -info WxxStaticLibFramework
Non-fat file: WxxStaticLibFramework is architecture: x86_64
修改下模擬器的文件名,將其扔進真機的文件夾,執(zhí)行合并命令
注意咯:最好合并輸出的文件與原來的保持名字一致,替換掉原來的文件即可。否則framework中會找不到這個文件?。。。ㄐ薷牧嗣诌€能關(guān)聯(lián)的,有好的辦法請告訴我)

lipo -create 模擬器庫 真機庫 -output 最終庫
$ lipo -create StaticLibObject StaticLibObjectSimulator -output StaticLibLastFramework
查看最終合并的所支持的指令集:
lipo -info StaticLibLastFramework
查詢結(jié)果:
Architectures in the fat file: StaticLibLastFramework are: x86_64 armv7 armv7s arm64
StaticLibLastFramework已經(jīng)可以同時用于真機和模擬器了!可是這種方式有點麻煩,每次重新編譯,都需要重新合并文件,據(jù)說還可以用腳本的方式來合并,待我研究后再補充,這里先占個坑。
framework的使用
framework的使用,無非就是對外暴露.h文件,.h文件中有寫好的被人使用的方法。這里拋磚引玉。下面具體說明:
1)新建對外文件,并提供方法 +(void)staticLibSDKTest;

內(nèi)部方法實現(xiàn):
+(void)staticLibSDKTest{
NSLog(@"static lib sdk test method");
}
2)暴露頭文件
Build Phases -> + ->New Header Phase



注意:添加完默認是歸類到Project中,將需要暴露的.h文件,手動拖進Public中即可。
重新編譯,即可發(fā)現(xiàn),頭文件已經(jīng)對外暴露了:

3)創(chuàng)建一個普通工程StaticLibObjectDemo來測試剛剛創(chuàng)建的framework,跑這個工程的時候,注意真機和模擬器的區(qū)別!framework的指令集和工程的運行環(huán)境要對上!當然,合并執(zhí)行真機和執(zhí)行文件的另當別論了。
引入framework的操作這里無需贅敘了:

4)在使用的地方 #import
#import <StaticLibObject/StaticLibSDK.h>
5)調(diào)用StaticLibSDK.h中的方法
[StaticLibSDK staticLibSDKTest];
很開心的快捷鍵Cmd+R,發(fā)現(xiàn)報錯了:

具體錯誤:framework not found StaticLibObject果然,原先的文件被我刪除了,留下的可執(zhí)行文件是支持模擬器和真機的通用文件StaticLibLastFramework,連文件名都不一樣的,難怪找不到:

上圖中的同級中有個info.plist文件,本來以為改動里面的Executable file的名字,就可以了,沒想到還是不行!

(無奈,重新合并,合并后的文件與原來的同名稱):
各自環(huán)境編譯完成,修改各自的執(zhí)行文件的名字為:真機的StaticLibObjec1和模擬器的StaticLibObject2,執(zhí)行合并生成StaticLibObject:
$ lipo -create StaticLibObjec1 StaticLibObject2 -output StaticLibObject
然后把StaticLibObject文件丟回去.framework文件夾。
再次編譯,即可成功輸出:
StaticLibObjectDemo[1980:867317] static lib sdk test method
至此,整個創(chuàng)建和使用bundle類型創(chuàng)建的framework全部完成。
制作靜態(tài)庫的注意事項
從這里搬過來的
1 )注意理解:無論是.a靜態(tài)庫還.framework靜態(tài)庫,我們需要的都是二進制文件+.h+其它資源文件的形式,不同的是,.a本身就是二進制文件,需要我們自己配上.h和其它文件才能使用,而.framework本身已經(jīng)包含了.h和其它文件,可以直接使用。
2 )圖片資源的處理:兩種靜態(tài)庫,一般都是把圖片文件單獨的放在一個.bundle文件中,一般.bundle的名字和.a或.framework的名字相同。.bundle文件很好弄,新建一個文件夾,把它改名為.bundle就可以了,右鍵,顯示包內(nèi)容可以向其中添加圖片資源。
3 )category是我們實際開發(fā)項目中經(jīng)常用到的,把category打成靜態(tài)庫是沒有問題的,但是在用這個靜態(tài)庫的工程中,調(diào)用category中的方法時會有找不到該方法的運行時錯誤(selector not recognized),解決辦法是:在使用靜態(tài)庫的工程中配置other linker flags的值為-ObjC。
4) 如果一個靜態(tài)庫很復雜,需要暴露的.h比較多的話,就可以在靜態(tài)庫的內(nèi)部創(chuàng)建一個.h文件(一般這個.h文件的名字和靜態(tài)庫的名字相同),然后把所有需要暴露出來的.h文件都集中放在這個.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出來就可以了。