[Unity插件使用心得] 适用于iOS,tvOS和Android的蓝牙LE

文章讲述了在Unity中使用蓝牙LE插件与iOS、tvOS和Android设备通信时遇到的连接问题及解决方法,涉及扫描、连接流程,以及安卓和iOS回调函数差异的处理。
摘要由CSDN通过智能技术生成

[Unity插件使用心得] 适用于iOS,tvOS和Android的蓝牙LE

unity使用【适用于iOS,tvOS和Android的蓝牙LE】插件 与传感器进行连接时碰到的一些问题和解决办法。

以示例为例,主要的功能如下:

设备信息、初始化插件

    public string DeviceName = "ledbtn";
    public string ServiceUUID = "A9E90000-194C-4523-A473-5FDF36AA4D20";
    public string LedUUID = "A9E90001-194C-4523-A473-5FDF36AA4D20";
    public string ButtonUUID = "A9E90002-194C-4523-A473-5FDF36AA4D20";
 void StartProcess()
    {
        Reset();
        BluetoothLEHardwareInterface.Initialize(true, false, () =>
        {

            SetState(States.Scan, 0.1f);

        }, (error) =>
        {

            StatusMessage = "Error during initialize: " + error;
        });
    }

扫描、连接、订阅

 void Update()
    {
        if (_timeout > 0f)
        {
            _timeout -= Time.deltaTime;
            if (_timeout <= 0f)
            {
                _timeout = 0f;

                switch (_state)
                {
                    case States.None:
                        break;

                    case States.Scan:
                        StatusMessage = "Scanning for " + DeviceName;

                        BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null, (address, name) =>
                        {
                            // if your device does not advertise the rssi and manufacturer specific data
                            // then you must use this callback because the next callback only gets called
                            // if you have manufacturer specific data

                            if (!_rssiOnly)
                            {
                                if (name.Contains(DeviceName))
                                {
                                    StatusMessage = "Found " + name;

                                    // found a device with the name we want
                                    // this example does not deal with finding more than one
                                    _deviceAddress = address;
                                    SetState(States.Connect, 0.5f);
                                }
                            }

                        }, (address, name, rssi, bytes) =>
                        {

                            // use this one if the device responses with manufacturer specific data and the rssi

                            if (name.Contains(DeviceName))
                            {
                                StatusMessage = "Found " + name;

                                if (_rssiOnly)
                                {
                                    _rssi = rssi;
                                }
                                else
                                {
                                    // found a device with the name we want
                                    // this example does not deal with finding more than one
                                    _deviceAddress = address;
                                    SetState(States.Connect, 0.5f);
                                }
                            }

                        }, _rssiOnly); // this last setting allows RFduino to send RSSI without having manufacturer data

                        if (_rssiOnly)
                            SetState(States.ScanRSSI, 0.5f);
                        break;

                    case States.ScanRSSI:
                        break;

                    case States.ReadRSSI:
                        StatusMessage = $"Call Read RSSI";
                        BluetoothLEHardwareInterface.ReadRSSI(_deviceAddress, (address, rssi) =>
                        {
                            StatusMessage = $"Read RSSI: {rssi}";
                        });

                        SetState(States.ReadRSSI, 2f);
                        break;

                    case States.Connect:
                        StatusMessage = "Connecting...";

                        // set these flags
                        _foundButtonUUID = false;
                        _foundLedUUID = false;

                        // note that the first parameter is the address, not the name. I have not fixed this because
                        // of backwards compatiblity.
                        // also note that I am note using the first 2 callbacks. If you are not looking for specific characteristics you can use one of
                        // the first 2, but keep in mind that the device will enumerate everything and so you will want to have a timeout
                        // large enough that it will be finished enumerating before you try to subscribe or do any other operations.
                        BluetoothLEHardwareInterface.ConnectToPeripheral(_deviceAddress, null, null, (address, serviceUUID, characteristicUUID) =>
                        {
                            StatusMessage = "Connected...";

                            BluetoothLEHardwareInterface.StopScan();

                            if (IsEqual(serviceUUID, ServiceUUID))
                            {
                                StatusMessage = "Found Service UUID";

                                _foundButtonUUID = _foundButtonUUID || IsEqual(characteristicUUID, ButtonUUID);
                                _foundLedUUID = _foundLedUUID || IsEqual(characteristicUUID, LedUUID);

                                // if we have found both characteristics that we are waiting for
                                // set the state. make sure there is enough timeout that if the
                                // device is still enumerating other characteristics it finishes
                                // before we try to subscribe
                                if (_foundButtonUUID && _foundLedUUID)
                                {
                                    _connected = true;
                                    SetState(States.RequestMTU, 2f);
                                }
                            }
                        });
                        break;

                    case States.RequestMTU:
                        StatusMessage = "Requesting MTU";

                        BluetoothLEHardwareInterface.RequestMtu(_deviceAddress, 185, (address, newMTU) =>
                        {
                            StatusMessage = "MTU set to " + newMTU.ToString();

                            SetState(States.Subscribe, 0.1f);
                        });
                        break;

                    case States.Subscribe:
                        StatusMessage = "Subscribing to characteristics...";

                        BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(_deviceAddress, ServiceUUID, ButtonUUID, (notifyAddress, notifyCharacteristic) =>
                        {
                            StatusMessage = "Waiting for user action (1)...";
                            _state = States.None;

                            // read the initial state of the button
                            BluetoothLEHardwareInterface.ReadCharacteristic(_deviceAddress, ServiceUUID, ButtonUUID, (characteristic, bytes) =>
                            {
                                ProcessButton(bytes);
                            });

                            SetState(States.ReadRSSI, 1f);

                        }, (address, characteristicUUID, bytes) =>
                        {
                            if (_state != States.None)
                            {
                                // some devices do not properly send the notification state change which calls
                                // the lambda just above this one so in those cases we don't have a great way to
                                // set the state other than waiting until we actually got some data back.
                                // The esp32 sends the notification above, but if yuor device doesn't you would have
                                // to send data like pressing the button on the esp32 as the sketch for this demo
                                // would then send data to trigger this.
                                StatusMessage = "Waiting for user action (2)...";

                                SetState(States.ReadRSSI, 1f);
                            }

                            // we received some data from the device
                            ProcessButton(bytes);
                        });
                        break;

                    case States.Unsubscribe:
                        BluetoothLEHardwareInterface.UnSubscribeCharacteristic(_deviceAddress, ServiceUUID, ButtonUUID, null);
                        SetState(States.Disconnect, 4f);
                        break;

                    case States.Disconnect:
                        StatusMessage = "Commanded disconnect.";

                        if (_connected)
                        {
                            BluetoothLEHardwareInterface.DisconnectPeripheral(_deviceAddress, (address) =>
                            {
                                StatusMessage = "Device disconnected";
                                BluetoothLEHardwareInterface.DeInitialize(() =>
                                {
                                    _connected = false;
                                    _state = States.None;
                                });
                            });
                        }
                        else
                        {
                            BluetoothLEHardwareInterface.DeInitialize(() =>
                            {
                                _state = States.None;
                            });
                        }
                        break;
                }
            }
        }
    }

