Swift で Unity の macOS の Native Plugin を作る

# Swift で Unity の macOS の Native Plugin を作る
* Unity は Native Plugin を作成することで、Unity から提供されていない、OS 固有の機能を使用することができます
* 例えば maxOS では、Bluetooth の利用などが出来るようになります
* こちらの記事では、Swift だけで、Unity の iOS の Native Plugin を紹介しています  

https://qiita.com/fuziki/items/955c2b35514bcfc37969

* 上記の記事の iOS の Native Plugin のプロジェクトを拡張して、macOS 向けの Native Plugin を作成します
* iOS 実機向けと、macOS 向けの Native Plugin を同時に開発し、__Editor での動作確認__を実現することで、開発効率の向上を狙っています
* 今回は、iOS 向けに作成したプロジェクトをベースに、数字の文字列を整数型に変換する `swiftPmPlugin_toNumber` 関数を持つ macOS で利用可能な Native Pugin を作成します
* リポジトリはこちら↓です

https://github.com/fuziki/UnityPluginXcodeTemplate

# macOS の bundle をビルドする
## スタート時の workspace の様子

* Swift で作った SwiftPM のライブラリと、動作確認用の Native のアプリターゲットを含むプロジェクトがあります
* アプリターゲットは今回は必須ではありません

![start_workspace.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/ff5a234a-2751-3ea6-85cf-ac161d19d583.png)

## Bundle のターゲットを作成する
* macOS-Plugin project を作成しました
* project は何でも良いです

![macOS-Plugin_project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/85cc4848-0979-3f21-949d-d272f8d5cb9d.png)

* File > New > Target から Bundle を選んで作成します
* ここでは、MacOsSwiftPmPlugin と命名しました

![select_bundle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/687fbe2a-2a4e-d44f-1201-c468a92c7d45.png)

![save_bundle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/38df4fb2-14b2-d49b-980d-50a154593fa2.png)

## Package のリンク

* bundle のターゲットを選択し、general から Frameworks に、SwiftPM のライブラリを追加します

![link_bundle_framework.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/aac9e061-6794-ebe3-a6d0-13c93dd794f9.png)


## Header のリンク
* MacOsSwiftPmPlugin 内に PrefixHeader.pch を作成します

![make_pch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/21282215-b2bc-13dc-e23b-b219d719e55a.png)

![made_pch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/d4403e0b-aee8-bf4f-0856-e3835abe6c4c.png)

* `@import {{Swift で作ったパッケージ名}};` を記述します

```c
#ifndef PrefixHeader_pch
#define PrefixHeader_pch

// Include any system framework and library headers here that should be included in all compilation units.
// You will also need to set the Prefix Header build setting of one or more of your targets to reference this file.

@import SwiftPmPlugin; // <- 追加

#endif /* PrefixHeader_pch */
```

* ビルドをすると Bundle が出力されます

![created_bundle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/1fb95e00-abe1-f133-2f2c-d5434e44d4c4.png)

* nm コマンドを利用すると、swiftPmPlugin_toNumber のシンボルが含まれることを確認できます

```
$ nm /path/to/bundle/MacOsSwiftPmPlugin.bundle/Contents/MacOS/MacOsSwiftPmPlugin | grep swiftPmPlugin_toNumber
0000000000001fe0 T _swiftPmPlugin_toNumber
```

# Unity に組み込む
* サンプルプロジェクトの Unity の Plugins/macOS/ に作成した MacOsSwiftPmPlugin.bundle を配置しました

![self_bundle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/93a99bff-3569-16ab-5521-0f0f3472de0c.png)

* macOS の場合は、DllImport 時に、bundle 名を指定する必要があるため、#if で分けました

```c#
using System;
using System.Runtime.InteropServices;
using UnityEngine;

public class Cube : MonoBehaviour
{

#if UNITY_EDITOR_OSX
    [DllImport("MacOsSwiftPmPlugin")]
#elif UNITY_IOS
    [DllImport("__Internal")]
#endif
    private static extern long swiftPmPlugin_toNumber(string stringNumber);

    void Update()
    {
        Debug.Log("number: " + swiftPmPlugin_toNumber("30"));
    }
}
```

* Unity Editor から 実行してエラーが出なければ、Native Plugin の作成成功です

# さいごに
* macOS の場合、一度 DllImport すると、Unity Editor を終了するまで保持されます
* bundle の差し替えだけだと処理が変わらないので注意してください
* ライブラリの開発時は、iOS 向けのライブラリと同様に、Native 向けのターゲットを Xcode で作成して、デバッグをすると効率的だと思います