一. 靜態庫的簡介
- 庫
- 所謂庫, 就是講程序代碼集合, 封裝為一個庫文件, 他是共享代碼的一種方式, 可以將自己的代碼共享給他人使用
- 庫的分類
- 開源庫: 公開代碼, 能看到代碼的具體實現
- 閉源庫:
- 不公開代碼, 將代碼的實現編譯為二進制文件, 只將API接口提供給使用者
- 閉源庫分為
- 靜態庫: .a和.framework
- 動態庫: .dylib和.framework
- 靜態庫和動態庫的區別
- 靜態庫在鏈接時, 會被完整的復制到可執行文件中; 多次使用, 就會有多次的拷貝;(import)
- 動態庫則不會復制, 只有一份, 當程序運行時動態加載到內存; 系統只加載一次, 多個程序可以共用, 節省內存
- 注意: 項目如果使用到自己的動態庫, 蘋果就不會上架你的APP
- 但是, 在WWDC2014上公布的, 蘋果對iOS8開放動態加載dylib的接口, 也就是說開放了動態庫掛載
- 靜態庫的主要用途
- 保護自己的代碼: 將自己的技術分享給其他人使用, 但是又不希望自己的代碼暴露給別人, 就可以使用靜態庫:
- 如一些技術公司提供的SDK: 支付寶/百度高德地圖/推送等
- 將MRC的項目, 打包成靜態庫, 可以直接在ARC的環境下直接使用, 不需要轉換
- 保護自己的代碼: 將自己的技術分享給其他人使用, 但是又不希望自己的代碼暴露給別人, 就可以使用靜態庫:
二. 靜態庫的制作
- 生成靜態庫的大致步驟:
- 創建一個項目, 在選擇工程文件時: iOS(Framework & Library) -> Cocoa Touch Static Library
- 選擇當生成靜態庫時, 要暴露給外人使用的頭文件
- TARGETS(項目文件) -> Build Phases -> Copy Files -> 需要暴露的頭文件后面打鉤(Code Sign On Copy)
- 如果當前是模擬器環境, 編譯程序的話, 就會得到模擬器狀態下的靜態庫
- 如果當前是真機環境, 編譯程序就會得到真機狀態下的靜態庫
- 編譯之后, 在項目工程文件處查看, 如果Products中的.a文件是紅色的, 代表創建失敗
- 如果.a文件變為白色, 代表創建成功, 右擊Show In Finder就可以查看對應版本的靜態庫
- Debug-iphoneos: 調試版本的真機靜態庫
- Debug-iphonesimulator: 調試版本的模擬器靜態庫
- Release-iphoneos: 發布版本的真機靜態庫
- Release-iphonesimilator: 發布版本的模擬器靜態庫
- 生成的靜態庫一般包括兩個文件
- include文件夾, 存放暴露出來的頭文件, 有各種屬性/方法的聲明
- .a文件: 將實現文件編譯為二進制后生成的文件
三. 靜態庫使用測試
- 使用模擬器的靜態庫:(在6S, iOS9.2模擬器環境下生成的靜態庫)
- 模擬器和真機環境下的靜態庫不能共用
- 使用低版本的模擬器, 不能運行高版本模擬器下生成的靜態庫
- 靜態庫對應的CPU架構:
- 模擬器:
- 4s---5: i386架構
- 5s---6sPlus: x86_64架構
- 真機:
- 4s: armv7
- 5/5c: armv7s(但是他兼容armv7)
- 5s---6sPlus: arm64
- 模擬器:
- 查看當前靜態庫支持的架構
- 使用終端, 進入靜態庫.a文件所在的目錄
- 使用命令: lipo -info .a文件名稱, 即可查看靜態庫所支持的系統架構
- 經過檢查, 剛剛生成的靜態庫支持的架構為: i386和x86_64, 因此他是不支持真機運行的
- 在不同的模擬器下進行編譯, 生成的靜態庫支持的架構也就不同
- 生成支持多個架構的靜態庫
- 默認情況下, 需要選中不同的模擬器分別進行編譯, 才會生成支持對應架構的靜態庫, 然后再合并靜態庫
- 如果要生成支持多個架構的靜態庫, 需要以下步驟:
- 點擊TARGET項目工程文件 -> Build Settings -> Build Active -> NO
- 該選項表示不知編譯活躍的架構(當前架構), 而是編譯所有的架構
四. 靜態庫文件的版本
-
調試版本:
- Debug-iphoneos: 真機調試版本
- Debug-iphonesimulator: 模擬器調試版本
- 特點:
- 調試版本會包含完整的符號信息, 方便調試
- 調試版本不會代碼進行優化
-
發布版本:
- Release-iphoneos: 真機發布版本
- Release-iphoneSimulator: 模擬器發布版本
- 特點:
- 發布版本不包含完整的符號信息
- 發布版本的代碼會進行優化
- 發布版本的大小比調試版本略小
- 在執行速度方面, 發布版本會更快一些, 但是效果也并不顯著
-
生成不同的版本:
- 項目 -> Edit Scheme -> Run(info) -> Release/Debug分貝進行編譯
-
生成一個既支持模擬器又支持真機的靜態庫
- 由于靜態庫針對于模擬器和真機, 生成的靜態庫版本是不一樣的(為了不同的CPU架構), 因此無法同時運行
- 靜態庫的合并
- 在終端, 使用lipo -info .a文件名稱的方法, 查看靜態庫的版本
- 合并.a文件
lipo -create Debug-iphoneos/libTools.a Debug-iphonesimulator/libTools.a -output libTools.a
- 文件合并之后, 可以查看該靜態庫目前已經支持armv7 i386 x86_64 arm64
-
合并靜態庫的特點:
- 合并后的靜態庫, 既可以在真機上調試, 也可以在模擬器上調試
- 但是如果靜態庫太大, 合并打包之后靜態庫會很大, 影響App的大小, 因此很多第三方靜態庫都是區分版本的
- 因此, 使用靜態庫的時候一定要注意靜態庫支持的版本
-
拆解指定架構的庫
- 可以將合并后的靜態庫, 按照所需版本拆解出來
- 終端命令:
lipo -thin 架構名稱 .a路徑 -output 目標路徑
五. .framework靜態庫的制作
- 制作流程
- 新建項目: 選擇.framework靜態庫
- 編譯時, 設置編譯所有的架構
- TARGET -> Build Setting -> Build Active -> NO
- 此時編譯的話, 默認產生的是動態庫, 因此要設置鏈接類型
- TARGET -> Build Setting -> 搜索Mach-o Type -> 改為靜態庫(Static Library)
六. 靜態庫的簡單小結
-
靜態庫的完整打包步驟:
- .a文件肯定是靜態庫
- .framework文件more是動態庫, 需要轉換為靜態庫(Mach-o Type)
- 確定靜態庫是否支持模擬器或者真機中的所有CPU架構(Build Active)
- 提供的靜態庫一般應該為release版本(項目文件 -> Run -> info)
-
.a和.framework靜態庫的區別
- .a是一個純二進制文件, 而.framework文件除了二進制文件, 還可以包含一些資源文件
- .a文件不能直接使用, 需要.h文件配合使用; 而.framework文件則可以直接使用
- .a + .h + sourceFile(bundle文件) = .framework文件
- 建議使用.framework文件
-
靜態庫開發中遇到的常見問題
- 一些靜態庫包含的資源文件可能與我們自己的資源文件重名
- Xcode在編譯的時候, 會把所有的資源文件導入mainBundle中, 這樣可能出現重名沖突
- 因此在靜態庫中使用圖片素材, 需要利用bundle文件
- 建立一個bundle文件, 然后向其中添加靜態庫所需的圖片
- 在庫中創建一個類方法, 返回圖片
- 編譯
- 外界如果需要使用圖片, 需要導入.h + .a + XXX.bundle文件
- 如果用戶需要導入的頭文件過多, 就可以使用一個主頭文件, 包含其他所有的頭文件, 這樣用戶只需要導入一個主頭文件就可以了
- 靜態庫程序怎樣測試
- 靜態庫本身就是一個項目文件, 為了實現某些功能, 通常需要和項目一起進行測試, 才能查看是否達到了預期的效果
- 因此可以使用復合項目的方法來解決
- 直接在項目中, 創建一個.framework的文件
- 正常設置庫文件應該做的設置
- 配合項目工程來調試你的靜態庫
- 最后設置打包靜態庫
- 一些靜態庫包含的資源文件可能與我們自己的資源文件重名
七. 靜態庫的補充
- 將MRC的項目, 打包為靜態庫, 可以在ARC下直接使用, 不需要轉換
- Swift不支持靜態庫, 他只能使用靜態庫
- 如果要想打包動態庫并且暴露API, 就需要在你需要暴露的方法前, 增加public關鍵字