iOSとmacのunityのnative pluginを作る 

# iOSとmacのunityのnative pluginを作る
unity editorで使えるmacOS用のbundleとiOS用のFrameworkのnative pluginを作成する手順です。
Bluetoothや動画作成など、**Unityに実装されていない機能**をiOS, macOSの機能を使うことで実現します。
[UnityPluginXcodeTemplate](https://github.com/fuziki/UnityPluginXcodeTemplate)をベースに作成します。
UnityPluginXcodeTemplateを使うことで、unityのnative pluginを作成するために必要なxcodeの複雑な設定の必要がなくなり、editorで動作確認できるbundleと実機用のframeworkが同時に開発できます。

### 今回作成するnative pluginの目的
* unity(C#)には加算演算が実装されていない(設定)です。そこで、swiftの加算演算子を使って加算演算を実現するnative pluginを実装します。
* 手順に着目しているので、今回は加算演算のみの実装ですが、同じ手順でbluetoothなどのnative pluginを作成しているので、参考になれば嬉しいです。
* iOS, macOSで使えるbluetoothのnative plugin: https://github.com/fuziki/UnityCoreBluetooth

### 作成するC#クラス
* NativeSuperCalculatorクラスです。
* 加算演算ができるAddメソッドを持っています。

```NativeSuperCalculator.cs
public class NativeSuperCalculator {
    public static int Add(int l, int r);
}
```

### 作成するSuperCalculator Xcodeプロジェクト
5つのターゲットがあります

|  Target  |   Description    |
| ---- | ---- |
|  SuperCalculator.framework| iOS BuildとExample_iOSでの動作確認に使用するframework|
|  SuperCalculator_macOS.framework  |  macOS_Exampleで動作確認に使用するframework  |
|  SuperCalculator_bundle.bundle  |  macのUnity Editorで動作確認に使用するbundle  |
|  Example_iOS  |  作成した実装をUnityに組み込む前にiOSで動作確認するために使用する  |
|  Example_macOS  |  作成した実装をUnityに組み込む前にmacOSで動作確認するために使用する  |

### 作成するswiftクラス
SuperCalculatorクラスです。
加算演算ができるaddメソッドを持っています。

```SuperCalculator.swift
@objcMembers
public class SuperCalculator: NSObject {
    public static func add(l: Int, r: Int) -> Int {
        return l + r  //swiftにしか加算演算子がない(設定)
    }
}
```

## Xcode プロジェクトを作成する

### 1. UnityPluginXcodeTemplateをcloneしてrename

```
git clone https://github.com/fuziki/UnityPluginXcodeTemplate
mv UnityPluginXcodeTemplate/ SuperCalculatorPlugin/
cd SuperCalculatorPlugin
```

### 2.  setting.ymlを編集

```setting.yml
PROJECT_NAME: SuperCalculatorPlugin
FRAMEWORK_IOS: SuperCalculator
FRAMEWORK_MACOS: SuperCalculator_macOS
BUNDLE_MACOS: SuperCalculator_bundle
EXAMPLE_IOS: Example_iOS
EXAMPLE_MACOS: Example_macOS
```

### 3.  xcodeprojを作成する

xcodegenを使用して、Xcodeディレクトリ下にxcodeprojを作成します。

```
make setup
open Xcode/SuperCalculatorPlugin.xcodeproj/
```

## Swiftで機能を実装する
### 1. SuperCalculator.swiftの実装
 1. xcodeプロジェクトのNavigator AreaからLibrary/Sourcesを右クリック→ new file...を選択
 2. swift fileを選択し、next
 3. ファイル名はSuperCalculatorを指定、targetはSuperCalculator, SuperCalculator_macOS, SuperCalculator_bundleを選択してcreate
<img width="1089" alt="スクリーンショット 2020-02-04 22.26.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/c5e87399-fc7b-304c-5046-827c0f0e850c.png">

 4. SuperCalculatorクラスを実装する
 5. objective-cから呼び出すために@objcMembers属性をつけます。

```SuperCalculator.swift
@objcMembers
public class SuperCalculator: NSObject {
    public static func add(l: Int, r: Int) -> Int {
        return l + r//swiftにしか加算演算子がない(設定)
    }
}
```

### 2. Unityからの呼び出し部分の実装
1. NativePlugin.hの実装
* Unityのnative pluginはcの呼び出しなので、cのインタフェースを作成します。
* superCalculator_addを追加します。

```NativePlugin.h
  #ifdef __cplusplus
  extern  "C" {
  #endif
     int add_one(int num);
+    int superCalculator_add(int l, int r);  //追加する
  #ifdef __cplusplus
  }
 #endif
```

2.  NativePlugin.mmの実装
* superCalculator_addが呼ばれたら、swiftのSuperCalculator.addを呼び出して計算します。

```objc:NativePlugin.mm
int superCalculator_add(int l, int r) {
    return (int)[SuperCalculator addWithL:l r:r];
}
```

### 3. macOS, iOSでの動作確認(optional)
* viewDidLoadでsuperCalculator_addを呼び出して、正しく動作することを確認する。  
  ※ iOSは実機のみサポートです。

```swift:ViewController.swift
override func viewDidLoad() {
    super viewDidLoad()
    // Do any additional setup after loading the view.
    let res = superCalculator_add(32, 42)
    print("res: \(res)")
}
```

## UnityのNative Pluginとして導入する
### 1. iOS向けframeworkのビルド
* schemeからSuperCalculatorを選択して、ビルドする。
<img width="577" alt="スクリーンショット 2020-02-04 22.37.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/c3310747-750b-0b8a-b505-02b401585d7b.png">


### 2. macOSのunity editor向けbundleのビルド
* schemeからSuperCalculator_bundleを選択して、ビルドする。
<img width="495" alt="スクリーンショット 2020-02-04 22.38.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/18502f13-3889-3449-0b5f-ee199c0a8f8d.png">


### 3. 成果物の確認
* ４つ作成されているはず
  * Xcode/Out/Assets/SuperCalculatorPlugin/Plugins/iOS/SuperCalculator.framework.meta
  * Xcode/Out/Assets/SuperCalculatorPlugin/Plugins/iOS/SuperCalculator.framework
  * Xcode/Out/Assets/SuperCalculatorPlugin/Plugins/macOS/SuperCalculator_bundle_xxxxxxx.bundle
  * Xcode/Out/Assets/SuperCalculatorPlugin/Scripts/SuperCalculator_bundle.cs

### 4. 成果物をUnityにコピーする
* Xcode/Out/Assets/SuperCalculatorPlugin/. を Unity/LibraryUser/Assets/Plugins/. にコピーする

```
mkdir Unity/LibraryUser/Assets/Plugins/SuperCalculatorPlugin
cp -r Xcode/Out/Assets/SuperCalculatorPlugin/. Unity/LibraryUser/Assets/Plugins/SuperCalculatorPlugin/.
```

## Unityからnative pluginを使う実装
### 1. NativeSuperCalculator.csを作成し、NativeSuperCalculatorクラスを実装する
```csharp:NativeSuperCalculator.cs
using System.Runtime.InteropServices;
namespace SuperCalculatorPlugin
{
    public class NativeSuperCalculator
    {
        [DllImport(SuperCalculator_bundle.IMPORT_TARGET)]
        private static extern int superCalculator_add(int l, int r);
        public static int Add(int l, int r) {
             return superCalculator_add(l, r);
        }
    }
}
```

### 2. NewBehaviourScriptなどで呼び出してみる
```csharp:NewBehaviourScript.cs
using SuperCalculatorPlugin;
public class NewBehaviourScript : MonoBehaviour {
    void Start ()
    {
        int res = NativeSuperCalculator.Add(32, 45);
        Debug.Log("res: " + res);
    }
}
```

## おわりに
Unityに実装されていない(設定の)加算をnative pluginを使って実現するプラグインを作成しました。 
iOSの実機のみで使用する場合は、.mmファイルをベタ置きしてunityのビルドしたxcode projectにブリッジヘッダを設定すると言う方法もあるのですが、ブリッジヘッダの設定や、editorで動かないなど手間がかかるので、個人的にはbundleとframeworkを作りたい派です。
同様の手順でbluetoothや、ble keyboard, mp4作成など、unityに実装されていない、楽しい機能のネイティブプラグインを作成できるので、一度試してみて頂けると嬉しいです！