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功能,需要的可以找我。

  鑒於有很多人求藍牙源碼,現采用了Plugin.BLE的包重新寫了一個版本,本文章版本用的藍牙包已不在維護和更新,請遷移到Plugin.BLE包,GitHub地址:https://github.com/zuimengaitianya/BleCat.git。本GitHub代碼包括藍牙掃描和連接,還有Nordic芯片的12.3版本的DFU功能,需要的可以借鑒,本人可提供有償技術支持,后續將在出一篇文章講解藍牙的DFU和遇到的各種問題。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM