zoukankan      html  css  js  c++  java
  • Xamarin.Form 蓝牙ble

      本文介绍Xamarin.Form的蓝牙使用方法,开始之前说说题外话,就Xamarin.Form来说,在国内是没多少人在弄的,但对于我自己来说,是吃了这碗饭,也希望在这行做的人越来越多,越来越好,本人2016年开始入使用Xamarin.Form开发App,那时候刚微软刚收购Xamarin,也正式开源免费给开发者使用,但那时候的本说实话是有多不完善的,直到现在微软依然有很多不完善的功能,所以在国内学这个,一般是由公司高层推这个技术,直接至底向上的非常少。微软的东西在国内环境来说,多不太好,很多大的互联网公司都比较少用,但是我要强调的是,Xamarin.Form本身其实并不太适合做界面变化太多,变化太大的东西,如果你的项目需要优秀的界面,炫酷的特效,那原生是比较好的选择,而这个特性是互联网公司的特性,所以互联网公司不太适合使用Xamarin.Form。Xamarin适合界面少,但是业务比较复杂的项目,如IOT项目。也比较适合传统企业而不是互联网公司。所以在前面一篇文章中,我介绍了MQTT协议,现在介绍底功耗蓝牙协议。

      这里使用ble.net库,直接使用nuget查找相应的包就可以了,ble.net库是一个混合平台的低功耗蓝牙库,可用于开发Android、iOS、UWP平台的BLE客户端。支持的平台和版本如下

    Platform Version
    Xamarin.iOS iOS 8.3+
    Xamarin.Android API 18+
    Windows 10(UWP) 1709+

      在引用包的时候注意:在Xamarin.Form层引用ble.net包,在xamarin.Android层引用ble.net 和ble.net-android包,在Xamarin.Form层引用ble.net和ble.net-ios包。

      Android 平台

      添加权限,在Android 6.0或更高版本中需要获取危险的位置权限,所以在AndroidManifesst.xml文件中添加

    1 <uses-permission android:name="android.permission.BLUETOOTH" />
    2     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    3     <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
    4   <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    5   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    6   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

      初始化BluetoothLowEnergyAdapter(只有Android平台需要,iOS和UWP平台不需要)。如果你想让IBluetoothLowEnergyAdapter.DisableAdapter() 和 IBluetoothLowEnergyAdapter.EnableAdapter()起作用,你需要在你的Main Activity中添加:

    protected override void OnCreate( Bundle bundle )
    {
       // ...
       BluetoothLowEnergyAdapter.Init( this );
       // ...
    }

      如果你要IBluetoothLowEnergyAdapter.CurrentState.Subscribe()方法起作用,你还需要在Activity中添加:

    protected sealed override void OnActivityResult( Int32 requestCode, Result resultCode, Intent data )
    {
       BluetoothLowEnergyAdapter.OnActivityResult( requestCode, resultCode, data );
    }

      iOS 平台

      必须添加使用蓝牙的提示,并且苹果公司上架App会审核,需正确填写Info.plist文件

    1 <key>UIBackgroundModes</key>
    2 <array>
    3    <string>bluetooth-central</string>
    4 </array>
    5 <key>NSBluetoothPeripheralUsageDescription</key>
    6 <string>[MyAppNameHere] would like to use bluetooth.</string>

      所有平台都需要初始化一个

    IBluetoothLowEnergyAdapter ble =
    BluetoothLowEnergyAdapter.ObtainDefaultAdapter()

    同时传到Xamarin.Form层。

      App内开启蓝牙:使用如下方法检查和启用手机蓝牙适配器

    if(ble.AdapterCanBeEnabled && ble.CurrentState.IsDisabledOrDisabling()) {
       await ble.EnableAdapter();
    }

      开始扫描附近的蓝牙设备,可以扫描到各种设备,注意:超时时间不宜设置过长,通过测试,蓝牙设备不能一直扫描,需停一会在扫描一会这样使用。扫描能扫描出附近的蓝牙设备和特性。

    var cts = new CancellationTokenSource(TimeSpan.FromSeconds( 30 ));
    await ble.ScanForBroadcasts(
       // providing ScanSettings is optional
       new ScanSettings()
       {
          // Setting the scan mode is currently only applicable to Android and has no effect on other platforms.
          // If not provided, defaults to ScanMode.Balanced
          Mode = ScanMode.LowPower,
    
          // Optional scan filter to ensure that the observer will only receive peripherals
          // that pass the filter. If you want to scan for everything around, omit the filter.
          Filter = new ScanFilter()
          {
             AdvertisedDeviceName = "foobar",
             AdvertisedManufacturerCompanyId = 76,
             // peripherals must advertise at-least-one of any GUIDs in this list
             AdvertisedServiceIsInList = new List<Guid>(){ someGuid },
          },
    
          // ignore repeated advertisements from the same device during this scan
          IgnoreRepeatBroadcasts = false
       },
       // Your IObserver<IBlePeripheral> or Action<IBlePeripheral> will be triggered for each discovered
       // peripheral based on the provided scan settings and filter (if any).
       ( IBlePeripheral peripheral ) =>
       {
          // read the advertising data
          var adv = peripheral.Advertisement;
          Debug.WriteLine( adv.DeviceName );
          Debug.WriteLine( adv.Services.Select( x => x.ToString() ).Join( "," ) );
          Debug.WriteLine( adv.ManufacturerSpecificData.FirstOrDefault().CompanyName() );
          Debug.WriteLine( adv.ServiceData );
    
          // if we found what we needed, stop the scan manually
          cts.Cancel();
    
          // perhaps connect to the device (see next example)...
       },
       // Provide a CancellationToken to stop the scan, or use the overload that takes a TimeSpan.
       // If you omit this argument, the scan will timeout after BluetoothLowEnergyUtils.DefaultScanTimeout
       cts.Token
    );
    
    // scanning has stopped when code reached this point since the scan was awaited

      如果你要连接蓝牙设备,采用如下方法:

    var connection = await ble.ConnectToDevice(
       // The IBlePeripheral to connect to
       peripheral,
       // TimeSpan or CancellationToken to stop the
       // connection attempt.
       // If you omit this argument, it will use
       // BluetoothLowEnergyUtils.DefaultConnectionTimeout
       TimeSpan.FromSeconds( 15 ),
       // Optional IProgress<ConnectionProgress>
       progress => Debug.WriteLine(progress)
    );
    
    if(connection.IsSuccessful())
    {
       var gattServer = connection.GattServer;
       // ... do things with gattServer here... (see later examples...)
    }
    else
    {
       // Do something to inform user or otherwise handle unsuccessful connection.
       Debug.WriteLine( "Error connecting to device. result={0:g}", connection.ConnectionResult );
       // e.g., "Error connecting to device. result=ConnectionAttemptCancelled"
    }

      断开蓝牙方法:

    await gattServer.Disconnect();

      下列方法用来连接指定的蓝牙设备:

    var connection = await ble.FindAndConnectToDevice(
       new ScanFilter()
          .SetAdvertisedDeviceName( "foo" )
          .SetAdvertisedManufacturerCompanyId( 0xffff )
          .AddAdvertisedService( guid ),
       TimeSpan.FromSeconds( 30 ) );
    if(connection.IsSuccessful())
    {
       // ...
    }

      调用蓝牙的读特性

    try
    {
       var value = await gattServer.ReadCharacteristicValue( someServiceGuid, someCharacteristicGuid );
    }
    catch(GattException ex)
    {
       Debug.WriteLine( ex.ToString() );
    }

      监听通知特性

    IDisposable notifyHandler;
    
    try
    {
       // Will also stop listening when gattServer
       // is disconnected, so if that is acceptable,
       // you don't need to store this disposable.
       notifyHandler = gattServer.NotifyCharacteristicValue(
          someServiceGuid,
          someCharacteristicGuid,
          // IObserver<Tuple<Guid, Byte[]>> or IObserver<Byte[]> or
          // Action<Tuple<Guid, Byte[]>> or Action<Byte[]>
          bytes => {/* do something with notification bytes */} );
    }
    catch(GattException ex)
    {
       Debug.WriteLine( ex.ToString() );
    }
    
    // ... later, once done listening for notifications ...
    notifyHandler.Dispose();

      调用写特性,注意:在写的时候不能一直不停的调用这个方法,不然会发送不了,需要停顿500毫秒左右在发送第二个包。这点非常重要。

    try
    {
       // The resulting value of the characteristic is returned. In nearly all cases this
       // will be the same value that was provided to the write call (e.g. `byte[]{ 1, 2, 3 }`)
       var value = await gattServer.WriteCharacteristicValue(
          someServiceGuid,
          someCharacteristicGuid,
          new byte[]{ 1, 2, 3 } );
    }
    catch(GattException ex)
    {
       Debug.WriteLine( ex.ToString() );
    }

      蓝牙有很多应用,需要自己多尝试,对于蓝牙的升级DFU功能,需要的可以找我。

  • 相关阅读:
    使用 Redis 实现分布式系统轻量级协调技术
    高并发系统中的常见问题
    ASP.NET跨平台
    消息队列RabbitMQ
    Redis数据结构
    自定义的配置文件实现动态注入
    redis基础的字符串类型
    持久化redis
    redis
    MS Open Tech 技术团队构建可靠的Windows版Redis
  • 原文地址:https://www.cnblogs.com/zuimengaitianya/p/12153093.html
Copyright © 2011-2022 走看看