如何在Xcode 6 iOS 8中創建一個FrameWork(翻譯文章)

原文:https://insert.io/frameworkios8xcode6/ 來自Oded Regev

網上充滿了關于如何構建一個iOS Framework的教程。然而,當我們開始了著手開始做這件事情時候,仍然必須克服一些不小的挑戰,才能夠得到以我們想要的方式工作的SDK。

此外,在Xcode 6中,蘋果極大地改變開發人員創建和構建Frameworks的方式,所以你會發現在互聯網上很多的frameworks制作教程都是沒有及時更新。

在這篇文章中,我們會告訴你,如何一步一步在iOS8創建和構建一個Framwork,本教程中的Framework源代碼可以在Github獲取到。

我們將針對性指出下面這些重要的挑戰:

  • 如何混合Swift和Objective-C代碼結合在同一個SDK中?
  • 如何構建能被所有相關的架構(armv7,armv7s,arm64,i386)使用的framework。如果你只需要這一個解決方案,只需要添加一個新的構建階段(Build Phase)到項目中,并使用“run script“, 腳本ios-build-framework-script.sh可以在這篇文章的底部找到。

在我們的例子中,我們將使用一個管理器(Manager)啟用\禁用framework,CustomView類將包含(驚喜吧)一個自定義的UIView。在這個例子中,我們要告訴你如何把xib文件和PNG文件資源整合在Framework中。

讓我們開始第1步 #1

1)從頭開始創建一個項目

因為Xcode6中有一個內置的選項來創建一個動態的Framework項目。選擇這個選項,如果你需要從頭開始創建一個框架,項目的選擇:

“靜態庫(Static Library)”和“框架(Framework)”的區別是什么?

“靜態庫”主要是將代碼編譯成.a文件的樣式,例如InsertLib.a。可以通過導出的靜態庫與他人共享,靜態庫中包含一些公共類和方法,客戶端獲取到靜態庫后可以使用這些公共類和方法。

“Cocoa Touch Framework”實質上是一個包,其中包含一個“動態庫(dynamic library)”,若干.h文件和資源文件。 “動態庫”的概念(換個詞“動態鏈接(dynamic linking)”) 就是有共享代碼的一個副本在單個設備中(CoreLocation.Framework就是一個例子)由所有鏈接到它的應用程序共享。這種動態鏈接的方式將提高系統的性能,通過最小化framework的內存使用。

2)添加Manager類文件,下面是代碼:

InsertManager.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface InsertManager : NSObject

+(instancetype) sharedManager;

-(void) startManager;
-(void) stopManager;

-(void) showMessageInViewController:(UIViewController *)viewController;

-(BOOL) isManagerRunning;

@end

InsertManager.m

#import "InsertManager.h"
#import "CustomView.h"

@interface InsertManager()

@property (nonatomic) BOOL isEnabled;

@end

@implementation InsertManager

+ (instancetype) sharedManager {
   static InsertManager *sharedManager = nil;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
      sharedManager = [[[self class] alloc] init];
   });
   return sharedManager;
}

- (void) startManager {
   NSLog(@"Manager is running");
   _isEnabled = YES;
}

- (void) stopManager {
   NSLog(@"Manager stopped..");
   _isEnabled = NO;
}

-(BOOL) isManagerRunning {
   return _isEnabled;
}

-(void) showMessageInViewController:(UIViewController *)viewController {
   if (_isEnabled) {
      NSBundle* frameworkBundle = [NSBundle bundleForClass:[self class]];
      CustomView *csView = [[frameworkBundle loadNibNamed:@"CustomView" owner:self options:nil] firstObject];
      csView.frame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height);
      [viewController.view addSubview:csView];
   }
}

@end

3)添加CustomView代碼:

CustomView.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface CustomView : UIView

@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIButton *closeButton;

@end

CustomView.m

#import "CustomView.h"

@implementation CustomView

- (IBAction)closeButtonClicked:(id)sender {
    [self removeFromSuperview];
}

@end

CustomView.xib - 下載從Github上,看看它是如何配置的。


Newsroom.png - 我們用這個文件作為背景圖片來演示,如何在一個框架中使PNG一類的資源文件并且傳給一個應用程序。

4)當你在Xcode中創建一個新的“Cocoa Touch Framework” 項目,默認的.h文件將被自動命名生成的“項目名.h” 。請確保您的所有公開的.h文件添加到該文件中,公開.h文件中包含公開方法,客戶端可以通過framework調用這些公開方法,在我們的例子中添加以下代碼:

#import <UIKit/UIKit.h>

//!InsertSampleFramework項目的版本號。

FOUNDATION_EXPORT double InsertSampleFrameworkVersionNumber;

//!InsertSampleFramework項目版本字符串。

FOUNDATION_EXPORT const unsigned char InsertSampleFrameworkVersionString [];

//在這頭,你應該導入使用類似語句的框架的所有公共頭

#import <InsertSampleFramework/InsertManager.h>

5)在Xcode中單擊Target,并轉到“Build Phase”部分,在“Headers”中添加需要公開的.h文件到“Public”中