写入

 void SendByte(byte value)
    {
        byte[] data = { value };
        BluetoothLEHardwareInterface.WriteCharacteristic(_deviceAddress, ServiceUUID, LedUUID, data, data.Length, true, (characteristicUUID) =>
        {
            BluetoothLEHardwareInterface.Log("Write Succeeded");
        });
    }

其中碰到几个问题
①扫描到蓝牙后连接不上
②安卓能正常订阅但是IOS订阅后没有应用回调函数

扫描到蓝牙后连接不上

一开始我一直用的StartingExample来改,一直没有成功,后面换了个示例MultipleLevels,一下子就成功了。仔细看了下他们的区别,只是扫描设备时少了一个回调函数,减少一个回调后续连接就成功了,问作者也只是说明了下这两个回调是干嘛的,具体导致连不上的原因我也没搞懂~

BluetoothLEHardwareInterface.Initialize (true, false, () => {

			FoundDeviceListScript.DeviceAddressList = new List<DeviceObject> ();

			BluetoothLEHardwareInterface.ScanForPeripheralsWithServices (null, (address, name) => {

				FoundDeviceListScript.DeviceAddressList.Add (new DeviceObject (address, name));

			}, null);

		}, (error) => {

			BluetoothLEHardwareInterface.Log ("BLE Error: " + error);

		});

