- 概要
- SwiftからObjCを呼び出すためのBridge用ファイルを生成・設定する
- Objective-CからSwiftのメソッドを呼び出す
- Objective-CからSwiftのクラスをイニシャライザを使って生成する
- その他気になったところ
概要
以前、Objective-Cを用いたプラグイン生成については記事を書きました。
今回はSwiftを用いたプラグイン作成方法です。
Unity側で準備する内容は基本的には大きく違いませんが、Xcode側でやることあったり、SwiftとObjective-Cとの連携周りについての調整が多く、そのあたりを中心にまとめておきたいと思います。
ちなみに、大本はこちらの記事を参考にさせていただきました。
SwiftからObjCを呼び出すためのBridge用ファイルを生成・設定する
通常、Xcodeプロジェクトから生成したものであればブリッジが必要になったタイミングでXcodeが聞いて自動的に生成してくれるようですが、Unityからだとそれが行われないので自分で追加、設定する必要があります。
ファイル名は任意で、必要な項目にそのファイルを設定するだけです。
設定箇所は「Swift Compiler - General > Objective-C Bridging Header」です。
$(SRCROOT)
とするとプロジェクトフォルダまでのパスを設定してくれるので、あとは作成したファイル名を続けて入力すると無事に設定されます。
$(SRCROOT)/Bridging-Header.h
ヘッダファイルの中身は、Swiftから呼ばれる可能性のあるものをインポートしておきます。
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> #import "UnityInterface.h"
Objective-CからSwiftのメソッドを呼び出す
Swiftのバージョンなどによって挙動が違うようですが、Swift4から(?)明示的に書かないとObjCに対して公開されないようになったようです。
そのため、ObjCに対して公開する場合は@objc
をつけて宣言する必要があるようです。
class ExampleClass : NSObject { @objc static func swiftMethod(_ message: String) { print("\(#function) is called with message: \(message)") } }
ObjCから呼び出している箇所はこんな感じ↓
extern "C" { void _ex_callSwiftMethod(const char* message) { [ExampleClass swiftMethod:[NSString stringWithUTF8String:message]]; } }
ちなみに、この@objc
が必要な理由はこちらの記事で解説されているので、興味がある人は読んでみるといいかもです。
Objective-CからSwiftのクラスをイニシャライザを使って生成する
例えば以下のようなSwiftクラスを定義したとします。
public class SwiftClass : NSObject { var name: String? var age: Int? @objc public init(name: String, age: Int) { self.name = name self.age = age } }
これを、Objective-Cで利用するには以下のようにします。
SwiftClass *aClass = [[SwiftClass alloc] initWithName:@"hoge" age:@20]
Tips
< Product_Module_Name>-Swift.h
をCommand
+ Left Clickすると定義に飛べるので、自動生成したヘッダファイルを見て、Swiftのメソッドがどうエクスポートされているかを確認するとエラー解消が早いかもしれません。
(Product_Module_Name
はBuild Settingsで確認することができます)
ちなみに、以下のようなクラス・メソッドの場合のエクスポート例です。
Swiftの定義は以下。
import Foundation public class Callback : NSObject { var objectName: String? var methodName: String? @objc public init(objectName: String, methodName: String) { self.objectName = objectName self.methodName = methodName } @objc public func Picked(date: String) { UnitySendMessage(objectName, methodName, date) } }
ヘッダには以下のように書き出される。
@interface Callback : NSObject - (nonnull instancetype)initWithObjectName:(NSString * _Nonnull)objectName methodName:(NSString * _Nonnull)methodName OBJC_DESIGNATED_INITIALIZER; - (void)PickedWithDate:(NSString * _Nonnull)date; - (nonnull instancetype)init SWIFT_UNAVAILABLE; + (nonnull instancetype)new SWIFT_DEPRECATED_MSG("-init is unavailable"); @end
Objective-Cからはこんな感じで呼び出します。
Callback *callback = [[Callback alloc] initWithObjectName:objStr methodName:methodStr];
[callback PickedWithDate:@"2019/06/07"];
その他気になったところ
Swift Versionの設定
上記設定をしてビルドをしようとすると、Swiftのバージョンについての問題を指摘されてエラーとなりビルドが失敗します。
設定項目があってそこを設定するだけなので、該当エラーが出たら以下の箇所を適切に設定してください。