本記事について
この記事は CoreBluetoothForUnity Advent Calendar 2023 の18日目の記事です。
ネイティブプラグインにおいてデリゲートを使う場合 C# 側では呼び出す静的メソッドに対して MonoPInvokeCallback 属性を付ける必要があります。
Unity の Building plug-ins for iOS のドキュメントの Using delegate の項目にも記載されています。
インスタンスメソッドを渡すことはできないため、インスタンスメソッドを呼んで欲しかったら静的メソッドを経由して呼び出す必要があります。
その方法として以下の3つを考えました。
- C# のオブジェクトに紐づくアンマネージドオブジェトのポインタを引数に渡す
- デリゲート登録時にコールバックを呼び出すインスタンスを渡す。
- クラスに ID を付与して、その ID を引数に渡す
このうち 1 がメンバ変数増やす必要がなくて簡単だったためこの方法を選択しました。
開発する上で問題は発生しませんでした。
この方法の具体的なやり方を説明します。
環境
- CoreBluetoothForUnity 0.4.6
コード
見た方が理解が早いと思うため、コードを先に示します。
internal interface INativeCentralManagerDelegate
{
// 呼び出したいメソッド
}
CoreBluetoothForUnity ではネイティブプラグインから読んでほしいメソッドはインタフェースで定義しています。
インタフェースで定義することで依存切ってるのはドキュメント生成の都合のため、本記事の内容とはほぼ関係ありません。
このインタフェースを実装したクラスのメソッドを呼びたいとだけ理解していただければ大丈夫です。
それを踏まえて以下のクラスでインスタンスメソッドの呼び出しを実装しています。
internal class NativeCentralManagerCallbacks : INativeCentralManagerCallbacks
{
readonly static Dictionary<IntPtr, INativeCentralManagerDelegate> s_centralManagerDelegateMap = new Dictionary<IntPtr, INativeCentralManagerDelegate>();
public void Register(SafeNativeCentralManagerHandle handle, INativeCentralManagerDelegate centralManagerDelegate)
{
s_centralManagerDelegateMap[handle.DangerousGetHandle()] = centralManagerDelegate;
NativeMethods.cb4u_central_manager_register_handlers(
handle,
DidConnect,
DidDisconnectPeripheral,
DidFailToConnect,
DidDiscoverPeripheral,
DidUpdateState
);
}
...
static INativeCentralManagerDelegate GetDelegate(IntPtr centralPtr)
{
return s_centralManagerDelegateMap.GetValueOrDefault(centralPtr);
}
[AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidConnectHandler))]
static void DidConnect(IntPtr centralPtr, IntPtr peripheralIdPtr)
{
GetDelegate(centralPtr)?.DidConnect(Marshal.PtrToStringUTF8(peripheralIdPtr));
}
- 事前に静的な辞書
Dictionary<IntPtr, INativeCentralManagerDelegate>
を用意しておく -
MonoPInvokeCallback
属性を付けた静的メソッドが呼び出される。 - 静的な辞書からアンマネージドオブジェクトのポインタをキーにしてインスタンスを取得する
おわりに
ネイティブプラグインからのコールバックでインスタンスメソッドを呼ぶ方法を説明しました。
IntPtr をキーにするのはいかがなものか..とは思うものの、理想通りに動いてしまっているのでまぁいいかとしています。
こっちのほうがいいよ!等あればぜひ教えてください!