0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Unity】Swift のネイティブプラグインとの byte 配列のやり取りの仕方

Last updated at Posted at 2023-12-15

本記事について

この記事は CoreBluetoothForUnity Advent Calendar 2023 の16日目の記事です。

Swift のネイティブプラグイン開発における byte 配列の渡し方、受け取る時のやり方について説明します。

例として CoreBluetoothForUnity の関数を用いますが、特に CoreBluetooth 関連の概念を知っている必要はありません。

環境

  • CoreBluetoothForUnity 0.4.5

byte 配列を引数として渡す

C#

リンク

NativeMethods.cs
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
internal static extern void cb4u_mutable_characteristic_set_value(SafeNativeMutableCharacteristicHandle handle, byte[] dataBytes, int dataLength);

byte 配列そのものと、配列の長さを引数として渡しています。

固定長な byte 配列は Blittable なためマーシャリングは不要です。

Swift

リンク

CoreBluetoothForUnity.swift
@_cdecl("cb4u_mutable_characteristic_set_value")
public func cb4u_mutable_characteristic_set_value(_ characteristicPtr: UnsafeRawPointer, _ dataBytes: UnsafePointer<UInt8>?, _ dataLength: Int32) {
    let instance = Unmanaged<CB4UMutableCharacteristic>.fromOpaque(characteristicPtr).takeUnretainedValue()
    
    if let dataBytes = dataBytes {
        instance.value = Data(bytes: dataBytes, count: Int(dataLength))
    } else {
        instance.value = nil
    }
}

byte 配列は UnsafePointer<UInt8>? として渡しています。
あとはそれをよしなに扱えばいいですが、ここでは Data に変換しています。

Data.init(bytes:count:)

byte 配列を受け取る

以下の手順で byte 配列を受け取ります。

  1. ネイティブプラグインに byte 配列の長さを問い合わせる
  2. 受け取った長さで byte 配列を作成する
  3. ネイティブプラグインに byte 配列(のポインタ)を渡して中身を詰めてもらう
.cs
internal byte[] Value
{
    get
    {
        var dataLength = NativeMethods.cb4u_mutable_characteristic_value_length(_handle);
        var data = new byte[dataLength];
        int result = NativeMethods.cb4u_mutable_characteristic_value(_handle, data, dataLength);

        if (result == 0)
        {
            return null;
        }
        return data;
    }
}

長さが 0 の場合でも、空か null かを判断するために byte 配列を作成しています。

以下に詳細を示します。

C#

リンク

NativeMethods.cs
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
internal static extern int cb4u_mutable_characteristic_value_length(SafeNativeMutableCharacteristicHandle handle);

[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
internal static extern int cb4u_mutable_characteristic_value(SafeNativeMutableCharacteristicHandle handle, byte[] dataBytes, int dataLength);

方向属性をつけていない理由

In, Out の属性はマーシャリングの動作を指定するための Attribute です。
固定長な byte 配列は Blittable であり、マーシャリングは発生しないため属性をつける必要がないと判断しました。

Swift

リンク

CoreBluetoothForUnity.swift
@_cdecl("cb4u_mutable_characteristic_value_length")
public func cb4u_mutable_characteristic_value_length(_ characteristicPtr: UnsafeRawPointer) -> Int32 {
    let instance = Unmanaged<CB4UMutableCharacteristic>.fromOpaque(characteristicPtr).takeUnretainedValue()
    
    return Int32(instance.valueLength)
}

@_cdecl("cb4u_mutable_characteristic_value")
public func cb4u_mutable_characteristic_value(_ characteristicPtr: UnsafeRawPointer, _ dataBytes: UnsafeMutablePointer<UInt8>, _ dataLength: Int32) -> Int32 {
    let instance = Unmanaged<CB4UMutableCharacteristic>.fromOpaque(characteristicPtr).takeUnretainedValue()
    
    guard let value = instance.value else {
        return 0
    }
    
    value.withUnsafeBytes { (valueBytes: UnsafeRawBufferPointer) in
        let valueBytesPtr = valueBytes.bindMemory(to: UInt8.self).baseAddress!
        dataBytes.update(from: valueBytesPtr, count: Int(dataLength))
    }
    return 1
}

UnsafeMutablePointer への書き込みには update(from:count:) を使っています。

この from に渡すコピー元のポインタを得るために value (Data 型)からwithUnsafeBytes や bindMemory を使用しています。

その他のやり方

  • NSData を使うと、byte 配列の取得処理を共通化することはできそうです。

おわりに

本記事では byte 配列の渡し方、受け取り方について説明しました。
byte 配列の受け取りは、ありそうで情報が全然見当たりませんでした。
特に Data からの byte 配列取得のあたりは Copilot に大いに助けられました。
あまり使う頻度は多くなさそうではありますが、参考になれば幸いです!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?