Unity/UWPでBLEを扱うプラグインを作る

(2017-06-04)

コードはここ

この動画の 50:00あたりから説明があるように、 ビルドされたWSAが読むUWPのdllのほかに、 Unityエディタ上から読むための.NET Framework3.5のdllを用意する。 こうすることで実行環境ごとの違いをUnityコード上で気にしなくてもよくなる。

新しいプロジェクトで

  • Visual C# から.NET Framework 3.5にしてクラスライブラリ(.NET Framework)

  • Visual C# -> Windows -> ユニバーサルからクラスライブラリ(ユニバーサルWindows)

の2つのプロジェクトを同じソリューションに作成する。 VS2017で.NET Frameworkのクラスライブラリプロジェクトを作成するためには Visual Studio Installerで.NET Coreのワークロードをインストールする必要がある。 また、これとは別に動作確認用のUWPアプリケーションプロジェクトを作成した。

UWPの方のプロジェクトにあるClass1.csを削除し、追加 -> 既存の項目から、 もう片方のClass1.csをリンクとして追加して、この共通のcsにUWPのコードを書いていくんだけど、 そのまま書くと当然.NET Frameworkの方でビルドできないので 実装部分を#if WINDOWS_UWP ~ #endif で囲む。UWPの方のプロジェクトにはプロパティ -> ビルドの条件付きコンパイルにWINDOWS_UWPが含まれているので有効になる。

public void Start()
{
#if WINDOWS_UWP
    ...
#endif
}

UWPでBLEを扱うのは前書いた通り。 ただし、なぜかXAMLに依存しているようでD3Dビルドすると失敗する。

UWPでBLEデバイスとペアリングして値を取得する - sambaiz-net

ビルドするとdllができるので.NET Frameworkの方をAssets/Pluginsに置いてInspectorからEditorにだけチェックを入れる。 UWPの方はAssets/Plugins/WSAに置くとWSA Playerにだけチェックが入る。

あとは普通にusingして使うだけ。Edit->Project Settings->PlayerからBluetoothのcapabilityを有効にするのを忘れずに。 Package.appxmanifestは上書きされないようなので前にビルドしたやつがあったら一旦消す。

using UnityBLE;
  
public class BLE : MonoBehaviour {

    string value = "no connection";

    public GameObject text;

    private string serviceUUID = "***";
    private string characteristicUUID = "***";

    void Start() {
        var ble = new UnityBLE.BLE();
        ble.DeviceAdded += (sender, obj) => {
            value = "DeviceID: " + obj.DeviceID;
            ble.Listen(obj.DeviceID, serviceUUID, characteristicUUID);
            ble.Stop();
        };
        ble.CharacteristicReceived += (sender, obj) =>
        {
            if (sender == ble)
            {
                if (obj.ex == null)
                {
                    value = Encoding.UTF8.GetString(obj.Value);
                }
                else
                {
                    value = obj.ex.Message;
                }
            }
        };
        ble.Start();
    }

    void Update() {
        text.GetComponent<TextMesh>().text = value;
    }
}