你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 經驗分享:Xcode 創建.a和framework靜態庫

經驗分享:Xcode 創建.a和framework靜態庫

編輯:IOS開發基礎

img (178).jpg

投稿文章,作者:Haley_Wong

最近因為項目中的聊天SDK,需要封裝成靜態庫,所以實踐了一下創建靜態庫的步驟,做下記錄。

庫介紹

庫從本質上來說是一種可執行代碼的二進制格式,可以被載入內存中執行。庫分靜態庫和動態庫兩種。

iOS中的靜態庫有 .a 和 .framework兩種形式;動態庫有.dylib 和 .framework 形式,後來.dylib動態庫又被蘋果替換成.tbd的形式。

靜態庫與動態庫的區別

靜態庫和動態庫是相對編譯期和運行期的:靜態庫在程序編譯時會被鏈接到目標代碼中,程序運行時將不再需要改靜態庫;而動態庫在程序編譯時並不會被鏈接到目標代碼中,只是在程序運行時才被載入,因為在程序運行期間還需要動態庫的存在。

總結:同一個靜態庫在不同程序中使用時,每一個程序中都得導入一次,打包時也被打包進去,形成一個程序。而動態庫在不同程序中,打包時並沒有被打包進去,只在程序運行使用時,才鏈接載入(如系統的框架如UIKit、Foundation等),所以程序體積會小很多,但是蘋果不讓使用自己的動態庫,否則審核就無法通過。

創建.a靜態庫

第一步,新建工程。一般使用工程名就使用庫的名稱,比如我這裡用FMDB來創建靜態庫,我的工程名就取名為FMDB,創建的.a靜態庫就是libFMDB.a。

1468320478754707.jpg

1468320496343210.png

第二步,刪除系統默認創建的【FMDB.h】和【FMDB.m】文件,導入需要打包的源文件。

QQ截圖20160712184846.png

第三步(方式一),修改項目配置

727768-5d001cd4a0de30dd.jpg

點擊上圖中的【3】,彈出的列表中選擇【New Headers Phase】,打開【Headers (0 items)】,點擊左下角的【+】,選擇所有的.h文件。

QQ截圖20160712184933.png

第三步(方式二),修改項目配置

727768-78d95d4769981bad.jpg

第四步,修改導出product配置

727768-4188568eec7c43be.jpg

第五步,修改編譯指令集

727768-717773667126f998.jpg

模擬器:iPhone4s~5 : i386 iPhone5s~6plus : x86_64

真機:iPhone3gs~4s : armv7 iPhone5~5c : armv7s iPhone5s~6plus : arm64

如果第五步這裡,設置為YES,那麼編譯出來的.a靜態庫就只包含當前設備的指令集。

舉個例子:如果我們選擇iPhone 5模擬器【Command+B】編譯,則編譯出來的.a靜態庫只能用iPhone4s~5模擬器跑程序,用iPhone5s~6plus,則會報找不到x86_64的libFMDB庫。

設置為NO,則會把所有指令集的都打包合並。

第六步,編譯(快捷鍵【Command+B】

編譯時,需要用模擬器和真機各編譯一次,這樣Products目錄下的libFMDB.a靜態庫才會變為黑色,右鍵show in Finder,可以進入Products目錄下。

QQ截圖20160712191542.png

為什麼需要用模擬器和真機各編譯一次呢?

可以看到Products目錄下有【Release-iphoneos】和【Release-iphonesimulator】兩個文件件。前者裡面是真機使用的.a靜態庫,後者是模擬器使用的.a靜態庫。

注意:如果步驟四中,不將Build Configuration改為Release,則打包出來的靜態庫會存於【Debug-iphoneos】和【Debug-iphonesimulator】兩個文件夾下。

我們一般都使用Release模式,因為程序最終發布之後是Release版的,所以靜態庫也是在Release模式下使用。

如果想要通用需要將模擬器使用的靜態庫與真機使用的靜態庫合並成一個靜態庫,可以使用終端命令來實現。命令格式:

lipo -create 第一個.a文件的絕對路徑 第二個.a文件的絕對路徑 -output 最終的.a文件路徑。

本文中使用的命令如下:

lipo -create /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-ctegiztcjikewoeprxxtmryzetfa/Build/Products/Release-iphoneos/libFMDB.a /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-ctegiztcjikewoeprxxtmryzetfa/Build/Products/Release-iphonesimulator/libFMDB.a -output /Users/harvey/Desktop/libFMDB.a

補充:經過多次實踐,第三步的操作省略,依然可以導出可正常使用的包。

如果靜態庫中有category類,則在使用靜態庫的項目配置中【Other Linker Flags】需要添加參數【-ObjC]或者【-all_load】。

