1. 程式人生 > >iOS製作framework以及引入到工程

iOS製作framework以及引入到工程

Framework常識

蘋果平臺的連結庫除了靜態庫 .a 和 動態庫.dylib 之外,Mac OS/iOS 平臺還可以使用 Framework。Framework 實際上是一種打包方式,將庫的二進位制檔案,標頭檔案和有關的資原始檔打包到一起,方便管理和分發,這樣 Xcode 能夠很容易的將其整合到你的工程中去。

在 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 平臺添加了動態庫的支援。為什麼 iOS 8 要新增動態庫的支援?唯一的理由大概就是 Extension 的出現。Extension 和 App 是兩個分開的可執行檔案,同時需要共享程式碼,這種情況下動態庫的支援就是必不可少的了。但是這種動態 Framework 和系統的 UIKit.Framework 還是有很大區別。系統的 Framework 不需要拷貝到目標程式中,我們自己做出來的 Framework 哪怕是動態的,最後也還是要拷貝到 App 中(App 和 Extension 的 Bundle 是共享的),因此蘋果又把這種 Framework 稱為 Embedded Framework。

系統會在需要的時候將framework載入記憶體中,多個應用程式可以同時使用同一個framework。這種方法可以使得你的程式碼易分享,在多個工程中複用,並且可以隱藏實現細節,控制公開的標頭檔案。

蘋果平臺的靜態庫和動態庫的概念與其他平臺的概念不盡相同。

  • 靜態庫:連結時完整地拷貝至可執行檔案中,被多次使用就有多份冗餘拷貝。
  • 動態庫:連結時不復制,程式執行時由系統動態載入到記憶體,供程式呼叫,系統只加載一次,多個程式共用,節省記憶體。

總結來說:其實就是載入時機和載入次數的不同。

