使用蓝牙在两部手机之间发送数据(我正在尝试使用 aritchie 的 Plugin.BluetoothLE 插件)
Sending data between two phones with bluetooth (I'm trying to use aritchie's Plugin.BluetoothLE plugin)
我正在尝试通过蓝牙在两部手机(例如两部 iPhone,甚至跨平台)之间发送数据。
我一直在尝试使用 NuGet 中的 Plugin.BluetoothLE,它最近似乎已更新(2020 年 3 月),但我似乎无法使用任何示例代码(详情如下) .
如果有人能指出下面的错误,我将不胜感激,and/or如果有更好的方法可以通过蓝牙在两部手机之间发送数据。我的应用程序是依赖时间的,可能没有wifi网络,所以蓝牙似乎是最好的选择...
当我实现 https://github.com/aritchie/bluetoothle 上可用的演示服务器代码时,出现以下错误:
No 'AddService' method within CrossBleAdapter.Current.CreateGattServer()
.
No 'Start' method within CrossBleAdapter.Current.CreateGattServer()
.
这是我正在使用的代码(我是从表单中调用的)。
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Text;
using Plugin.BluetoothLE;
using Plugin.BluetoothLE.Server;
namespace BluetoothTest.Models
{
public class BluetoothServer
{
public BluetoothServer()
{
}
public void StartAdvertising()
{
//Guid[] guidArray = new Guid[1];
List<Guid> guidArray;
guidArray = new List<Guid>();
guidArray.Add(Guid.NewGuid());
CrossBleAdapter.Current.Advertiser.Start(new AdvertisementData
{
LocalName = "TestServer",
ServiceUuids = guidArray
});
}
public void StopAdvertising()
{
}
public async void SetUpServer()
{
var server = CrossBleAdapter.Current.CreateGattServer();
var service = server.AddService(Guid.NewGuid(), true);
var characteristic = service.AddCharacteristic(
Guid.NewGuid(),
CharacteristicProperties.Read | CharacteristicProperties.Write | CharacteristicProperties.WriteNoResponse,
GattPermissions.Read | GattPermissions.Write
);
var notifyCharacteristic = service.AddCharacteristic
(
Guid.NewGuid(),
CharacteristicProperties.Indicate | CharacteristicProperties.Notify,
GattPermissions.Read | GattPermissions.Write
);
IDisposable notifyBroadcast = null;
notifyCharacteristic.WhenDeviceSubscriptionChanged().Subscribe(e =>
{
var @event = e.IsSubscribed ? "Subscribed" : "Unsubcribed";
if (notifyBroadcast == null)
{
this.notifyBroadcast = Observable
.Interval(TimeSpan.FromSeconds(1))
.Where(x => notifyCharacteristic.SubscribedDevices.Count > 0)
.Subscribe(_ =>
{
Debug.WriteLine("Sending Broadcast");
var dt = DateTime.Now.ToString("g");
var bytes = Encoding.UTF8.GetBytes(dt);
notifyCharacteristic.Broadcast(bytes);
});
}
});
characteristic.WhenReadReceived().Subscribe(x =>
{
var write = "HELLO";
// you must set a reply value
x.Value = Encoding.UTF8.GetBytes(write);
x.Status = GattStatus.Success; // you can optionally set a status, but it defaults to Success
});
characteristic.WhenWriteReceived().Subscribe(x =>
{
var write = Encoding.UTF8.GetString(x.Value, 0, x.Value.Length);
// do something value
});
await server.Start(new AdvertisementData
{
LocalName = "TestServer"
});
}
}
}
确保您在 info.plist
中设置了正确的密钥。有关详细信息,请参阅 this link。
尝试创建 Gatt 服务器时,底层 CBPeripheralManager
仍处于未知状态存在问题。要解决此问题,您必须绕过 CrossBleAdapter
并自行处理 top-level 对象的创建。 API 与给出的示例相比也有一些细微的变化,这使得它无法直接开始工作。
代码
可在此处找到完整的工作示例:https://github.com/jameswestgate/BleRedux
定义一个可以在每个平台上实现的接口:
public interface IBleServer
{
void Initialise();
event EventHandler<Plugin.BluetoothLE.AdapterStatus> StatusChanged;
IGattService CreateService(Guid uuid, bool primary);
void AddService(IGattService service);
void StartAdvertiser(AdvertisementData advertisingData);
void StopAdvertiser();
}
实现接口,创建您自己的 CBPeripheralManager
并公开
基础 StatusChanged
事件。在 iOS,您还需要创建一个广告商。
public class BleServer: IBleServer
{
private CBPeripheralManager _manager;
private GattServer _server;
private Advertiser _advertiser;
public event EventHandler<Plugin.BluetoothLE.AdapterStatus> StatusChanged;
public void Initialise()
{
_manager = new CBPeripheralManager();
_manager.StateUpdated += (object sender, EventArgs e) =>
{
var result = Plugin.BluetoothLE.AdapterStatus.Unknown;
Enum.TryParse(_manager.State.ToString(), true, out result);
StatusChanged?.Invoke(this, result);
};
}
public IGattService CreateService(Guid uuid, bool primary)
{
if (_server == null) _server = new GattServer(_manager);
return new GattService(_manager, _server, uuid, primary);
}
public void AddService(IGattService service)
{
_server.AddService(service);
}
public void StartAdvertiser(Plugin.BluetoothLE.Server.AdvertisementData advertisingData)
{
//advertisingData.ManufacturerData = new ManufacturerData();
if (_advertiser != null) StopAdvertiser();
_advertiser = new Advertiser(_manager);
_advertiser.Start(advertisingData);
}
public void StopAdvertiser()
{
if (_advertiser == null) return;
_advertiser.Stop();
}
}
从您的共享项目中,创建 class 的实例,并根据原始示例添加您的服务和特征:
public partial class MainPage : ContentPage
{
IBleServer _server;
IDisposable notifyBroadcast = null;
Plugin.BluetoothLE.Server.IGattService _service;
public MainPage()
{
InitializeComponent();
}
void Button_Clicked(System.Object sender, System.EventArgs e)
{
if (_server == null)
{
Console.WriteLine("CREATING SERVER");
_server = DependencyService.Get<IBleServer>();
_server.Initialise();
_server.StatusChanged += Peripheral_StatusChanged;
}
}
private void Peripheral_StatusChanged(object sender, AdapterStatus status)
{
try
{
Console.WriteLine($"GOT STATUS CHANGED: {status}");
if (status != AdapterStatus.PoweredOn) return;
if (_service != null) return;
Console.WriteLine($"CREATING SERVICE");
_service = _server.CreateService(new Guid(BluetoothConstants.kFidoServiceUUID), true);
Console.WriteLine($"ADDING CHARACTERISTICS");
var characteristic = _service.AddCharacteristic(
Guid.NewGuid(),
CharacteristicProperties.Read | CharacteristicProperties.Write | CharacteristicProperties.WriteNoResponse,
GattPermissions.Read | GattPermissions.Write
);
var notifyCharacteristic = _service.AddCharacteristic
(
Guid.NewGuid(),
CharacteristicProperties.Indicate | CharacteristicProperties.Notify,
GattPermissions.Read | GattPermissions.Write
);
Console.WriteLine($"SUBSCRIBING TO DEVICE SUBS");
notifyCharacteristic.WhenDeviceSubscriptionChanged().Subscribe(e =>
{
var @event = e.IsSubscribed ? "Subscribed" : "Unsubcribed";
if (notifyBroadcast == null)
{
this.notifyBroadcast = Observable
.Interval(TimeSpan.FromSeconds(1))
.Where(x => notifyCharacteristic.SubscribedDevices.Count > 0)
.Subscribe(_ =>
{
Console.WriteLine("Sending Broadcast");
var dt = DateTime.Now.ToString("g");
var bytes = Encoding.UTF8.GetBytes(dt);
notifyCharacteristic.Broadcast(bytes);
});
}
});
Console.WriteLine($"SUBSCRIBING TO READ");
characteristic.WhenReadReceived().Subscribe(x =>
{
Console.WriteLine($"READ RECEIVED");
var write = "HELLO";
// you must set a reply value
x.Value = Encoding.UTF8.GetBytes(write);
x.Status = GattStatus.Success; // you can optionally set a status, but it defaults to Success
});
Console.WriteLine($"SUBSCRIBING TO WRITE");
characteristic.WhenWriteReceived().Subscribe(x =>
{
var write = Encoding.UTF8.GetString(x.Value, 0, x.Value.Length);
// do something value
Console.WriteLine($"WRITE RECEIVED: {write}");
});
//Also start advertiser (on ios)
var advertisingData = new AdvertisementData
{
LocalName = "FIDO Test Server",
ServiceUuids = new List<Guid> { new Guid(BluetoothConstants.kFidoServiceUUID) } //new Guid(DeviceInformationService),
};
//Now add the service
Console.WriteLine($"ADDING SERVICE");
_server.AddService(_service);
Console.WriteLine($"STARTING ADVERTISER");
_server.StartAdvertiser(advertisingData);
}
catch (Exception ex)
{
Console.WriteLine($"EXCEPTION: {ex}");
}
}
}
使用 nFR Connect 等工具,您现在应该能够连接到服务器并查询特征。写入时可能需要将数据编码为utf-8(见图)
我正在尝试通过蓝牙在两部手机(例如两部 iPhone,甚至跨平台)之间发送数据。
我一直在尝试使用 NuGet 中的 Plugin.BluetoothLE,它最近似乎已更新(2020 年 3 月),但我似乎无法使用任何示例代码(详情如下) .
如果有人能指出下面的错误,我将不胜感激,and/or如果有更好的方法可以通过蓝牙在两部手机之间发送数据。我的应用程序是依赖时间的,可能没有wifi网络,所以蓝牙似乎是最好的选择...
当我实现 https://github.com/aritchie/bluetoothle 上可用的演示服务器代码时,出现以下错误:
No 'AddService' method within
CrossBleAdapter.Current.CreateGattServer()
.
No 'Start' method within
CrossBleAdapter.Current.CreateGattServer()
.
这是我正在使用的代码(我是从表单中调用的)。
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Text;
using Plugin.BluetoothLE;
using Plugin.BluetoothLE.Server;
namespace BluetoothTest.Models
{
public class BluetoothServer
{
public BluetoothServer()
{
}
public void StartAdvertising()
{
//Guid[] guidArray = new Guid[1];
List<Guid> guidArray;
guidArray = new List<Guid>();
guidArray.Add(Guid.NewGuid());
CrossBleAdapter.Current.Advertiser.Start(new AdvertisementData
{
LocalName = "TestServer",
ServiceUuids = guidArray
});
}
public void StopAdvertising()
{
}
public async void SetUpServer()
{
var server = CrossBleAdapter.Current.CreateGattServer();
var service = server.AddService(Guid.NewGuid(), true);
var characteristic = service.AddCharacteristic(
Guid.NewGuid(),
CharacteristicProperties.Read | CharacteristicProperties.Write | CharacteristicProperties.WriteNoResponse,
GattPermissions.Read | GattPermissions.Write
);
var notifyCharacteristic = service.AddCharacteristic
(
Guid.NewGuid(),
CharacteristicProperties.Indicate | CharacteristicProperties.Notify,
GattPermissions.Read | GattPermissions.Write
);
IDisposable notifyBroadcast = null;
notifyCharacteristic.WhenDeviceSubscriptionChanged().Subscribe(e =>
{
var @event = e.IsSubscribed ? "Subscribed" : "Unsubcribed";
if (notifyBroadcast == null)
{
this.notifyBroadcast = Observable
.Interval(TimeSpan.FromSeconds(1))
.Where(x => notifyCharacteristic.SubscribedDevices.Count > 0)
.Subscribe(_ =>
{
Debug.WriteLine("Sending Broadcast");
var dt = DateTime.Now.ToString("g");
var bytes = Encoding.UTF8.GetBytes(dt);
notifyCharacteristic.Broadcast(bytes);
});
}
});
characteristic.WhenReadReceived().Subscribe(x =>
{
var write = "HELLO";
// you must set a reply value
x.Value = Encoding.UTF8.GetBytes(write);
x.Status = GattStatus.Success; // you can optionally set a status, but it defaults to Success
});
characteristic.WhenWriteReceived().Subscribe(x =>
{
var write = Encoding.UTF8.GetString(x.Value, 0, x.Value.Length);
// do something value
});
await server.Start(new AdvertisementData
{
LocalName = "TestServer"
});
}
}
}
确保您在 info.plist
中设置了正确的密钥。有关详细信息,请参阅 this link。
尝试创建 Gatt 服务器时,底层 CBPeripheralManager
仍处于未知状态存在问题。要解决此问题,您必须绕过 CrossBleAdapter
并自行处理 top-level 对象的创建。 API 与给出的示例相比也有一些细微的变化,这使得它无法直接开始工作。
代码
可在此处找到完整的工作示例:https://github.com/jameswestgate/BleRedux
定义一个可以在每个平台上实现的接口:
public interface IBleServer
{
void Initialise();
event EventHandler<Plugin.BluetoothLE.AdapterStatus> StatusChanged;
IGattService CreateService(Guid uuid, bool primary);
void AddService(IGattService service);
void StartAdvertiser(AdvertisementData advertisingData);
void StopAdvertiser();
}
实现接口,创建您自己的 CBPeripheralManager
并公开
基础 StatusChanged
事件。在 iOS,您还需要创建一个广告商。
public class BleServer: IBleServer
{
private CBPeripheralManager _manager;
private GattServer _server;
private Advertiser _advertiser;
public event EventHandler<Plugin.BluetoothLE.AdapterStatus> StatusChanged;
public void Initialise()
{
_manager = new CBPeripheralManager();
_manager.StateUpdated += (object sender, EventArgs e) =>
{
var result = Plugin.BluetoothLE.AdapterStatus.Unknown;
Enum.TryParse(_manager.State.ToString(), true, out result);
StatusChanged?.Invoke(this, result);
};
}
public IGattService CreateService(Guid uuid, bool primary)
{
if (_server == null) _server = new GattServer(_manager);
return new GattService(_manager, _server, uuid, primary);
}
public void AddService(IGattService service)
{
_server.AddService(service);
}
public void StartAdvertiser(Plugin.BluetoothLE.Server.AdvertisementData advertisingData)
{
//advertisingData.ManufacturerData = new ManufacturerData();
if (_advertiser != null) StopAdvertiser();
_advertiser = new Advertiser(_manager);
_advertiser.Start(advertisingData);
}
public void StopAdvertiser()
{
if (_advertiser == null) return;
_advertiser.Stop();
}
}
从您的共享项目中,创建 class 的实例,并根据原始示例添加您的服务和特征:
public partial class MainPage : ContentPage
{
IBleServer _server;
IDisposable notifyBroadcast = null;
Plugin.BluetoothLE.Server.IGattService _service;
public MainPage()
{
InitializeComponent();
}
void Button_Clicked(System.Object sender, System.EventArgs e)
{
if (_server == null)
{
Console.WriteLine("CREATING SERVER");
_server = DependencyService.Get<IBleServer>();
_server.Initialise();
_server.StatusChanged += Peripheral_StatusChanged;
}
}
private void Peripheral_StatusChanged(object sender, AdapterStatus status)
{
try
{
Console.WriteLine($"GOT STATUS CHANGED: {status}");
if (status != AdapterStatus.PoweredOn) return;
if (_service != null) return;
Console.WriteLine($"CREATING SERVICE");
_service = _server.CreateService(new Guid(BluetoothConstants.kFidoServiceUUID), true);
Console.WriteLine($"ADDING CHARACTERISTICS");
var characteristic = _service.AddCharacteristic(
Guid.NewGuid(),
CharacteristicProperties.Read | CharacteristicProperties.Write | CharacteristicProperties.WriteNoResponse,
GattPermissions.Read | GattPermissions.Write
);
var notifyCharacteristic = _service.AddCharacteristic
(
Guid.NewGuid(),
CharacteristicProperties.Indicate | CharacteristicProperties.Notify,
GattPermissions.Read | GattPermissions.Write
);
Console.WriteLine($"SUBSCRIBING TO DEVICE SUBS");
notifyCharacteristic.WhenDeviceSubscriptionChanged().Subscribe(e =>
{
var @event = e.IsSubscribed ? "Subscribed" : "Unsubcribed";
if (notifyBroadcast == null)
{
this.notifyBroadcast = Observable
.Interval(TimeSpan.FromSeconds(1))
.Where(x => notifyCharacteristic.SubscribedDevices.Count > 0)
.Subscribe(_ =>
{
Console.WriteLine("Sending Broadcast");
var dt = DateTime.Now.ToString("g");
var bytes = Encoding.UTF8.GetBytes(dt);
notifyCharacteristic.Broadcast(bytes);
});
}
});
Console.WriteLine($"SUBSCRIBING TO READ");
characteristic.WhenReadReceived().Subscribe(x =>
{
Console.WriteLine($"READ RECEIVED");
var write = "HELLO";
// you must set a reply value
x.Value = Encoding.UTF8.GetBytes(write);
x.Status = GattStatus.Success; // you can optionally set a status, but it defaults to Success
});
Console.WriteLine($"SUBSCRIBING TO WRITE");
characteristic.WhenWriteReceived().Subscribe(x =>
{
var write = Encoding.UTF8.GetString(x.Value, 0, x.Value.Length);
// do something value
Console.WriteLine($"WRITE RECEIVED: {write}");
});
//Also start advertiser (on ios)
var advertisingData = new AdvertisementData
{
LocalName = "FIDO Test Server",
ServiceUuids = new List<Guid> { new Guid(BluetoothConstants.kFidoServiceUUID) } //new Guid(DeviceInformationService),
};
//Now add the service
Console.WriteLine($"ADDING SERVICE");
_server.AddService(_service);
Console.WriteLine($"STARTING ADVERTISER");
_server.StartAdvertiser(advertisingData);
}
catch (Exception ex)
{
Console.WriteLine($"EXCEPTION: {ex}");
}
}
}
使用 nFR Connect 等工具,您现在应该能够连接到服务器并查询特征。写入时可能需要将数据编码为utf-8(见图)