Отправка данных между двумя телефонами по bluetooth (я пытаюсь использовать плагин aritchie. BluetoothLE)

Я пытаюсь отправить данные между двумя телефонами (например, двумя iPhone или даже кросс-платформенным) через Bluetooth.

Я пытался использовать Plugin.BluetoothLE от NuGet, который, похоже, был обновлен недавно (март 2020 г.), однако я не могу заставить работать какой-либо из примеров кода (подробности ниже).

Я был бы признателен, если бы кто-нибудь мог указать, что не так, ниже, и / или есть ли лучший способ передачи данных между двумя телефонами через Bluetooth. Мое приложение зависит от времени, и может не быть сети Wi-Fi, поэтому bluetooth кажется лучшим вариантом...

Когда я реализую код демонстрационного сервера, доступный на https://github.com/aritchie/bluetoothle, я получаю следующие ошибки:

Нет метода AddService внутри CrossBleAdapter.Current.CreateGattServer().

Нет метода "Старт" внутри 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"
            });
        }
    }
}

1 ответ

Решение

Убедитесь, что вы установили правильный ключ в info.plist. См. Эту ссылку для получения более подробной информации.

Проблема в том, что основная CBPeripheralManagerвсе еще находится в неизвестном состоянии при попытке создать сервер Gatt. Чтобы обойти это, вы должны обойти CrossBleAdapterи самостоятельно обрабатывать создание объектов верхнего уровня. Есть также некоторые тонкие изменения в 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();
    }
} 

Из вашего общего проекта создайте экземпляр класса и добавьте свои сервисы и характеристики в соответствии с исходным примером:

       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 (см. Изображение)

Другие вопросы по тегам