手把手教你高效快捷的創建Swift Framework

前言:

?本文是我在工作中開發 Framework 過程中的對踩過的坑走過的彎路的總結,此教程 Swift 和 OC 都適用,文章末尾附可能遇到的問題以及解決方案,希望給各位開發小伙伴一點幫助。

本文主要講了一下內容:
1,動態庫和靜態庫的區別
2,如何創建 swift 版的 framework
3,如何調試 Framework,兩種方法
4,關于 Framework 的CPU架構 以及如何合成 framework 的架構讓其即支持真機又支持模擬器,兩種方法
5,在開發 framework 中可能遇到的坑以及解決方案

開始:

?在我們開發中最離不開的就是 Framework 比如 UIKit.framework,所以對 framework 應該是比較熟悉的,那么在開發中也經常把自己的所做模塊的代碼做成 framework,場景如下:

  1. 方便給別人使用我們自己的模塊
  2. 提供給第三方使用,且又不愿意別人看到自己的內部實現邏輯
  3. 模塊化提高代碼的復用性

動態庫和靜態庫的區別

靜態庫:

?鏈接時完整地拷貝至可執行文件中,被多次使用就有多份冗余拷貝。

動態庫:

?鏈接時不復制,程序運行時由系統動態加載到內存,供程序調用,系統只加載一次,多個程序共用,節省內存。

區別:

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

總結:

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

下面就一步一步的演示如何制作一個 framework, 以及制作自己的 framework 中可能會遇到的坑,以及如何解決。作為演示做個比較簡單的數組亂序的 framework

新建一個 framework

  1. File -> new -> Progect-> 選中 iOS -> Cocoa Touch Framework
1.png
  1. 點擊 Next -> Protect Name 為 ArrayDisorderSDK launguage 選為 Swift 點擊 Next 新建完成
2.png
  1. 在 Framework 中新建文件:
    選 source 的時候 可以選擇Cocoa Touch Class 或者Swift File 等 都是可以的可以根據自己的需要選擇
3.png

類名就取為 ArrayDisorder,然后新建完成

4.png
  1. 在ArrayDisorder 類中寫下數組亂序的代碼

open class ArrayDisorder: NSObject {
    
    open func disorder (orders:Array<Any>) -> Array<Any> {
        var temp = orders
        var count = Int(temp.count)
        while count > 0 {
            let index = Int(arc4random_uniform(UInt32(Int32(count))))
            let last =  Int(count-1)
            temp.swapAt(index, last)
            count -= 1
        }
        return temp
    }
}

  • [x] 注意:也許你會發現 在 class 前面或者在disorder方法前有 open 關鍵字,說到這里先說下和這個地方和oc 制作 Framework 不同的地方
  • oc 制作 framework 會生成一個和 framework 名字一樣的類 只有.h 文件 內容如下
//! Project version number for ArrayDisorderSDK.
FOUNDATION_EXPORT double ArrayDisorderSDKVersionNumber;

//! Project version string for ArrayDisorderSDK.
FOUNDATION_EXPORT const unsigned char ArrayDisorderSDKVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <ArrayDisorderSDK/PublicHeader.h>
上面的這句注釋說的很清楚 如果你想讓別人外面找到你在 framework 中的類你必須像 <ArrayDisorderSDK/PublicHeader.h> 這種格式一樣把 你的類導入這文件中

最后一句

// In this header, you should import all the public headers of your framework using statements like #import <ArrayDisorderSDK/PublicHeader.h>

說的很清楚如果你想讓別人外面找到你在 framework 中的類你必須像 <ArrayDisorderSDK/PublicHeader.h> 這種格式一樣把 你的類導入這文件中,在編譯成 SDK 之后生成的頭文件中就可以看到你對外開放的類和方法

創建 Swift framework也會生成一個這樣的文件但是 則不需要這樣導入頭文件。只需要在要暴露給使用者的類名和方法名前面寫上 Open 或者 Public 當編譯成 Framework 之后會生成 "你的 framework 的名字-Swift.h"的文件 在這個文件中你可以看到類名前面 表有 Public 或者 Open 關鍵字的類.

什么時候用 Open 什么時候用 Public?

  1. Open 在作用域外是可以被訪問,繼承 ,用 Open 關鍵字修飾的開放類成員在作用域之外是可訪問和可覆蓋的。

  2. Pubic 在作用域外是可訪問的,但在作用域之外沒有子類。公共類成員是可訪問的,但在作用域之外是不可覆蓋的。

配置你的 Framework

  1. 配置動態或者靜態庫

點擊 framework 的 target build settings - linking -> Mach-o Type -> Static Library
或者 Dynamic Library

  1. Development Target

在這個 Demo 中 設置為支持 iOS 8


8.png
  1. 還要配置 運行編譯的成的 Build Configuration 為 release 如果不是 release 則在 release 環境下運行會出錯

走到這一步,基本 Framework 已經初步完成, Com + B

  • [x] 注意:編譯的時候 選擇的 Device 如果是模擬器 則生成的是 x86架構,僅支持模擬器,在真機上這個編譯的 Framework 則不能用 ,如果 Device 不選或者選擇你連接在電腦上的真機,則編譯成的是arm64 可以在真機上跑但是不能用在模擬器,如果制作的 framework 需要在模擬器和真機上用,則需要把這兩個架構合成一塊,這個==待會下面詳細講.==
9.png

點擊生成的 Framework 然后 Show In Finder

10.png

如圖中所示,生成了ArrayDisorderSDK.framework 那么這個文件就可以直接給別人使用了.

調試 Framework

在我們寫代碼時一般都習慣于邊寫邊調試,那么在制作 Framework 時有兩種方法調試我們的 Framework

第一種(不推薦)

新建一個名字是 testArrayDisorderDemo的 Progect 如下


11.png

直接把編譯好的 Framework 拖入到 testArrayDisorderDemo中


12.png

然后 import ArrayDisorderSDK

在 ViewDidLoad 中寫入如下代碼

  let disOrder = ArrayDisorder() //Framework 中的封裝了亂序功能的類
        //disOrder.disorder(orders: [1,2,3,4,5,6,7,8,9]) 調用ArrayDisorder 對外公布的類
        print(disOrder.disorder(orders: [1,2,3,4,5,6,7,8,9]))
        // 輸出:[8, 6, 2, 5, 3, 4, 7, 9, 1]

到此,我們簡單的 framework 就可以算完成了.

但是這中調試framework 的方法效率比較低,我們每一次調試都需要重新把原來的 framework 從testArrayDisorderDemo中刪除然后重新導入.這樣比較麻煩.那么下面有一種比較方便高效的方法。

第二種 創建一個依賴工程(推薦)

還是testArrayDisorderDemo 這個測試 Framework 的工程

如圖所示


14.png

然后把ArrayDisorderSDK 拖入到testArrayDisorderDemo 文件中 如圖


15.png

然后打開testArrayDisorderDemo

-- > General ->Embedded Binaries-> 點擊加號-> add Other -> 選中ArrayDisorderSDK.xcodeproj

如下圖


16.png

)]


17.png
18.png

再選擇 Target 的地方你會發現 現在已經有連個 Taeget 一個是testArrayDisorderDemo 一個是ArrayDisorderSDK

如果選中 testArrayDisorderDemo就是運行 Demo 如果選中ArrayDisorderSDK 就是編譯 SDK

這時你會發現可以直接在testArrayDisorderDemo 的 ViewController 中直接 導入ArrayDisorderSDK就可以了 不需要在刪除然后再拖入了. 最重要的是 ,當你選中的testArrayDisorderDemo Tagret 運行的時候 當程序走到 framework 中去的時候 你還可以打斷點等方式調試. 效率會很高.

  • [x] 注意: 當你修改 framework 中的代碼時要想測試下修改的效果,你必需先編譯下你的 framework 的 target 如本文中所示的就要先編譯下ArrayDisorderSDK的 target,不編譯的話就相當于你的 測試你 framework 的 Demo 用的還是原來的 framework 而不是修改后的

關于 Framework 的CPU架構

CPU 的架構在不同的機型上有不同的
主要有一下:

arm7: 在最老的支持 iOS7的設備上使用
arm7s: 在 iPhone 5 和 iPhone 5c 上使用
arm64: 在 iPhone 5s 的64位 ARM 處理器上
i386: 在32位模擬器上使用
x86_64: 在64位模擬器上使用

當然一個 Framework 不需要全部支持,可以根據需要.

如上文所說, 編譯的時候 選擇的 Device 如果是模擬器 則生成的是 x86架構,僅支持模擬器,在真機上這個編譯的 Framework 則不能用 ,如果 Device 不選或者選擇你連接在電腦上的真機,則編譯成的是arm64 和 arm7 可以在真機上跑但是不能用在模擬器,如果制作的 framework 需要在模擬器和真機上用,則需要把這兩個架構合成一塊,那么這就需要合成架構了.

首先,我們要了解,如何查看一個 framework 的架構

用命令: lipo -info

  • [x] 注意 -info 中 - 和 info 沒有空格,info 后面有一個空格

如圖所示


20.png

把ArrayDisorderSDK 文件拖入控制臺 然后回車
控制臺就可以輸出ArrayDisorderSDK 的 CPU 架構 如 armv7 arm64