創建framework靜態庫

第一步,新建項目

QQ截圖20160712191641.jpg

第二步,刪除系統默認創建的【FMDB.h】和【FMDB.m】文件,導入需要打包的源文件。

QQ截圖20160712191717.jpg

第三步,修改項目配置

首先,設置需要暴漏的頭文件

QQ截圖20160712191747.jpg

這裡需要注意的是暴露出來的頭文件中import的其他類也得添加到public中暴露出來。

如果不想將import的類暴露出來,那麼在頭文件中用@class 然後在對應的.m文件中再import。

然後設置編譯模式,在Xcode菜單【Product】--->【Scheme】--->【Edit Scheme...】中

QQ截圖20160712192134.jpg

設置編譯出的靜態庫包含的指令集

QQ截圖20160712192203.jpg

最後修改生成的Mach-O格式

1468322559936793.png

第四步,編譯生成靜態庫

編譯時,需要用模擬器和真機各編譯一次,這樣Products目錄下的libFMDB.a靜態庫才會變為黑色,右鍵show in Finder,可以進入Products目錄下。

QQ截圖20160712192300.jpg

第五步,合並模擬器版framework和真機版framework

合並的命令同上面相似,不同之處是:framework靜態庫合並的不是framework,而是framework下的一個二進制文件,即上一步圖中標記的文件。

lipo -create 第一個framework下二進制文件的絕對路徑 第二個framework下二進制文件的絕對路徑 -output 最終的二進制文件路徑。

本文中使用的命令如下:

lipo -create /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-clvayfrjgytqrbdkyqrtcjkxfeuz/Build/Products/Release-iphonesimulator/FMDB.framework/FMDB /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-clvayfrjgytqrbdkyqrtcjkxfeuz/Build/Products/Release-iphoneos/Release-iphoneos.framework/FMDB -output /Users/harvey/Desktop/FMDB

最後將任何一個framework中的二進制文件替換成合並後的二進制文件即可。

把framework添加到要使用的項目中即可使用。

注意:如果創建的framework中使用了category類,則在使用framework的項目配置中【Other Linker Flags】需要添加參數【-ObjC]或者【-all_load】。

如果使用framework的使用出現【Umbrella header for module 'XXXX' does not include header 'XXXXX.h'】,是因為錯把xxxxx.h拖到了public中。

如果出現【dyld: Library not loaded:XXXXXX】,是因為打包的framework版本太高。比如打包framework時,選擇的是iOS 9.0,而實際的工程環境是iOS 8開始的。

如果創建的framework類中使用了.dylib或者.tbd,首先需要在實際項目中導入.dylib或者.tbd動態庫,然後需要設置【Allow Non-modular Includes ....】為YES,否則會報錯"Include of non-modular header inside framework module"。

QQ截圖20160712192337.jpg

補充:打包成的靜態庫肯定是比源碼類要大很多的,因為是由不同指令集不同設備的版本合並成的。所以如果你很在意你的app大小,並且也不是很需要打包成靜態庫的話,還是用原始類吧。

framework靜態庫中是可以包含圖片資源的;而.a靜態庫中不能包含圖片資源,只能另外創建一個目錄存放。

填坑記錄

上面的注意裡提到了一些坑,以及解決辦法。這裡再記錄一些:

1.framework中用到了NSClassFromString,但是轉換出來的class 一直為nil。

先來看一下這個API的官方描述

QQ截圖20160712192412.png

什麼意思呢?如果轉換出來的class為nil,有兩種情況:一種情況是這個類不存在;第二種情況是這個類還沒有被load。所以一般出現問題,都是第二種情況。

怎麼解決這個問題呢?在主工程的【Other Linker Flags】需要添加參數【-ObjC]即可。

Have Fun!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved