iOS 中的動態庫、靜態庫和 framework

寫在前面

所謂 SDK 開發,就是做一個庫(library)給別人用,本文重在介紹 iOS 平臺下的庫 --framework。

本文的結構如下:

基本認識,這一部分介紹靜態、靜態庫和framework的基本概念

iOS 系統下的 framework 總結,這一部分介紹 iOS 平臺下的庫

在 Xcode 中手動創建各類 framework

使用上面創建的 framework

本文使用的 Xcode 版本是 Version 10.1 (10B61)。

本文 demo 的 GitHub 地址在文章末尾!

1. 基本認識

1.1 什么是庫

首先來看什么是庫,庫(Library)說白了就是一段編譯好的二進制代碼,加上頭文件就可以供別人使用。

什么時候我們會用到庫呢?一種情況是某些代碼需要給別人使用,但是我們不希望別人看到源碼,就需要以庫的形式進行封裝,只暴露出頭文件。另外一種情況是,對于某些不會進行大的改動的代碼,我們想減少編譯的時間,就可以把它打包成庫,因為庫是已經編譯好的二進制了,編譯的時候只需要 Link 一下,不會浪費編譯時間。

上面提到庫在使用的時候需要 Link,Link 的方式有兩種,靜態和動態,于是便產生了靜態庫和動態庫。

我們從文件名可以直觀的分辨動態庫和靜態庫。

一般來說,動態庫以.dylib或者.framework后綴結尾;靜態庫以.a和.framework結尾。

1.2 動態庫、靜態庫和 framework 概念

嚴格意義上講,這三個概念不在一個維度上。framework 并不是庫,它只是一種打包方式,它既可以是動態庫也可以是靜態庫。

靜態庫

靜態庫即靜態鏈接庫(Windows 下的 .lib,Linux 和 Mac 下的 .a)。之所以叫做靜態,是因為靜態庫在編譯的時候會被直接拷貝一份,復制到目標程序里,這段代碼在目標程序里就不會再改變了。

靜態庫的好處很明顯,編譯完成之后,庫文件實際上就沒有作用了。目標程序沒有外部依賴,直接就可以運行。當然其缺點也很明顯,就是會使用目標程序的體積增大。

動態庫

動態庫即動態鏈接庫(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib/.tbd)。與靜態庫相反,動態庫在編譯時并不會被拷貝到目標程序中,目標程序中只會存儲指向動態庫的引用。等到程序運行時,動態庫才會被真正加載進來。

動態庫的優點是,不需要拷貝到目標程序中,不會影響目標程序的體積,而且同一份庫可以被多個程序使用(因為這個原因,動態庫也被稱作共享庫)。同時,運行時才載入的特性,也可以讓我們隨時對庫進行替換,而不需要重新編譯代碼。動態庫帶來的問題主要是,動態載入會帶來一部分性能損失,使用動態庫也會使得程序依賴于外部環境。如果環境缺少動態庫或者庫的版本不正確,就會導致程序無法運行(Linux 下喜聞樂見的 lib not found 錯誤)。

iOS Framework

除了上面提到的 .a 和 .dylib/.tbd 之外,Mac OS/iOS 平臺還可以使用 Framework。

Framework 實際上是一種打包方式,將庫的二進制文件,頭文件和有關的資源文件打包到一起,方便管理和分發,和靜態庫動態庫的本質是沒有什么關系。

在 iOS 8 之前,iOS 平臺不支持使用動態 Framework,開發者可以使用的 Framework 只有蘋果自家的 UIKit.Framework,Foundation.Framework 等。因為 iOS 應用都是運行在沙盒當中,不同的程序之間不能共享代碼,同時動態下載代碼又是被蘋果明令禁止的,沒辦法發揮出動態庫的優勢,實際上動態庫也就沒有存在的必要了。

由于上面提到的限制,開發者想要在 iOS 平臺共享代碼,唯一的選擇就是打包成靜態庫 .a 文件,同時附上頭文件。

iOS 8/Xcode 6 推出之后,iOS 平臺添加了動態庫的支持,同時 Xcode 6 也原生自帶了 Framework 支持。

2. iOS 系統下的 framework 總結

有上面對庫和framework的基本認識之后,本節對 iOS 平臺下的 framework 進行闡述。

2.1 framework 只是一種打包方式

framework 只是一種打包方式,它只是簡單的將二進制文件、頭文件以及其它的一些信息聚合在一起。

