標籤:
最近在使用使用一個網上的Demo的時候. 出現另一令人煩惱的問題 . 就是它裡面有嵌套的工程. 如所示. 工程裡面還嵌套有一個工程. 真的是讓人煞費苦心 …
其實這個問題看起來並不是很難, 如果是一般的工程的話, 解決方案有兩種:
- 我可把嵌套工程裡面的檔案拖拽出來. 修改一些屬性什麼的應該可以使用了
- 還有一種方法就是我把嵌套裡面的工程整個產生一個靜態庫檔案.把我需要使用的檔案的.h暴露出來使用.
但是這個工程比較奇葩. 他裡面是c++de一些檔案. 如果直接拖拽的話會有各種引用檔案錯誤的問題. 沒辦法現在只能使用第二種方法. 產生.a的檔案了. 雖說現在還在努力中,但是至少能看見些希望了吧!
iOS 靜態庫,動態庫與 Framework靜態庫與動態庫的區別
首先來看什麼是庫,庫(Library)說白了就是一段編譯好的二進位代碼,加上標頭檔就可以供別人使用。
什麼時候我們會用到庫呢?一種情況是某些代碼需要給別人使用,但是我們不希望別人看到源碼,就需要以庫的形式進行封裝,只暴露出標頭檔。另外一種情況是,對於某些不會進行大的改動的代碼,我們想減少編譯的時間,就可以把它打包成庫,因為庫是已經編譯好的二進位了,編譯的時候只需要 Link 一下,不會浪費編譯時間。
上面提到庫在使用的時候需要 Link,Link 的方式有兩種,靜態和動態,於是便產生了靜態庫和動態庫。
靜態庫
靜態庫即靜態連結庫(Windows 下的 .lib,Linux 和 Mac 下的 .a)。之所以叫做靜態,是因為靜態庫在編譯的時候會被直接拷貝一份,複製到目標程式裡,這段代碼在目標程式裡就不會再改變了。
靜態庫的好處很明顯,編譯完成之後,庫檔案實際上就沒有作用了。目標程式沒有外部依賴,直接就可以運行。當然其缺點也很明顯,就是會使用目標程式的體積增大。
動態庫
動態庫即動態連結程式庫(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib)。與靜態庫相反,動態庫在編譯時間並不會被拷貝到目標程式中,目標程式中只會儲存指向動態庫的引用。等到程式運行時,動態庫才會被真正載入進來。
動態庫的優點是,不需要拷貝到目標程式中,不會影響目標程式的體積,而且同一份庫可以被多個程式使用(因為這個原因,動態庫也被稱作共用庫)。同時,編譯時間才載入的特性,也可以讓我們隨時對庫進行替換,而不需要重新編譯代碼。動態庫帶來的問題主要是,動態載入會帶來一部分效能損失,使用動態庫也會使得程式依賴於外部環境。如果環境缺少動態庫或者庫的版本不正確,就會導致程式無法運行(Linux 下喜聞樂見的 lib not found 錯誤)。
iOS Framework
除了上面提到的 .a 和 .dylib 之外,Mac OS/iOS 平台還可以使用 Framework。Framework 實際上是一種打包方式,將庫的二進位檔案,標頭檔和有關的資源檔打包到一起,方便管理和分發。
在 iOS 8 之前,iOS 平台不支援使用動態 Framework,開發人員可以使用的 Framework 只有蘋果自家的 UIKit.Framework,Foundation.Framework 等。這種限制可能是出於安全的考慮。換一個角度講,因為 iOS 應用都是運行在沙箱當中,不同的程式之間不能共用代碼,同時動態下載代碼又是被蘋果明令禁止的,沒辦法發揮出動態庫的優勢,實際上動態庫也就沒有存在的必要了。
由於上面提到的限制,開發人員想要在 iOS 平台共用代碼,唯一的選擇就是打包成靜態庫 .a 檔案,同時附上標頭檔(例如的SDK)。但是這樣的打包方式不夠方便,使用時也比較麻煩,大家還是希望共用代碼都能能像 Framework 一樣,直接扔到工程裡就可以用。於是人們想出了各種奇技淫巧去讓 Xcode Build 出 iOS 可以使用的 Framework,具體做法參考這裡和這裡,這種方法產生的 Framework 還有 “偽”(Fake) Framework 和 “真“(Real) Framework 的區別。
iOS 8/Xcode 6 推出之後,iOS 平台添加了動態庫的支援,同時 Xcode 6 也原生內建了 Framework 支援(動態和靜態都可以),上面提到的的奇技淫巧也就沒有必要了(新的做法參考這裡)。為什麼 iOS 8 要添加動態庫的支援?唯一的理由大概就是 Extension 的出現。Extension 和 App 是兩個分開的可執行檔,同時需要共用代碼,這種情況下動態庫的支援就是必不可少的了。但是這種動態 Framework 和系統的 UIKit.Framework 還是有很大區別。系統的 Framework 不需要拷貝到目標程式中,我們自己做出來的 Framework 哪怕是動態,最後也還是要拷貝到 App 中(App 和 Extension 的 Bundle 是共用的),因此蘋果又把這種 Framework 稱為 Embedded Framework。
Swift 支援
跟著 iOS8 / Xcode 6 同時發布的還有 Swift。如果要在項目中使用外部的代碼,可選的方式只有兩種,一種是把代碼拷貝到工程中,另一種是用動態 Framework。使用靜態庫是不支援的。
造成這個問題的原因主要是 Swift 的 Runtime 沒有被包含在 iOS 系統中,而是會打包進 App 中(這也是造成 Swift App 體積大的原因),靜態庫會導致最終的目標程式中包含重複的 Runtime(這是蘋果自家的解釋)。同時拷貝 Runtime 這種做法也會導致在純 ObjC 的項目中使用 Swift 庫出現問題。蘋果聲稱等到 Swift 的 Runtime 穩定之後會被加入到系統當中,到時候這個限制就會被去除了。
CocoaPods 的做法
在純 ObjC 的項目中,CocoaPods 使用編譯靜態庫 .a 方法將代碼整合到項目中。在 Pods 項目中的每個 target 都對應這一個 Pod 的靜態庫。不過在編譯過程中並不會真的產出 .a 檔案。如果需要 .a 檔案的話,可以參考這裡,或者使用 CocoasPods-Packager 這個外掛程式。
當不想發布代碼的時候,也可以使用 Framework 發布 Pod,CocoaPods 提供了 vendored_framework 選項來使用第三方 Framework,具體的做法可以參考這裡和這裡。
對於 Swift 項目,CocoaPods 提供了動態 Framework 的支援,通過 use_frameworks! 選項控制。
更多有關代碼分發的擴充資料可以參考這篇部落格: http://geeklu.com/2014/02/objc-lib/
上文轉自:https://skyline75489.github.io/post/2015-8-14_ios_static_dynamic_framework_learning.html
靜態庫怎麼產生呢?簡介
在企業開發中,一些核心技術或者常用架構,出於安全性和穩定性的考慮,不想被外界知道,所以會把核心代碼打包成靜態庫,只暴露標頭檔給程式員使用(比如:友盟、百度地圖等第三方的sdk)
- 庫的分類-根據原始碼的公開情況,庫可以分為2種類型
- 開源庫 – 公開原始碼,能看到具體實現
比如SDWebImage、AFNetworking
- 閉源庫 – 不公開原始碼,是經過編譯後的二進位檔案,看不到具體實
主要分為:靜態庫、動態庫
- 靜態庫和動態庫的區別
靜態庫:連結時,靜態庫會被完整地複製到可執行檔中,被多次使用就有多份冗餘拷貝
動態庫:連結時不複製,程式運行時由系統動態載入到記憶體,供程式調用,系統只載入一次,多個程式共用,節省記憶體
注意:項目中如果使用了動態庫,會蘋果拒接 – 待驗證
靜態庫檔案的版本(4種)
- 真機-Debug版本
- 真機-Release版本
- 模擬器-Debug版本
- 模擬器-Release版本
Debug(調試)版本
1.含完整的符號資訊,以方便調試
2.不會對代碼進行最佳化
Release(發布)版本
1.不會包含完整的符號資訊
2.的執行代碼是進行過最佳化的
3.的大小會比Debug版本的略小
4.在執行速度方面,Release版本會更快些(但不意味著會有顯著的提升)
所以我們一般開發中都打包Release(發布)版本,提供外界
裝置的CPU架構簡介
模擬器:
4s~5 : i386
5s~6plus : x86_64
真機:
3gs~4s : armv7
5~5c : armv7s (靜態庫只要支援了armv7,就可以跑在armv7s的架構上)
5s~6plus : arm64
製作靜態庫 - Debug版
1.建立項目
2.添加靜態庫並命名
3.需要打包到進靜態庫的代碼,放在這個檔案夾內
4.重新建立測試類別(HSCalculate),提供外界計算兩個數和的方法
HSCalculate.h
1 2 3
|
@interface HSCalculate : NSObject + (NSInteger)sumNum1:(NSInteger)num1 num2:(NSInteger)num2; @end
|
HSCalculate.m
1 2 3 4 5 6 7 8 9 10
|
#import "HSCalculate.h"
@implementation HSCalculate
+ (NSInteger)sumWithNum1:(NSInteger)num1 num2:(NSInteger)num2 { return num1 + num2; }
@end
|
5.需要暴露給外界的檔案(介面)
6.打包支援模擬器和真機的靜態庫(分別選擇真機和模擬器運行,就會產生對應的靜態庫)
7.查看打包好的靜態庫
兩個檔案夾,裡面的.a檔案就是打包好的靜態庫
Debug-iphoneos : 真機
Debug-iphonesimulator:模擬器
可用下面命令查看靜態庫支援的cpu架構(可查看上面描述的cpu架構類型)
分別查看打包好的模擬器與真機的靜態庫所支援的cpu架構
你會發現模擬器的靜態庫少了4s~5 : i386架構
原因:
下面Debug:Yes表示只編譯選中模擬器對應的架構,No則為編譯所有模擬器支援的cup架構(Debug的Yes狀態改為No即可)
修改完後,重新編譯:
8.在本項目對該靜態庫進行調試,ViewController.m匯入HSCalculate.h,測試回合,你會發現報錯了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
#import "ViewController.h" #import "HSCalculate.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad { [super viewDidLoad];
NSInteger result = [HSCalculate sumWithNum1:23 num2:25]; NSLog(@"result: %d", result); }
@end
|
報錯:
原因:
需要匯入靜態庫(編譯即可運行成功)
9.同時支援真機與模擬器的靜態庫(需要合并)
真機和模擬器的靜態庫,是不一樣的,不能同時適用在真機和模擬器上,但要滿足這要求的話,要對編譯好的兩個靜態庫進行合并
合并好壞:
好:開發過程中既可以在真機上調試,也可以在模擬器上調試
壞:如果靜態庫太大,合并打包後,會非常大,因此很多第三方的靜態庫的.a是區分版本的
合并產生新的靜態庫:
lipo -create Debug-iphoneos/xxx.a Debug-iphonesimulator/xxx.a -output xxx.a
10.把合并好的靜態庫和外界訪問的檔案拉入到新工程,即可使用(inc檔案自己建立的)
建立工程測試:
製作靜態庫 - Release版
跟Debug版步驟一樣,只不過在編譯時間,改下面的選項即可
大概步驟差不多就這些. 其實看起來還不是很麻煩的嘛 OK 祝你好遠嘍… 以後肯定會用到的. 恩恩. mark—-先
參考:
部分轉載與 – iOS 靜態庫開發
iOS開發拓展篇—靜態庫
http://rookie.org.cn/2015/12/24/StaticLibary/
iOS中靜態庫-.a檔案產生和使用