21.png
22.png

這個是支持真機的,如果支持模擬器則不行的,需要重新編譯:

在上圖中也能看到 當選中ArrayDisorderSDK.framework show in Finder 時你會發現在上一層有四個文件夾(最多為四個如果你只在 relesae 下真機上編譯 就只有一個文件夾) ,主要分為 Debug 和 release 兩種環境下的 真機和模擬器
Debug-iphoneos/ Debug-iphonesimulator Debug 下的模擬器
Release-iphoneos/Release-iphonesimulator relesase 下的真機和模擬器

那么我們需要做的就是把Release-iphoneos/Release-iphonesimulator 下的兩種架構合成一個

架構合并:

第一種方法(不推薦)

用命令: lipo -create xx $$ -output @@
加入你framework 的名字是 ArrayDisorderSDK

xx: 表示Release-iphoneos 文件夾下的 ArrayDisorderSDK.framework/ArrayDisorderSDK 的路徑
$$ : Release-iphonesimulator 文件夾下的 ArrayDisorderSDK.framework/ArrayDisorderSDK

@@: 生成的文件名 是和你的 framework 同名的,比如叫ArrayDisorderSDK

生成的output 出來的ArrayDisorderSDK是需要把Release-iphoneos 文件夾下的 ArrayDisorderSDK.framework 的中的ArrayDisorderSDK 替換掉的.

  • [x] 注意:-create 以及-output 在 create 和 output前面以- 是沒有空格,但是在create 和 output后面是有一個空格的

上面說的可能不太好懂,那么下面演示一下,化繁為簡:
如圖


23.png

總之這種方法還是太麻煩的,容易出錯,下面介紹另外一種比較簡單的.

第二種:(推薦)

  1. 選中ArrayDisorderSDK.xcodeproj 新建一個名字為UniversalArrayDisorder 的 target


    24.png
25.png

26.png
  1. 選中 UniversalArrayDisorder --> Build Phases --> 選中加號 --> 選中 New Run Script Phase


    27.png
28.png

然后在 腳本地址

下載一個名為universal-framework.sh 文件 把文件內容拷貝到如圖所示


29.png
  • [x] 注意:universal-framework.sh 中 ${PROJECT_NAME} 要把這個換成你自己的 framework 的名字

設置完成之后 ,編譯UniversalArrayDisorder target 編譯成功之后,會自動打開一個生成 Framework 的文件夾,然后再查看架構信息你會發現,即支持真機也支持模擬器啦.

你可能會遇到的坑

1 找不到 framework

錯誤提示:

No such module xxx

解決:

原因就是 Framework Search Path 中的路徑錯了 可以參考 參考地址 解決方案手動設置 這個路徑是你向引用你的 framework 的項目拖自定義的 framework 時自動生成的 所以簡單的解決方案就是 刪除 framework 重新拖入 注意:拖的時候一定要確保 framework 和目標項目在同一個文件夾下,這樣就不會出問題了

2 找不到類

錯誤提示:

'xxxx' is unavailable: cannot find Swift declaration for this class
 xxxx 表示 framework 中的類名

解決:

framework 的架構錯誤: 如果如你的 framework 需要在模擬器上跑 那么你的 framework 必須包含x86
如果還需要在真機上跑 那么必須包含arm64 架構 可以用命令檢查架構 lipo -info 參考

3 動態庫和靜態庫的問題

錯誤提示:

Reason: image not found
 Message from debugger: Terminated due to signal 6

解決:

動態庫 Embedded Binaries沒有 添加 your framework name.framework -> 添加
如果是靜態庫 則不需要添加
如圖


32.png

寫在最后:

參考文獻:

1 :https://medium.com/flawless-app-stories/getting-started-with-reusable-frameworks-for-ios-development-f00d74827d11

2 :https://medium.com/captain-ios-experts/develop-a-swift-framework-1c7fdda27bf1

3 :https://www.raywenderlich.com/65964/create-a-framework-for-ios

本文是在我開發中遇到的問題的一個總結,總體傾向與如何更方便高效的創建自己的 framework,對于 OC 和 Swift 創建 framework 的異同介紹較少,由于本文重點不在于此,有機會下次再總結. 由于工作繁忙,水平有限,難免有不全,或者說的不合適的地方,還請看到此文章的朋友不吝賜教.或者你對本文中有不理解的地方,都希望在評論區交流. 如果此文解決了你的問題,還請點贊支持下。

Demo地址
歡迎轉載,轉載請注明出處:https://juejin.im/post/5a5269a3f265da3e347b15de
有問題請到 個人網站 http://www.wuchao.net.cn/來找我

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容