基于Inthehand开源库开发
搜了一下网上的代码,基本上都是采用同步方式,即蓝牙固定扫描一段时间,然后返回这段时间内扫描到的所有蓝牙设备;缺点是耗时太长;下边给出另一种解决方法,采用了事件方式,每发现一个设备,就触发一次事件,实测耗时大大缩短;
准备工作
在nuget中搜索,32feet,我使用的是3.5版本
代码如下
Test.cs
using InTheHand.Net.Bluetooth;
using InTheHand.Net.Sockets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Test.Ble
{
class BleDiscover
{
bool findBleDevice = false;
string tagDeviceAddress = null;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="x">需要搜索的蓝牙mac地址</param>
public BleDiscover(string x)
{
tagDeviceAddress = x;
BluetoothClient bluetoothClient = new BluetoothClient();
//bluetoothClient.DiscoverDevices();
BluetoothRadio bluetoothRadio = BluetoothRadio.PrimaryRadio;
bluetoothRadio.Mode = RadioMode.Connectable;
BluetoothComponent bluetoothComponent = new BluetoothComponent(bluetoothClient);
bluetoothComponent.DiscoverDevicesAsync(10, false, false, false, true, bluetoothComponent);
bluetoothComponent.DiscoverDevicesProgress += BluetoothComponent_DiscoverDevicesProgress;
Thread findBleDeviceThread = new Thread(findBleDeviceThreadFun);
findBleDeviceThread.Start();
}
private void findBleDeviceThreadFun()
{
//throw new NotImplementedException();
while (true)
{
if (findDeviceEventArgsHandler != null)
{
FindDeviceEventArgs findDeviceEventArgs = new FindDeviceEventArgs();
findDeviceEventArgs.isFinded = findBleDevice;
findDeviceEventArgsHandler(this, findDeviceEventArgs);
}
Thread.Sleep(500);
}
}
private void BluetoothComponent_DiscoverDevicesProgress(object sender, DiscoverDevicesEventArgs e)
{
//throw new NotImplementedException();
if (e.Devices[0].DeviceAddress.ToString() == tagDeviceAddress && findBleDevice == false)
{
//MessageBox.Show("Find my MI9");
findBleDevice = true;
}
}
/// <summary>
/// 声明事件
/// </summary>
public event FindDeviceEventArgsHandler findDeviceEventArgsHandler;
}
#region 找到设备事件
/// <summary>
/// 1、声明参数类型
/// </summary>
public class FindDeviceEventArgs : EventArgs
{
public bool isFinded;
}
/// <summary>
/// 2、声明委托类型
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public delegate void FindDeviceEventArgsHandler(object sender, FindDeviceEventArgs e);
//事件源头是 BleDiscover 这个class
#endregion
}
MainWindows.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using InTheHand.Net.Bluetooth;
using InTheHand.Net.Sockets;
namespace WpfAppForBlueTooth
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
string macAddress = "B4C9B92ccxxx";
public MainWindow()
{
InitializeComponent();
#region 方法1
BluetoothClient bluetoothClient = new BluetoothClient();
BluetoothRadio bluetoothRadio = BluetoothRadio.PrimaryRadio;
bluetoothRadio.Mode = RadioMode.Connectable;
Test.Ble.BleDiscover bleDiscover = new Test.Ble.BleDiscover(macAddress);
bleDiscover.findDeviceEventArgsHandler += BleDiscover_findDeviceEventArgsHandler;
#endregion
//#region 方法2
//BluetoothClient bluetoothClient = new BluetoothClient();
//BluetoothRadio bluetoothRadio = BluetoothRadio.PrimaryRadio;
//bluetoothRadio.Mode = RadioMode.Connectable;
//while (true)
//{
// BluetoothDeviceInfo[] bluetoothDeviceInfos = bluetoothClient.DiscoverDevices(); //固定10s
// Thread.Sleep(1000);
//}
//#endregion
}
private void BleDiscover_findDeviceEventArgsHandler(object sender, Test.Ble.FindDeviceEventArgs e)
{
//throw new C();
MessageBox.Show(e.isFinded.ToString());
}
}
}
一个挺大的问题,就是Inthehand这个库不支持BLE,实际上这个开源库也只是将windows的api封装了一下,而win8之前,windows并不支持BLE,所以…
如果需要BLE的话,一种方法是使用WIN10的API,用UWP开发,可以获得最好的支持;可参考GitHub的开源项目Windows-universal-samples
测试程序
基本是使用了GitHub上的代码,通过断点调试可以发现能够找到BLE的蓝牙设备;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Devices.Bluetooth;
using System.ServiceModel.Channels;
using Windows.UI.Popups;
using Windows.ApplicationModel;
using Windows.Devices.Bluetooth.Advertisement;
using System.Collections.ObjectModel;
using Windows.Devices.Enumeration;
using Windows.UI.Core;
using System.Diagnostics;
// https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x804 上介绍了“空白页”项模板
namespace UwpForBle
{
/// <summary>
/// 可用于自身或导航至 Frame 内部的空白页。
/// </summary>
public sealed partial class MainPage : Page
{
private DeviceWatcher deviceWatcher;
private List<DeviceInformation> devices = new List<DeviceInformation>();
public MainPage()
{
InitializeComponent();
}
private async void onButtonClick(object sender, RoutedEventArgs e)
{
var dialog = new MessageDialog("当前设置尚未保存,你确认要退出该页面吗?", "消息提示");
dialog.Commands.Add(new UICommand("确定", cmd => { }, commandId: 0));
dialog.Commands.Add(new UICommand("取消", cmd => { }, commandId: 1));
//设置默认按钮,不设置的话默认的确认按钮是第一个按钮
dialog.DefaultCommandIndex = 0;
dialog.CancelCommandIndex = 1;
//获取返回值
var result = await dialog.ShowAsync();
}
#region Device discovery
/// <summary>
/// Starts a device watcher that looks for all nearby Bluetooth devices (paired or unpaired).
/// Attaches event handlers to populate the device collection.
/// </summary>
private void StartBleDeviceWatcher()
{
// Additional properties we would like about the device.
// Property strings are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/ff521659(v=vs.85).aspx
string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected", "System.Devices.Aep.Bluetooth.Le.IsConnectable" };
// BT_Code: Example showing paired and non-paired in a single query.
string aqsAllBluetoothLEDevices = "(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")";
deviceWatcher =
DeviceInformation.CreateWatcher(
aqsAllBluetoothLEDevices,
requestedProperties,
DeviceInformationKind.AssociationEndpoint);
// Register event handlers before starting the watcher.
deviceWatcher.Added += DeviceWatcher_Added;
//deviceWatcher.Updated += DeviceWatcher_Updated;
//deviceWatcher.Removed += DeviceWatcher_Removed;
//deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
//deviceWatcher.Stopped += DeviceWatcher_Stopped;
// Start over with an empty collection.
devices.Clear();
// Start the watcher. Active enumeration is limited to approximately 30 seconds.
// This limits power usage and reduces interference with other Bluetooth activities.
// To monitor for the presence of Bluetooth LE devices for an extended period,
// use the BluetoothLEAdvertisementWatcher runtime class. See the BluetoothAdvertisement
// sample for an example.
deviceWatcher.Start();
}
/// <summary>
/// Stops watching for all nearby Bluetooth devices.
/// </summary>
private void StopBleDeviceWatcher()
{
if (deviceWatcher != null)
{
// Unregister the event handlers.
deviceWatcher.Added -= DeviceWatcher_Added;
//deviceWatcher.Updated -= DeviceWatcher_Updated;
//deviceWatcher.Removed -= DeviceWatcher_Removed;
//deviceWatcher.EnumerationCompleted -= DeviceWatcher_EnumerationCompleted;
//deviceWatcher.Stopped -= DeviceWatcher_Stopped;
// Stop the watcher.
deviceWatcher.Stop();
deviceWatcher = null;
}
}
private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation deviceInfo)
{
// We must update the collection on the UI thread because the collection is databound to a UI element.
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
lock (this)
{
Debug.WriteLine(String.Format("Added {0}{1}", deviceInfo.Id, deviceInfo.Name));
// Protect against race condition if the task runs after the app stopped the deviceWatcher.
if (sender == deviceWatcher)
{
// Make sure device isn't already present in the list.
if (deviceInfo.Id == null)
{
if (deviceInfo.Name != string.Empty)
{
// If device has a friendly name display it immediately.
devices.Add(deviceInfo);
}
else
{
// Add it to a list in case the name gets updated later.
devices.Add(deviceInfo);
}
}
}
}
});
}
#endregion
private void EnumerateButton_Click(object sender, RoutedEventArgs e)
{
if (deviceWatcher == null)
{
StartBleDeviceWatcher();
EnumerateButton.Content = "Stop enumerating";
}
else
{
StopBleDeviceWatcher();
EnumerateButton.Content = "Start enumerating";
}
}
}
}