Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@fuziki

[Unity]Swift だけで作ったNative PluginでUnityにコールバック

Swift だけで作った Native Plugin で Unity にコールバックする

  • Swift だけで、Unity の iOS の Native Plugin を作る方法を紹介しました

  • Swift から Unity へコールバックしたい場合がよくあります
  • 例えば、Bluetoothを使えるようにするアセットで、検出した BLEデバイスを Unity へ通知する事が可能です
  • Unity から Native に関数のポンタを渡しておきます
  • iOS では、受け取った関数のポインタを実行します

今回のサンプル

  • リポジトリはこちらです

処理の流れ

  1. Unity で実行されるコールバックの型と関数を用意する
  2. 関数のポインタを渡して、コールバックを登録する関数を実装する
  3. 実際に呼び出される関数を実装する
  4. コールバックを登録する関数を呼び出す
    == ここまで C# ここから Swift ===
  5. コールバックを登録する関数を実装する
  6. 受け取った関数のポインタを実行する

Unity の実装

最終目標

  • Swift で作成された任意の文字列で、swiftPmPlugin_callBackAction が実行されることを目指します
private static event Action<string> swiftPmPlugin_callBackAction;

Unity で実行されるコールバックの型と関数を用意する

  • コールバックされる関数の型を決めます
  • 文字列の引数1つだけです
  • 定義には、UnmanagedFunctionPointer を付けます
  • 引数には、MarshalAs を付けます
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void swiftPmPlugin_callBackType([MarshalAs(UnmanagedType.LPStr), In] string message);

関数のポインタを渡して、コールバックを登録する関数

  • 関数のポインタを引数に持つ関数です
  • 関数のポインタの引数には、[MarshalAs(UnmanagedType.FunctionPtr)] を付けます
[DllImport("__Internal")]
private static extern void swiftPmPlugin_callBack([MarshalAs(UnmanagedType.FunctionPtr)] swiftPmPlugin_callBackType callback);

Swift から呼び出される関数

  • MonoPInvokeCallback を付けて、作成したコールバックの型の関数を実装します
  • 最終目標である swiftPmPlugin_callBackAction を実行します
[MonoPInvokeCallback(typeof(swiftPmPlugin_callBackType))]
private static void swiftPmPlugin_callBackHandler(string message)
{
    swiftPmPlugin_callBackAction(message);
}

コールバックを登録する

  • Swift から受け取った文字列の処理を swiftPmPlugin_callBackAction に実装します
swiftPmPlugin_callBackAction = (string message) =>
{
    Debug.Log("native message -> " + message);
};
  • コールバックを登録します
swiftPmPlugin_callBack(swiftPmPlugin_callBackHandler);

Swift の実装

C# (c) の呼び出し口を作る

  • @_cdecl を付けて Swift で関数を定義します
  • コールバックは、C言語で定義されるので、@convention(c) を付けます
  • Swift.String から一度、NSString へ変換して、UnsafePointer<CChar> を取得します
@_cdecl("swiftPmPlugin_callBack")
public func swiftPmPlugin_callBack(_ handler: @convention(c) (UnsafePointer<CChar>) -> Void) {
    let str = "this is swift string"
    let nsStr = str as NSString
    handler(nsStr.utf8String!)
}

Framework の出力と設定

  • こちらの記事の Framework でビルドする の章以降と同じ手順で実行ビルド可能です

  • swiftPmPlugin_callBack を実行したときに、swiftPmPlugin_callBackAction の内容が実行されている事を確認します

おわりに

  • Swift が C言語と親和性が高く、Unity と Swift のやりとりは、コールバックなどを含めて比較的容易に実装が可能です
  • Objective-C を挟まなくても大概のことはできそうだと思っています
  • また、Cのインタフェースを揃えて、事前に Framework 化すると、Swift 実装の場合でも、PostProcess が不要となるので、Swift での Native Plugin が実装しやすいです
  • Swift から Unity コールバックするのは、応用の幅が広いので、活用して行きたいです
2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What is going on with this article?