Build Phase:

6)現在只是建立了Framework,還沒有準備好調用framework的項目。我們只能夠使用該framework在一個項目應用中。我們將在名為“Tabster”蘋果范例項目使用這個framework。該項目的完整源代碼可以從iOS Developer Library 下載,搜索“Tabster”,點擊結果。在Tabster頁面,查找按鈕“Download Sample Code”,下載代碼,并在Xcode打開項目。

來看看如何能夠讓我們的Framework在這個項目中工作起來...

在項目中集成framework

1)打開Tabster項目并運行應用程序,看到它如我們期望一樣運行起來。

2)復制“InsertSampleFramework”項目的根文件夾到Tabster的根文件夾

3)現在拖動Framework項目到Tabster項目中作為一個依賴(請注意,您必須先關閉Framework項目的Xcode的窗口,因為xcodeproj只可以在一個Xcode窗口中打開)。

4)加入該Framework作為依賴在Build Phases中

5)加入該框架為“Link Binary with Libraries”。如果框架有Swift代碼,你還需要添加框架中的““General”標簽下的“Embedded Binaries”

6)點擊Run,看看它是是否能工作,這個操作是一個完整性檢查(注意,我們還沒有用代碼集成framework)。

7)現在讓我們在Tabster項目中使用我們的神奇的Framework。Tabster這是一個相當簡單的應用程序:打開Storyboard ,并添加一個label(Insert Framework Enable\Disable),UISegmentControl和一個UIButton到ThreeViewController

8)在Tabster的ThreeViewController.m中添加:

#import<InsertSampleFramework/InsertManager.h>

9)添加下面的IBActions到ThreeViewController.m:

#pragma mark - IBAction

- (IBAction)segmentValueChanged:(id)sender {
    UISegmentedControl *sc = (UISegmentedControl *)sender;
    NSInteger selectedSegment = sc.selectedSegmentIndex;
    if (selectedSegment == 1) {
        [[InsertManager sharedManager] startManager];
    }
    else if (selectedSegment == 0) {
        [[InsertManager sharedManager] stopManager];
    }
}

- (IBAction)showCustomView:(id)sender {
    [[InsertManager sharedManager] showMessageInViewController:self];
}

10)運行應用程序,點擊標簽“Three”,點擊 On\Off segment control。點擊確認按鈕“Show Custom View”將顯示view,確保manager運行時才能使用。

分發我們的framework使其能夠融合到其他外部應用程序中

大多數公司和個人開發為iOS開發框架(framework),最終希望將自己的框架能夠分發給別人使用。你必須要做的最重要的一步就是,建立對所有可能的架構(armv7,armv7s,arm64,X86等)都支持的框架。一為架構的每個家庭(iPhone模擬器,舊設備(ARMv7的,armv7s),新設備(arm64) - 我們為了做到這一點,通過增加一個“Build Phase”運行一個腳本,腳本將build framework3次。

點擊框架目標,并添加一個“New Run Script Phase”:

這一行你應該復制和粘貼到build phase:

/${PROJECT_DIR}/OTRGuideManager/ios-build-framework-script.sh

一些開發人員更喜歡直接在此框中寫腳本,我更傾向于讓腳本在一個單獨的sh文件,這樣我可以在Git的跟蹤它,當需要在未來,他們跟蹤更改。

具體的腳本是在ios-build-framework-script.sh:

set -e
set +u
#避免遞歸調用這個腳本。
if [[ $SF_MASTER_SCRIPT_RUNNING ]]
then
exit 0
fi
set -u
export SF_MASTER_SCRIPT_RUNNING=1

#常量
SF_TARGET_NAME=${PROJECT_NAME}
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

#構建Target
if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]
then
SF_SDK_PLATFORM=${BASH_REMATCH[1]}
else
echo "Could not find platform name from SDK_NAME: $SDK_NAME"
exit 1
fi

if [[ "$SF_SDK_PLATFORM" = "iphoneos" ]]
then
echo "Please choose iPhone simulator as the build target."
exit 1
fi

IPHONE_DEVICE_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos

#生成其他(非虛擬機)平臺
xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/arm64" SYMROOT="${SYMROOT}" ARCHS='arm64' VALID_ARCHS='arm64' $ACTION

xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}"  CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/armv7" SYMROOT="${SYMROOT}" ARCHS='armv7 armv7s' VALID_ARCHS='armv7 armv7s' $ACTION

#復制framework結構的universal folder(先清空)
rm -rf "${UNIVERSAL_OUTPUTFOLDER}"
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework"

#把這些架構(architectures)攪碎融合到一起
lipo -create  "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/arm64/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/armv7/${PROJECT_NAME}.framework/${PROJECT_NAME}" -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}"

1)請確保選擇是iPhone模擬器,當你想建立的發布版本的framework - 腳本會檢測,并自動建立的其他平臺。

2)運行“ Build”后,你需要選擇Distribution-universal目錄下的Framework。

3)整合framework到Xcode項目中,使用framework和你已經配置好的設置。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容