本文轉載收集自: iOS_小松哥:https://www.jianshu.com/p/90f5ec723175
如果我們有些功能要給別人用,但是又不想公開代碼實現,比如高德地圖、第三方登錄分享等等,這時候我們就要打包成庫了。庫分靜態庫和動態庫兩種:
靜態庫:以
.a和.framework為文件后綴名。
動態庫:以.tbd(之前叫.dylib) 和.framework為文件后綴名。
靜態庫與動態庫的區別
靜態庫:鏈接時會被完整的復制到可執行文件中,被多次使用就有多份拷貝。
動態庫:鏈接時不復制,程序運行時由系統動態加載到內存,系統只加載一次,多個程序共用(如系統的UIKit.framework等),節省內存。
但是蘋果不讓使用自己的動態庫,否則審核就無法通過。
我們先來看一下iOS設備有哪些架構,因為下面要用到:
模擬器:
iPhone4s-iPnone5:i386
iPhone5s-iPhone7 Plus:x86_64
真機:
iPhone3gs-iPhone4s:armv7
iPhone5-iPhone5c:armv7s
iPhone5s-iPhone7 Plus:arm64
支持armv7的靜態庫可以在armv7s上正常運行。
.a靜態庫的制作
1、先創建一個新的Xcode工程Test,需要選擇下面這個模板:
創建完成后是這個樣子的:
2、我們把默認生成的Test.h和Test.m刪掉,重新創建一個類PrintString,在這個類里面添加一個單純打印字符串的簡單方法:
3、選擇添加公開頭文件
為了讓使用者知道有哪些方法可以用,我們需要公開頭文件,這里我們公開PrintString.h:
4、修改配置
我們需要把Build Active Architecture Only修改為NO,否則生成的靜態庫就只支持當前選擇設備的架構。
5、然后編譯
我們分別選擇Generic iOS Device和任意一個模擬器各編譯一次,編譯完后,我們會看到工程中Products文件夾下的libTest.a由紅色變成了黑色,然后show in finder,看看生成的文件:
我們看到它為真機和模擬器都生成了.a靜態庫。里面都包含我們選擇公開的頭文件。
我們來看看靜態庫支持的框架:命令為lipo -info 靜態庫名字
我們看到,Debug-iphoneos里面的靜態庫支持的架構有armv7和arm64所以它只能用於真機,在模擬器上會報錯。Debug-iphonesimulator里面的靜態庫支持的架構有i386和x86_64,所以它只能用於模擬器,在真機上會報錯。
如果想要讓模擬器和真機通用一個靜態庫,我們可以使用終端命令來實現。命令格式:lipo -create 第一個.a文件的絕對路徑 第二個.a文件的絕對路徑 -output 最終的.a文件路徑:
我們看到生成了一個新的libTest.a文件。這個靜態庫就支持所有模擬器和所有真機了。然后我們創建一個文件夾,把.a和頭文件都放進去,我們最終需要使用的就是這個文件夾:
注意:為了開發方便,我們可以使用生成的通用靜態庫,但是最終上線的使用我們可以只導入真機的,這樣工程的體積也會小一些。
使用生成的.a靜態庫
新建一個工程,將上面的通用靜態庫拖進去,導入頭文件,就可以使用里面的方法了。經過試驗,我們生成的靜態庫在真機上和模擬器上都能成功打印字符串:
.frameworke靜態庫的制作
1、先創建一個新的Xcode工程LibTest,需要選擇下面這個模板:
創建完成后是這個樣子的:
創建完成后我們可以看到,工程本身自帶一個LibTest.h文件和一個Info.plist文件。
2、我們創建一個類PrintString,添加一個單純打印字符串的簡單方法:
3、選擇添加公開頭文件
為了讓使用者知道有哪些方法可以用,我們需要公開頭文件,我們需要在 並且將Target->Build Phases->Headers中的Project中要暴露的頭文件拖拽到Pulic里面,這里我們公開PrintString.h:
注意:暴露出來的頭文件中import的其他類也得添加到public中暴露出來。如果不想將import的類暴露出來,那么在頭文件中用@class 然后在對應的.m文件中再import。
4、設置支持所有架構(和.a制作一樣)
5、修改生成的Mach-O格式,因為動態庫也可以是以framework形式存在,所以需要設置,否則默認打出來的是動態庫。將target->BuildSetting->Mach-o Type 設為Static Library(默認為Dynamic Library):
6、編譯
我們分別選擇Generic iOS Device和任意一個模擬器各編譯一次,編譯完后,我們會看到工程中Products文件夾下的LibTest.framework由紅色變成了黑色,然后show in finder,看看生成的文件:
我們看到它為真機和模擬器都生成了LibTest.framework靜態庫。
我們來查看靜態庫支持的框架:與上面不同,命令為lipo -info framework下的二進制文件名字
如果想要讓模擬器和真機通用一個靜態庫,我們可以使用終端命令來實現。合並的命令與上面不同的是:framework靜態庫合並的不是framework,而是framework下的二進制文件,命令為:
lipo -create 第一個framework下二進制文件的絕對路徑 第二個framework下二進制文件的絕對路徑 -output 最終的二進制文件路徑:
然后將任何一個framework中的二進制文件替換成合並后的二進制文件,然后把framework添加到要使用的項目中即可使用。
使用生成的.framework靜態庫
新建一個工程,將靜態庫拖進去,導入頭文件,就可以使用里面的方法了。經過試驗,我們生成的靜態庫在真機上和模擬器上都能成功打印字符串:
注意:
如果靜態庫中有category類,則在使用靜態庫的項目配置中Other Linker Flags需要添加參數-ObjC或者-all_load。
如果創建的framework類中使用了.tbd,則需要在實際項目中導入.tbd動態庫。
運行調試靜態庫
如果你是開發靜態庫的人,你會發現上面的方法只是制作靜態庫,並沒有辦法運行看效果和調試bug,這時候我們可以這樣:
1、新建一個專門用來開發靜態庫的正常工程Test:
2、添加一個靜態庫的target
我們看到它生成了幾樣東西:
一個framework的target:在這里面修改靜態庫的配置們,例如支持的架構、要暴露的頭文件們和Mach-O的配置。
一個LibTest文件夾:靜態庫里面的類們都放在這里面。
product文件夾下面的LibTest.framework:在這里show in finder找到編譯后生成的靜態庫。
3、開發調試代碼
我們看到程序可以正常運行,並可以在動態庫里面蹲點運行。方便我們調試。
4、確保代碼沒問題后,選擇對應的target編譯生成。
鏈接:https://www.jianshu.com/p/90f5ec723175
iOS里靜態庫形式?
.a和.framework
iOS里動態庫形式?
.dylib和.framework
framework為什么既是靜態庫又是動態庫?
系統的.framework是動態庫,我們自己建立的.framework是靜態庫。
a與.framework有什么區別?
.a是一個純二進制文件,.framework中除了有二進制文件之外還有資源文件。
.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。
.a + .h + sourceFile = .framework。
建議用.framework.
制作靜態庫時的幾點注意:
1 注意理解:無論是.a靜態庫還.framework靜態庫,我們需要的都是二進制文件+.h+其它資源文件的形式,不同的是,.a本身就是二進制文件,需要我們自己配上.h和其它文件才能使用,而.framework本身已經包含了.h和其它文件,可以直接使用。
2 圖片資源的處理:兩種靜態庫,一般都是把圖片文件單獨的放在一個.bundle文件中,一般.bundle的名字和.a或.framework的名字相同。.bundle文件很好弄,新建一個文件夾,把它改名為.bundle就可以了,右鍵,顯示包內容可以向其中添加圖片資源。
3 category是我們實際開發項目中經常用到的,把category打成靜態庫是沒有問題的,但是在用這個靜態庫的工程中,調用category中的方法時會有找不到該方法的運行時錯誤(selector not recognized),解決辦法是:在使用靜態庫的工程中配置other linker flags的值為-ObjC。
4 如果一個靜態庫很復雜,需要暴露的.h比較多的話,就可以在靜態庫的內部創建一個.h文件(一般這個.h文件的名字和靜態庫的名字相同),然后把所有需要暴露出來的.h文件都集中放在這個.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出來就可以了。