StartingExample修改如下

//减少一个回调
case States.Scan:
                    StatusMessage = "Scanning for " + DeviceName;
                    BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null, (address, name) =>
                    {
                        if (name.Contains(DeviceName))
                        {
                            if (adressList.Contains(name))
                            {
                                return;
                            }
                            adressList.Add(name);
                            _state = States.None;
                            StatusMessage = "Found " + name;
                            _deviceAddress = address;
                            deviceObjects.Add(new DeviceObject(address, name));
                            Debug.Log($"_deviceadress1:{_deviceAddress}");
                            SetState(States.Connect, 2f);
                        }
                   
                    }, null);

作者原话:
There are 2 callbacks that can be used to detect scanned devices. The first one is for devices that are not advertising a Manufacturer specific packet of type 0xFF. The other one is for those that have that packet in their advertising.
我:好吧,不纠结,能连就行~

安卓能正常订阅但是IOS订阅后没有应用回调函数

一开始打包在安卓机上跑时,能够订阅到传感器数据,转换完在UI上显示出来。
然后去了IOS上,打包后有个非常奇怪的现象,xcode 的log上是有我订阅到了数据的,但是UI上却显示不出来,打log看了,发现没有进入回调函数。

 BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(_deviceAddress, ServiceUUID, ButtonUUID, (notifyAddress, notifyCharacteristic) =>
                        {
                            StatusMessage = "Waiting for user action (1)...";
                            _state = States.None;

                            // read the initial state of the button
                            BluetoothLEHardwareInterface.ReadCharacteristic(_deviceAddress, ServiceUUID, ButtonUUID, (characteristic, bytes) =>
                            {
                                ProcessButton(bytes);
                            });

                            SetState(States.ReadRSSI, 1f);

                        }, (address, characteristicUUID, bytes) =>
                        {
                        //订阅后数据更新时都会传到这块ProcessButton(bytes)就是自己根据设备和需求来处理数据
                            if (_state != States.None)
                            {

                                StatusMessage = "Waiting for user action (2)...";

                                SetState(States.ReadRSSI, 1f);
                            }

                            // we received some data from the device
                            ProcessButton(bytes);
                        });

找了半天定位到BluetoothDeviceScript这

BluetoothDeviceScript
public void OnBluetoothData (string deviceAddress, string characteristic, string base64Data)
{
if (base64Data != null)
{
byte[] bytes = System.Convert.FromBase64String (base64Data);
if (bytes.Length > 0)
{
deviceAddress = deviceAddress.ToUpper ();
characteristic = characteristic.ToUpper ();

#if UNITY_IOS
                if (BLEStandardUUIDs.ContainsKey(characteristic))
                    characteristic = BLEStandardUUIDs[characteristic];
#endif

                BluetoothLEHardwareInterface.Log ("Device: " + deviceAddress + " Characteristic Received: " + characteristic);

string byteString = "";
foreach (byte b in bytes)
byteString += string.Format ("{0:X2}", b);

BluetoothLEHardwareInterface.Log (byteString);

if (DidUpdateCharacteristicValueAction != null && DidUpdateCharacteristicValueAction.ContainsKey (deviceAddress))
{
Debug.Log($"part0.1");
var characteristicAction = DidUpdateCharacteristicValueAction[deviceAddress];
#if UNITY_ANDROID
characteristic = characteristic.ToLower ();
#endif
if (characteristicAction != null && characteristicAction.ContainsKey (characteristic))
{
Debug.Log($"part0.2");
var action = characteristicAction[characteristic];
if (action != null)
                        {
Debug.Log($"part0.3");
action(characteristic, bytes);
}

}
}

if (DidUpdateCharacteristicValueWithDeviceAddressAction != null && DidUpdateCharacteristicValueWithDeviceAddressAction.ContainsKey (deviceAddress))
{
var characteristicAction = DidUpdateCharacteristicValueWithDeviceAddressAction[deviceAddress];
#if UNITY_ANDROID
characteristic = characteristic.ToLower ();
#endif
Debug.Log($"part1.1");
if (characteristicAction != null && characteristicAction.ContainsKey (characteristic))
{
Debug.Log($"part1.2");
var action = characteristicAction[characteristic];
if (action != null)
                        {
Debug.Log($"part1.3");
action(deviceAddress, characteristic, bytes);
}

}
}
}
}
}


