[編集中]Unity as a LibraryでC#からSwiftの関数を呼びたい


## Unity as a LibraryでC#からSwiftの関数を呼びたい。何なら値を渡したい
Unity as a LibraryはSwiftプロジェクトにUnityで作成したプロジェクトをフレームワークとして搭載することのできる機能です。この記事ではUnity as a Libraryを用いた際に、Unity側で作成したC#からSwiftの関数を呼び出す方法について説明します


:::note warn
注意
この記事は編集中です。完全なものではありません
:::


__参考__
[【Unity】iOSネイティブプラグイン開発を完全に理解する](https://qiita.com/mao_/items/5b33c90e533a538570b8
)

## Unity側のセットアップ
Unityで作成したプロジェクトからSwiftの関数を呼び出すためには
Assets/Plugin/iOS 以下にNativeCallProxy.h, NativeCallProxy.mm という二つのファイルを用意することが必要です。

## NativeCallProxy.hを書く

NativeCallProxy.hには以下のコードを書きます。

```NativeCallProxy.h
#import <Foundation/Foundation.h>

@protocol NativeCallsProtocol
@required
- (void) SwiftMethod:(NSString*)message;
//(返り値) 関数名:(引数の型)引数名
// 以下に好きなだけ関数を足してください。

@end

__attribute__ ((visibility("default")))
@interface FrameworkLibAPI : NSObject
// call it any time after UnityFrameworkLoad to set object implementing NativeCallsProtocol methods
+(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi;

@end
```

## NativeCallProxy.mmを書く
NativeCallProxy.mmには以下のコードを書きます。
```NativeCallProxy.mm
#import <Foundation/Foundation.h>
#import "NativeCallProxy.h"

@implementation FrameworkLibAPI

id<NativeCallsProtocol> api = NULL;
+(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi
{
    api = aApi;
}

@end

extern "C" {
    void SwiftMethod(const char *message) { return [api SwiftMethod:[NSString stringWithUTF8String:message]]; }
    //返り値の型 関数名(引数) { return [api 関数名:[引数]]}
}
```

## Swiftの関数を呼ぶC#を書く
```DataExchanger.cs
using UnityEngine;
using System.Runtime.InteropServices;

public class DataExchanger : MonoBehaviour
{
    #if UNITY_IOS && !UNITY_EDITOR
        [DllImport("__Internal")]
        private static extern void SwiftMethod(string message);
    #endif

    public static void CallSwiftMethod(string message) {
        #if UNITY_IOS && !UNITY_EDITOR
            SwiftMethod(message);
        #endif
    }
}
```

## UnityをiOS向けにビルドする
Build SettingからPlatformをiOSに変更し、普通にビルド。特に変わった設定はいらない。


## SwiftProjectName-Bridging-Header.hを書く
Swiftのプロジェクト直下にSwiftProjectName-Bridging-Header.hを作成し、以下を書き込む

```SwiftProjectName-Bridging-Header.h
#import <UnityFramework/NativeCallProxy.h>
```


## Swiftで呼び出す関数を定義する

```SwiftClass.swift
import Foundation

//C#から呼び出す関数を定義するクラスには以下のようにクラスを継承する
public class SwiftClass: NSObject, ObservableObject, NativeCallsProtocol {

    override init() {  // NSObject を継承しているので、init も override する
        super.init()
        NSClassFromString("FrameworkLibAPI")?.registerAPIforNativeCalls(self)
    }
    
    public func SwiftMethod(_ message: String) {
        //好きな処理を書く
    }
}
```

## XCodeでワークスペースを作成する。
File > New から新規ワークスペースを作成。
作成したワークスペースにSwiftで作成したプロジェクトと、ビルドしたUnityのxcode projectを追加する。

## ワークスペースでUnity側の準備
ワークスペースに追加したUnityのプロジェクトの名前は**Unity-iPhone**のような名前になっていると思います。
1. Unity-iPhoneのBuild TargetをUnityFrameWorkに変更する

2. NativeCallProxy.h のBuild TargetをUnityFrameWorkに変更し、publicにする。

3. Unity-iPhone以下に存在するDataフォルダーをpublicにする。

## UnityFrameworkをビルド
ここまでの準備が完了したらUnityFrameworkをビルドする。

ビルド時に心当たりのないエラーが出た場合はXCodeのProductからClean Build Folderを実行すると解決することがあるのでまず試すとよい。

それでも解決しない場合はUnityでのビルドに問題がある場合がある。Unityでのビルドからやり直すと解決することもある。

## Swift側のProjectにUnityFrameworkを登録する
Swift側で作成したプロジェクトのターゲットを選択し、general から Frameworks に、UnityFramework のライブラリを追加します

## アプリをビルド
ターゲットを設定してアプリをビルドします。
UnityFrameworkの時と同じく、問題があれば Clean Build Folderを試してください。

UnityからSwiftの関数が呼べると思います。