framework分為真機—Debug(除錯)版本、真機—Release(釋出)版本、模擬器—Debug版本、模擬器—Release版本;開發中一般都打包Release(釋出)版本,將真機和模擬器版本合併,提供外界。(注意:debug和release要和引入framework的工程對應

在專案開發的過程中,例如兩個公司之間業務交流,不可能把原始碼都發送給另一個公司,這時候將私密內容打包成framework,別人只能呼叫介面,而不能知道其中實現的細節。

製作framework

步驟

1,新建工程

這裡寫圖片描述
選擇左邊那個framework,右邊那個是建立.a靜態庫的。

2,建立介面程式碼

這裡寫圖片描述
在工程中建立類,寫一些開放給外部用的介面。
第一個類,做點簡單的加法,需要公開的api就寫在h裡面

//
//  Compute.h
//  FrameworkTest
//
//  Created by yxhe on 16/7/6.
//  Copyright © 2016年 yxhe. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Compute : NSObject
- (NSInteger)addNumber:(NSInteger)a withNumber:(NSInteger)b;
@end
//
//  Compute.m
//  FrameworkTest
//
//  Created by yxhe on 16/7/6.
//  Copyright © 2016年 yxhe. All rights reserved.
//

#import "Compute.h"

@implementation Compute
- (NSInteger)addNumber:(NSInteger)a withNumber:(NSInteger)b
{
    return a + b;
}
@end

第二個類,列印

//
//  Print.h
//  FrameworkTest
//
//  Created by yxhe on 16/7/6.
//  Copyright © 2016年 yxhe. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Print : NSObject
- (void)printWords:(NSString *)words;
@end
//
//  Print.m
//  FrameworkTest
//
//  Created by yxhe on 16/7/6.
//  Copyright © 2016年 yxhe. All rights reserved.
//

#import "Print.h"

@implementation Print
- (void)printWords:(NSString *)words
{
    NSLog(@"%@", words);
}
@end

最後在自動生成的匯出標頭檔案裡把這兩個類的h都import進去

//
//  FrameworkTest.h
//  FrameworkTest
//
//  Created by yxhe on 16/7/6.
//  Copyright © 2016年 yxhe. All rights reserved.
//

#import <UIKit/UIKit.h>

//! Project version number for FrameworkTest.
FOUNDATION_EXPORT double FrameworkTestVersionNumber;

//! Project version string for FrameworkTest.
FOUNDATION_EXPORT const unsigned char FrameworkTestVersionString[];

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

3,修改buildsettings

這裡寫圖片描述

這裡寫圖片描述
選擇TARGETS裡面

  • Linking下面:Dead Code Stripping選No,Mach-O Type選擇static或者dynamic都行(在後面有點區分
  • Architectures下增加armv7s,並選中。將Build Active Architecture Only 設定為NO

4,設定Headers

這裡寫圖片描述
把需要公開呼叫的標頭檔案一道public裡面,需要隱藏的放在private裡面。

5,打包framework

  • 選擇一個模擬器,編譯工程(command + B)
  • 選擇一個真機或者Generic Device(建議),編譯工程(command + B)
  • 在Finder中找到.framework檔案

生成成功後工程目錄裡的product從紅色變成了正常顏色。
這裡寫圖片描述
會看到分成了 模擬器和真機兩個資料夾,此時就可以把這兩個.framework分別引入到對應的模擬器或者真機專案使用了。

6,合併framework

通過終端命令將兩個framework合為一個模擬器和真機都可使用的framework。

開啟控制檯輸入

lipo -create iphoneos下frameworkTest的路徑 simulator下frameworkTest的路徑 -output 新的路徑,這樣就完成了模擬器和真機版本的合併,新路徑下的frameworkTest就是你合併後的檔案,將這個檔名字改成和你未合併之前的Test一樣的名字,放到framework資料夾下,替換掉原來的frameworkTest檔案。

例如我的

lipo -create /Users/yxhe/Library/Developer/Xcode/DerivedData/FrameworkTest-gajdcpnghsabghalspugjmolohhd/Build/Products/Debug-iphoneos/FrameworkTest.framework/FrameworkTest /Users/yxhe/Library/Developer/Xcode/DerivedData/FrameworkTest-gajdcpnghsabghalspugjmolohhd/Build/Products/Debug-iphonesimulator/FrameworkTest.framework/FrameworkTest -output /Users/yxhe/Library/Developer/Xcode/DerivedData/FrameworkTest-gajdcpnghsabghalspugjmolohhd/Build/Products/FrameworkTest

在目標資料夾裡找到那個FrameworkTest檔案,拖到真機.framework資料夾裡替換掉原來的,這樣,真機.framework就可以當做universal的framework使用了。

tips

  • 合併還有另外一種方法,沒試成功,是建立Aggregate跑指令碼,不會寫T_T
  • 帶有圖片資源的需要把圖片打包成Bundle檔案,和framework一起拷貝到相應的專案中。
  • 公開的類中如果引用的private的類,打包以後對外會報錯,找不到那個private的類,可以把那個private的.h放到private裡面

使用framework

引用系統framework

1)選中專案名稱
2)選中TARGETS
3)選中Build Phases
4)在Link Binary With Libraries中新增。
5)點選“+”號,加入所需的系統提供的.framework檔案
6)引入標頭檔案,就行了

引用第三方framework

步驟

這裡主要使用之前建立的framework測試
1)從Finder裡面直接將.framework檔案直接拖到工程目錄中
這裡寫圖片描述
2)在Link Binary With Libraries中新增framework
這裡寫圖片描述
其實一般拖進去之後,這個項系統自動添加了
注意:如果是Dynamic Libray形式的framework,需要新增到Embedded Frameworks
3)在專案中引入標頭檔案即可

測試結果

目錄結構
這裡寫圖片描述
程式碼的寫法

//
//  ViewController.m
//  FrameWorkUseTest
//
//  Created by yxhe on 16/7/6.
//  Copyright © 2016年 yxhe. All rights reserved.
//

#import "ViewController.h"
// 引入framework的標頭檔案
#import <FrameworkTest/Compute.h>
#import <FrameworkTest/Print.h>

@interface ViewController ()

@end

@implementation ViewController

- (IBAction)onClick:(id)sender
{
    Compute *compute = [[Compute alloc] init];
    NSInteger sum = [compute addNumber:7 withNumber:5];
    Print *print = [[Print alloc] init];
    [print printWords:[NSString stringWithFormat:@"7 + 5 = %ld", (long)sum]];
    _numberLabel.text = [NSString stringWithFormat:@"7 + 5 = %ld", (long)sum];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

在模擬器和iphone6s真機上都成測試成功
這裡寫圖片描述

原始碼