本文后面,會手動制作 static framework 和 embedded framework,這里,我們先從文件目錄結構上,研究一下這兩個 framework。

static framework 文件目錄結構如下:

?StaticFramework.frameworkgit:(master)tree.├──Headers│? └──StaticFramework.h├──Info.plist├──Modules│? └──module.modulemap├──StaticFramework└── _CodeSignature├──CodeDirectory├──CodeRequirements├──CodeRequirements-1├──CodeResources└──CodeSignature

embedded framework 文件目錄結構如下:

?EmbeddedFramework.frameworkgit:(master)?tree.├──EmbeddedFramework├──Headers│? └──EmbeddedFramework.h├──Info.plist├──Modules│? └──module.modulemap└── _CodeSignature└──CodeResources3directories, 5files

通過對比,我們發現二者并沒有太大區別,所以這也佐證了,framework只是一種打包方式,不代表庫的 link 特性。

2.2 iOS 系統下 framework 分類

從上面的描述可知,iOS 系統中的 framework 按照如下方式分類。

iOS 系統中的 framework 分類

>>> Dynamic Framework

Dynamic Framework,動態庫,系統提供的 framework 都是動態庫,比如UIKit.framework,具有所有動態庫的特性。

>>> Static Framework

Static Framework,靜態庫,用戶可以制作,可以粗略的理解為,它等價于頭文件 + 資源文件 + 二進制代碼,它具有靜態庫的屬性。

>>> Embedded Framework

Embedded Framework,這個是用戶可以制作的“動態庫”,它是受到 iOS 平臺限制(簽名機制和沙盒機制限制)的動態庫,它具有部分動態特性,比如:

Embedded Framework 可以在Extension可執行文件和APP可執行文件之間共享,但是不能像系統的動態庫一樣,在不同的 APP(進程) 中共享

系統的 Framework 不需要拷貝到目標程序中,Embedded Framework 最后也還是要拷貝到 APP 中,下圖所示的是,使用 Embedded Framework 的項目的 APP 目錄

使用 embedded framework 的 APP 可執行文件 目錄

注意:本質上講,Embedded Framework是動態庫,他只是我們給動態庫起的一個別名!!!

2.3 Embedded Framework 存在的意義

換言之,我們在哪些場景可以利用 Embedded Framework 的特性??

這個我們在另外一篇文章中闡明。

接下來,手動創建一個 static framework 和 embedded framework,來研究 framework 的特性。

3. Xcode 中手動創建 framework

下圖是當前版本 Xcode 提供的創建 framework 的模板。

framework創建模板

本節將使用這兩個模板,分別創建一個動態的framework--DynamicFramework.framework,一個靜態的framework --StaticFramework.framework。

3.1 制作 embedded framework

使用 cocoa touch framework 模板創建一個名為 EmbeddedFramework 的項目,

我們查看Build Setting --> Linking --> Mach-O Type,這個選項默認是Dynamic,表示我們當前為embedded framework。

embedded framework mech-o type 設置

為了方便測試,給framework添加一個同名的類,并給這個類添加一個log實例方法。

實現如下:

@implementationEmbeddedFramework- (void)log{NSLog(@"Hello Embedded Framework!");}@end

3.2 制作 static framework

使用 cocoa touch framework 模板創建一個名為 StaticFramework 的項目,通過設置Build Setting --> Linking --> Mach-O Type為Static Library,將我們當前的 framework 設置為 static framework。

static framework mech-o type 設置

同樣的,給 framework 添加一個同名的類,并給這個類添加一個log實例方法,方法實現如下:

@implementationStaticFramework- (void)log{NSLog(@"Hello Static Framework!");}@end

4. 使用

新建一個Single View App,在 APP里面測試我們上面創建的 framework,這個項目命名為 FrameworkDemo。

為了測試方便,我們只在模擬器 iPhone XR 中測試,不在其它架構平臺上測試。

4.1 static framework 的使用

生成StaticFramework.framework

StaticFramework 項目中,我們 target 選擇模擬器 iPhone XR,然后編譯,編譯成功之后,在 Product 文件夾下面會出現一個 StaticFramework.framework。

使用StaticFramework.framework

我們將這個 StaticFramework.framework 添加到 FrameworkDemo 這個項目中。

在 demo 工程中,使用靜態framework,調用代碼如下:

