Koichi Adachi

smart phone app development tips

SwiftでHogehoge.frameworkを作る

Xcode8betaが出たので、気になっていた「Swiftでコードを書いて.frameworkを作ることができるのか」を試してみました。 結論からいうとできるみたい。

検証したこと

  • DeploymentTargetはXcode8.0betaの下限のバージョンであるiOS8.0を指定。
  • Swiftで書いたライブラリコードを、アプリのSwiftコードから呼びだし
  • Swiftで書いたライブラリコードを、アプリのObjective-Cコードから呼びだし
  • Objective-Cで書いたライブラリコードを、アプリのSwiftコードから呼びだし
  • Objective-Cで書いたライブラリコードを、アプリのObjective-Cコードから呼びだし

これらすべてOKだった。

手順。 1. HogeHogeAppという名前でアプリを作成 1. MyFrameworkという名前で、CocoaTouchFrameworkを作成 1. それらをまとめるworkspaceを作成(ここではSandboxSwiftFramework.xcworkspaceとした) 1. 3に1と2を入れる

Swiftで書いたコードをライブラリに追加(外から使うにはpublicが必要)

import Foundation

public class StringUtil : NSObject{
    public class func getHoge()->String{
       return "hoge"
    }
    
    public func getFuga()->String{
        return "fuga"
    }
}

もちろん、既存のライブラリコードはObjective-Cで存在することもあるため、 ObjCのライブラリコードも試してみる

ObjCで書いたライブラリコードを追加

#import <Foundation/Foundation.h>

@interface StringEx : NSObject

+(NSString*)getHoge;
-(NSString*)getFuga;

@end
@implementation StringEx

+(NSString*)getHoge{
    return @"fuga";
}

-(NSString*)getFuga{
    return @"Hoge";
}
@end
  • 単純にObjCのファイルを追加しただけだと、外から呼び出せないため、headerをpublicに変更
  • StringEx.hのインポート文を、標準で作られるMyFramework.hに追記

f:id:sgspecial:20160618170912p:plain

//  MyFramework.h

#import <UIKit/UIKit.h>

//! Project version number for MyFramework.
FOUNDATION_EXPORT double MyFrameworkVersionNumber;

//! Project version string for MyFramework.
FOUNDATION_EXPORT const unsigned char MyFrameworkVersionString[];

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


#import "StringEx.h"

次はアプリ側。

MyFrameworkをアプリから呼べるように、アプリ側のBuildSettingsを以下のように変更。

f:id:sgspecial:20160618172332p:plain

アプリ側のSwiftコードからライブラリのクラスを読み込み

import UIKit
import MyFramework

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        print("StringUtil " + StringUtil.getHoge())
        print("StringUtil " + StringUtil().getFuga())
        print("StringEx " + StringEx.getHoge())
        print("StringEx " + StringEx().getFuga())
        
    }   
}
#import "SecondViewController.h"
@import MyFramework;

@interface SecondViewController ()

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
    NSLog(@"StringUtil %@", [StringUtil getHoge]);
    NSLog(@"StringUtil %@", [[[StringUtil alloc] init] getFuga]);
    NSLog(@"StringEx %@", [StringEx getHoge]);
    NSLog(@"StringEx %@", [[[StringEx alloc] init] getFuga]);
    
}
@end

実行するとこんな感じ。下

StringUtil hoge
StringUtil fuga
StringEx fuga
StringEx Hoge
2016-06-18 01:25:26.660 HogeHogeApp[8712:2887276] StringUtil hoge
2016-06-18 01:25:26.662 HogeHogeApp[8712:2887276] StringUtil fuga
2016-06-18 01:25:26.663 HogeHogeApp[8712:2887276] StringEx fuga
2016-06-18 01:25:26.663 HogeHogeApp[8712:2887276] StringEx Hoge

感想

WWDC16に参加中にXcode8.0betaを落としたところ、なんとDeploymentTargetの下限が8.0になっています。 「もしかしたらDynamicLinkLibraryをSwiftで作成できるのでは?」という疑問から試してみたところ、あっさりできました。 せっかくなのでラボ確認したところ、DynamicLinkLibraryはiOS7では対応しておらず、iOS8からは公式にサポートしているとのこと。

iOS7だとDynamicLinkLibraryを作ることができず、staticライブラリだとswiftでライブラリ作れないよーとXcodeに言われてしまって、いままでswiftでバイナリ配布型のライブラリは作ることができませんでした。 (オープンソースのようにソースコード配布ができるなら問題にならないですが)

これでSwiftで書いたライブラリを綺麗に管理できるようになるなーと、テンションが上がったラボでした。

追記

Xcode8.0betaのバグなのか、NSLogはエミュレーターではログを吐かない。