log
//2023-12-11 16:52:59.670000+0800 ble[24085:924414] | DidUpdateNotificationStateForCharacteristic| C1523F8E-C27F-AFB7-4FAA-ECF0FB1013F7| AE02
//2023-12-11 16:52:59.670520+0800 ble[24085:924414] | DidUpdateValueForCharacteristic| C1523F8E-C27F-AFB7-4FAA-ECF0FB1013F7| AE02| EWcAotRFAQAAAAAAAAAAEQABCAAAAAAAAP9/hgAFAPL/VQADAPf/
//2023-12-11 16:52:59.672097+0800 ble[24085:924414] Device: C1523F8E-C27F-AFB7-4FAA-ECF0FB1013F7 Characteristic Received: AE02
//2023-12-11 16:52:59.675121+0800 ble[24085:924414] 116700A2D44501000000000000000011000108000000000000FF7F86000500F2FF55000300F7FF
//part1.1
//BluetoothDeviceScript:OnBluetoothData(String, String, String)

//2023-12-11 16:52:59.703305+0800 ble[24085:924414] | DidUpdateValueForCharacteristic| C1523F8E-C27F-AFB7-4FAA-ECF0FB1013F7| AE02| EWcAw9RFAQAAAAAAAAAAEQABCAAAAAAAAP9/hgAFAPL/VQADAPf/
//2023-12-11 16:52:59.703723+0800 ble[24085:924414] Device: C1523F8E-C27F-AFB7-4FAA-ECF0FB1013F7 Characteristic Received: AE02
//2023-12-11 16:52:59.704003+0800 ble[24085:924414] 116700C3D44501000000000000000011000108000000000000FF7F86000500F2FF55000300F7FF
//part1.1
//BluetoothDeviceScript:OnBluetoothData(String, String, String)

//2023-12-11 16:52:59.769981+0800 ble[24085:924414] | DidUpdateNotificationStateForCharacteristic| C1523F8E-C27F-AFB7-4FAA-ECF0FB1013F7| AE02
//2023-12-11 16:52:59.770511+0800 ble[24085:924414] | DidUpdateValueForCharacteristic| C1523F8E-C27F-AFB7-4FAA-ECF0FB1013F7| AE02| EWcA5NRFAQAAAAAAAAAAEQABCAAAAAAAAP9/hgAFAPL/VQADAPf/
//2023-12-11 16:52:59.770775+0800 ble[24085:924414] Device: C1523F8E-C27F-AFB7-4FAA-ECF0FB1013F7 Characteristic Received: AE02
//2023-12-11 16:52:59.771055+0800 ble[24085:924414] 116700E4D44501000000000000000011000108000000000000FF7F86000500F2FF55000300F7FF
//part1.1
//BluetoothDeviceScript:OnBluetoothData(String, String, String)

原来是订阅的UUID的问题
安卓用的128bit 小写UUID 而 IOS回调给的UUID是16bit大写UUID
然后就很没问题了

    public string ServiceUUID = "A9E90000-194C-4523-A473-5FDF36AA4D20";
    public string LedUUID = "A9E90001-194C-4523-A473-5FDF36AA4D20";
    public string ButtonUUID = "A9E90002-194C-4523-A473-5FDF36AA4D20";
    //改为第一段的后4位数字,有字母建议大写
    private string imUUIDs = "0000";
    private string imUUID1 = "0001";
    private string imUUID2 = "0002";
  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值