- (void)viewDidLoad {? ? [super viewDidLoad];? ? ? ? [[StaticFrameworknew]log];}

控制臺打印結果如下:

2019-02-1419:14:31.674758+0800FrameworkDemo[39272:1382553]HelloStaticFramework!

調用成功。

所以靜態庫的使用比較簡單,直接將framework 添加到項目中即可。

4.2 embedded framework 的使用

和 3.1 展示的過程一樣,我們將生成的 EmbeddedFramework.framework 添加到 demo 工程中,并且調用。

#import"ViewController.h"#import<StaticFramework/StaticFramework.h>#import<EmbeddedFramework/EmbeddedFramework.h>@interfaceViewController()@end@implementationViewController- (void)viewDidLoad {? ? [superviewDidLoad];? ? ? ? [[StaticFramework new] log];? ? [[EmbeddedFramework new] log];}@end

運行 demo,程序crash了,控制臺輸出如下。

dyld:Librarynotloaded: @rpath/EmbeddedFramework.framework/EmbeddedFrameworkReferenced from: /Users/xieshoutan/Library/Developer/CoreSimulator/Devices/9124D297-42BC-467E-B343-59441AAA0FE0/data/Containers/Bundle/Application/3DAF0FC7-D040-478B-891A-AD678109380B/FrameworkDemo.app/FrameworkDemo? Reason: image not found

"dyld: Library not loaded"解決方案

需要在工程的General里的Embedded Binaries添加這個動態庫才能使用。

image.png

將 DynamicFramework.framework 添加進去。

image.png

重新運行代碼,程序正常運行。

2019-02-1419:32:23.819682+0800FrameworkDemo[39982:1415499]HelloStaticFramework!2019-02-1419:32:23.819802+0800FrameworkDemo[39982:1415499]HelloDynamicFramework!

4.3 二者使用過程中的差異比較

Xcode 配置

前面已經看出來了,是用動態庫的時候,需要額外的在 Xcode 中進行動態庫配置。

ipa 包中表現

二者在 ipa 包中表現也不一致。

我們打開 FramewoDemo 的 ipa 包發現:

動態庫單獨放在一個文件夾Frameworks中

靜態庫和源代碼一起,打成一個二進制文件FrameworkDemo

如下是FrameworkDemo.app的文件目錄:

?FrameworkDemo.apptree.├──Base.lproj│? ├──LaunchScreen.storyboardc│? │? ├── 01J-lp-oVM-view-Ze5-6b-2t3.nib│? │? ├──Info.plist│? │? └──UIViewController-01J-lp-oVM.nib│? └──Main.storyboardc│? ? ? ├──BYZ-38-t0r-view-8bC-Xf-vdC.nib│? ? ? ├──Info.plist│? ? ? └──UIViewController-BYZ-38-t0r.nib├──FrameworkDemo├──Frameworks│? └──EmbeddedFramework.framework│? ? ? ├──EmbeddedFramework│? ? ? ├──Info.plist│? ? ? └── _CodeSignature│? ? ? ? ? └──CodeResources├──Info.plist├──PkgInfo└── _CodeSignature└──CodeResources7directories, 13files

4.4 動態庫和靜態庫的判斷 -- file 工具

在 4.3 中,我們可以通過查看 ipa 中的目錄結構的方式,來判斷靜態庫和動態庫。

這里我們可以使用file工具查看。

EmbeddedFramework.framework 的查看結果如下:

?? EmbeddedFramework.framework git:(master) ? file EmbeddedFramework

EmbeddedFramework: Mach-O 64-bit dynamically linked shared library x86_64

StaticFramework.framework 的結果如下:

?? StaticFramework.framework git:(master) ? file StaticFramework

StaticFramework: current ar archive random library

上面也可以看出,兩個 framework 只支持 x86_64 架構。

5. 總結

本文介紹了 iOS framework 相關的基礎知識,弄清楚了 iOS 中 framework 的種類、構建方法和基本使用。

但事實上,我們實際開發中,我們并不是通過這種原始的方式來構建 framework,現在比較通用的方案是基于cocopods來做的。而且實際開發中,我們構建的 framework 遠比這個復雜,包含資源文件的依賴、其它靜態庫的依賴等等。

后文,將介紹 cocopods 和 framework 的關系。

作者:TankXie

鏈接:http://www.lxweimin.com/p/662832e16625

來源:簡書

簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權并注明出處。

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

推薦閱讀更多精彩內容