打开VS->工具->NuGet包管理器->程序包管理器设置->常规->默认包管理格式(设置为PackageRefrence)
解决方案里引用处,右键选择管理NuGet程序包,浏览->搜索 Microsoft.Windows.SDK.Contracts并安装。需要几分钟时间。
代码实现基本大同小异,主要是UWP API的引入方式。
重点说明: 这一步中,很多博主的采用的方式如下:
1.修改工程文件.csproj, 在文件中增加
<TargetPlatformVersion>10.0</TargetPlatformVersion>
2.引用 Windows.Devices、Windows.Foundation、Windows.Security、Windows.Services、Windows.Storage等组件进行环境搭建的。
本人在Windows11+Vs2022环境中实测,编译时无法通过,会出现无法引用System.Runtime.dll组件、IDisposable 没有实现等错误。采用Nuget方式引用,解决上述问题。也遇到上述问题的码友可以参考本文的方式。
using System;
using System.Collections.Generic;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Foundation;
using Windows.Security.Cryptography;
namespace BleSolution
{
public class BleCore:IDisposable
{
private bool asyncLock = false;
/// <summary>
/// 搜索蓝牙设备对象
/// </summary>
private BluetoothLEAdvertisementWatcher deviceWatcher;
/// <summary>
/// 当前连接的服务
/// </summary>
public GattDeviceService CurrentService { get; set; }
/// <summary>
/// 当前连接的蓝牙设备
/// </summary>
public BluetoothLEDevice CurrentDevice { get; set; }
/// <summary>
/// 写特征对象
/// </summary>
public GattCharacteristic CurrentWriteCharacteristic { get; set; }
/// <summary>
/// 通知特征对象
/// </summary>
public GattCharacteristic CurrentNotifyCharacteristic { get; set; }
/// <summary>
/// 特性通知类型通知启用
/// </summary>
private const GattClientCharacteristicConfigurationDescriptorValue CHARACERISTIC_NOTIFICATION_TYPE = GattClientCharacteristicConfigurationDescriptorValue.Notify;
/// <summary>
/// 存储检测到的设备
/// </summary>
private List<BluetoothLEDevice> DeviceList = new List<BluetoothLEDevice>();
/// <summary>
/// 定义搜索蓝牙设备委托
/// </summary>
/// <param name="type"></param>
/// <param name="bluetoothLEDevice"></param>
public delegate void DeviceWatcherChangeEvent(MsgType type, BluetoothLEDevice bluetoothLEDevice);
/// <summary>
/// 搜索蓝牙事件
/// </summary>
public event DeviceWatcherChangeEvent DeviceWatcherChanged;
/// <summary>
/// 获取服务委托
/// </summary>
/// <param name="gattDeviceService"></param>
public delegate void GattDeviceServiceAddEvent(GattDeviceService gattDeviceService);
/// <summary>
/// 获取服务事件
/// </summary>
public event GattDeviceServiceAddEvent GattDeviceServiceAdded;
/// <summary>
/// 获取特征委托
/// </summary>
/// <param name="characteristic"></param>
public delegate void CharacteristicAddedEvent(GattCharacteristic characteristic);
/// <summary>
/// 获取特征事件
/// </summary>
public event CharacteristicAddedEvent CharacteristicAdded;
/// <summary>
/// 提示信息委托
/// </summary>
/// <param name="type"></param>
/// <param name="message"></param>
/// <param name="data"></param>
public delegate void MessageChangedEvent(MsgType type, string message, byte[] data = null);
/// <summary>
/// 提示信息事件
/// </summary>
public event MessageChangedEvent MessageChanged;
/// <summary>
/// 当前连接的蓝牙MAC
/// </summary>
private string CurrentDeviceMAC { get; set; }
public BleCore()
{
}
/// <summary>
/// 搜索蓝牙设备
/// </summary>
public void StartBleDeviceWatcher()
{
deviceWatcher = new BluetoothLEAdvertisementWatcher();
deviceWatcher.ScanningMode = BluetoothLEScanningMode.Active;
deviceWatcher.SignalStrengthFilter.InRangeThresholdInDBm = -80;
deviceWatcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90;
deviceWatcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
deviceWatcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);
deviceWatcher.Received += DeviceWatcher_Received;
deviceWatcher.Stopped += DeviceWatcher_Stopped;
deviceWatcher.Start();
string msg = "自动发现设备中...";
MessageChanged(MsgType.NotifyTxt, msg);
}
private void DeviceWatcher_Stopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args)
{
}
private void DeviceWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress).Completed = (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
if (asyncInfo.GetResults() != null)
{
BluetoothLEDevice currentDevice = asyncInfo.GetResults();
bool contain = false;
foreach (BluetoothLEDevice device in DeviceList)//过滤重复的设备
{
if (device.DeviceId == currentDevice.DeviceId)
{
contain = true;
}
}
if (!contain)
{
byte[] _Bytes1 = BitConverter.GetBytes(currentDevice.BluetoothAddress);
Array.Reverse(_Bytes1);
DeviceList.Add(currentDevice);
MessageChanged(MsgType.NotifyTxt, "发现设备:" + currentDevice.Name + " address:" + BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower());
DeviceWatcherChanged(MsgType.BleDevice, currentDevice);
}
}
else
{
MessageChanged(MsgType.NotifyTxt, "没有得到结果集");
}
}
};
}
public void StopBleDeviceWathcer()
{
if (deviceWatcher != null)
deviceWatcher.Stop();
}
public void StartMatching(BluetoothLEDevice device)
{
CurrentDevice = device;
}
public void FindService()
{
CurrentDevice.GetGattServicesAsync().Completed = (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
var services = asyncInfo.GetResults().Services;
MessageChanged(MsgType.NotifyTxt, "GattService size = " + services.Count);
foreach (var service in services)
{
this.GattDeviceServiceAdded(service);
FindCharacteristic(service);
}
MessageChanged(MsgType.NotifyTxt, "获取特征码完毕!");
}
};
}
public void FindCharacteristic(GattDeviceService gattDeviceService)
{
CurrentService = gattDeviceService;
CurrentService.GetCharacteristicsAsync().Completed = (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
var services = asyncInfo.GetResults().Characteristics;
foreach (var c in services)
{
CharacteristicAdded?.Invoke(c);
}
}
};
}
public void SetOpertor(GattCharacteristic gattCharacteristic)
{
byte[] _Bytes1 = BitConverter.GetBytes(this.CurrentDevice.BluetoothAddress);
Array.Reverse(_Bytes1);
CurrentDeviceMAC = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();
string msg = "正在连接设备<" + this.CurrentDeviceMAC + ">..";
MessageChanged(MsgType.NotifyTxt, msg);
if (gattCharacteristic.CharacteristicProperties == GattCharacteristicProperties.Write)
{
CurrentWriteCharacteristic = gattCharacteristic;
}
if(gattCharacteristic.CharacteristicProperties == GattCharacteristicProperties.Notify)
{
CurrentNotifyCharacteristic = gattCharacteristic;
}
if((uint)gattCharacteristic.CharacteristicProperties == 26)
{
}
if(gattCharacteristic.CharacteristicProperties == (GattCharacteristicProperties.Notify |
GattCharacteristicProperties.Read | GattCharacteristicProperties.Write))
{
CurrentWriteCharacteristic = gattCharacteristic;
CurrentNotifyCharacteristic = gattCharacteristic;
CurrentNotifyCharacteristic.ProtectionLevel = GattProtectionLevel.Plain;
CurrentNotifyCharacteristic.ValueChanged += Characteristic_ValueChanged;
EnableNotifications(CurrentNotifyCharacteristic);
}
}
private void Matching(string Id)
{
try
{
BluetoothLEDevice.FromIdAsync(Id).Completed = (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
BluetoothLEDevice bleDevice = asyncInfo.GetResults();
DeviceList.Add(bleDevice);
DeviceWatcherChanged(MsgType.BleDevice, bleDevice);
}
if (asyncStatus == AsyncStatus.Started)
{
Console.WriteLine(asyncStatus.ToString());
}
if (asyncStatus == AsyncStatus.Canceled)
{
Console.WriteLine(asyncStatus.ToString());
}
if (asyncStatus == AsyncStatus.Error)
{
Console.WriteLine(asyncStatus.ToString());
}
};
}
catch(Exception e)
{
string msg = "没有发现设备" + e.Message;
MessageChanged(MsgType.NotifyTxt, msg);
StartBleDeviceWatcher();
}
}
public void Dispose()
{
CurrentDeviceMAC = null;
CurrentService?.Dispose();
CurrentDevice?.Dispose();
CurrentDevice = null;
CurrentService = null;
CurrentWriteCharacteristic = null;
CurrentNotifyCharacteristic = null;
MessageChanged(MsgType.NotifyTxt, "主动断开连接");
}
private void CurrentDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args)
{
if(sender.ConnectionStatus == BluetoothConnectionStatus.Disconnected && CurrentDeviceMAC != null)
{
string msg = "设备已断开,自动重连";
MessageChanged(MsgType.NotifyTxt, msg);
if(!asyncLock)
{
asyncLock = true;
CurrentDevice.Dispose();
CurrentDevice = null;
CurrentService = null;
CurrentWriteCharacteristic = null;
CurrentNotifyCharacteristic = null;
SelectDeviceFromIdAsync(CurrentDeviceMAC);
}
}
else
{
string msg = "设备已连接";
MessageChanged(MsgType.NotifyTxt, msg);
}
}
public void SelectDeviceFromIdAsync(string MAC)
{
CurrentDeviceMAC = MAC;
CurrentDevice = null;
BluetoothAdapter.GetDefaultAsync().Completed = (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
BluetoothAdapter adapter = asyncInfo.GetResults();
if (adapter != null)
{
byte[] _Bytes1 = BitConverter.GetBytes(adapter.BluetoothAddress);
Array.Reverse(_Bytes1);
string macAddress = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();
string Id = "BluetoothLE#BluetoothLE" + macAddress + "-" + MAC;
Matching(Id);
}
else
{
string msg = "查找连接蓝牙设备异常!";
MessageChanged(MsgType.NotifyTxt, msg);
}
}
};
}
public void EnableNotifications(GattCharacteristic characteristic)
{
string msg = "收通知对象=" + CurrentDevice.ConnectionStatus;
this.MessageChanged(MsgType.NotifyTxt, msg);
characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(CHARACERISTIC_NOTIFICATION_TYPE).Completed = (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
GattCommunicationStatus status = asyncInfo.GetResults();
if (status == GattCommunicationStatus.Unreachable)
{
msg = "设备不可用";
MessageChanged(MsgType.NotifyTxt, msg);
if (CurrentNotifyCharacteristic != null && !asyncLock)
{
EnableNotifications(CurrentNotifyCharacteristic);
}
}
asyncLock = false;
msg = "设备连接状态" + status;
MessageChanged(MsgType.NotifyTxt, msg);
}
};
}
private void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
CryptographicBuffer.CopyToByteArray(args.CharacteristicValue, out byte[] data);
string str = BitConverter.ToString(data);
MessageChanged(MsgType.BleData, str, data);
}
public void Write(byte[] data)
{
if (CurrentWriteCharacteristic != null)
{
CurrentWriteCharacteristic.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(data), GattWriteOption.WriteWithResponse).Completed = (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
GattCommunicationStatus a = asyncInfo.GetResults();
string str = "发送数据:" + BitConverter.ToString(data) + "State:" + a;
MessageChanged(MsgType.BleData, str, data);
}
};
}
}
}
public enum MsgType
{
BleData,
NotifyTxt,
BleDevice
}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
namespace BleSolution
{
public partial class Form1 : Form
{
BleCore bleCore = new BleCore();
List<BluetoothLEDevice> DeviceList = new List<BluetoothLEDevice>();
List<GattDeviceService> GattDeviceServices = new List<GattDeviceService>();
List<GattCharacteristic> GattCharacteristics = new List<GattCharacteristic>();
public Form1()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;
bleCore.MessageChanged += BleCore_MessageChanged;
bleCore.DeviceWatcherChanged += BleCore_DeviceWatcherChanged;
bleCore.GattDeviceServiceAdded += BleCore_GattDeviceServiceAdded;
bleCore.CharacteristicAdded += BleCore_CharacteristicAdded;
this.Init();
}
private void BleCore_GattDeviceServiceAdded(GattDeviceService gattDeviceService)
{
RunAsync(() =>
{
this.cmbServer.Items.Add(gattDeviceService.Uuid.ToString());
this.GattDeviceServices.Add(gattDeviceService);
this.btnFeatures.Enabled = true;
});
}
public static void RunAsync(Action action)
{
((Action)delegate ()
{
action.Invoke();
}).BeginInvoke(null, null);
}
private void Init()
{
//throw new NotImplementedException();
}
private void BleCore_CharacteristicAdded(GattCharacteristic characteristic)
{
RunAsync(() =>
{
this.cmbFeatures.Items.Add(characteristic.Uuid);
this.GattCharacteristics.Add(characteristic);
this.btnOperator.Enabled = true;
});
}
private void BleCore_DeviceWatcherChanged(MsgType type, BluetoothLEDevice bluetoothLEDevice)
{
RunAsync(() =>
{
//小米体重称
//if (bluetoothLEDevice.Name.Equals("MI SCALE2") || bluetoothLEDevice.DeviceId.Contains("c8:47:8c:a0:2b:db"))
//{
// this.listboxBleDevice.Items.Add(bluetoothLEDevice.Name);
// this.DeviceList.Add(bluetoothLEDevice);
// this.btnConnect.Enabled = true;
//}
this.listboxBleDevice.Items.Add(bluetoothLEDevice.Name);
this.DeviceList.Add(bluetoothLEDevice);
this.btnConnect.Enabled = true;
});
}
private void BleCore_MessageChanged(MsgType type, string message, byte[] data = null)
{
RunAsync(() =>
{
this.listboxMessage.Items.Add(message);
if(type == MsgType.BleData)
{
//小米体重数据 第1-2位为体重数据,小端存储。单位为斤(磅)
//float weight_kg = Convert.ToInt32(BinaryConversion(date[2], date[1]), 16) / 100f / 2;
}
});
}
private void btnSearch_Click(object sender, EventArgs e)
{
if (this.btnSearch.Text == "搜索")
{
this.listboxBleDevice.Items.Clear();
this.listboxMessage.Items.Clear();
this.bleCore.StartBleDeviceWatcher();
this.btnSearch.Text = "停止";
}
else
{
this.bleCore.StopBleDeviceWathcer();
this.btnSearch.Text = "搜索";
}
}
private void btnConnect_Click(object sender, EventArgs e)
{
if(this.listboxBleDevice.SelectedItem != null)
{
string deviceName = this.listboxBleDevice.SelectedItem.ToString();
var bluetoothLEDevice = this.DeviceList.Where(u=>u.Name == deviceName).FirstOrDefault();
if(bluetoothLEDevice != null)
{
bleCore.StartMatching(bluetoothLEDevice);
this.btnServer.Enabled = true;
}
else
{
MessageBox.Show("没有发现蓝牙,请重新搜索!");
this.btnServer.Enabled = false;
}
}
else
{
MessageBox.Show("请选择需要连接的现蓝牙设备!");
this.btnServer.Enabled = false;
}
}
private void btnServer_Click(object sender, EventArgs e)
{
this.cmbServer.Items.Clear();
this.bleCore.FindService();
}
private void btnFeatures_Click(object sender, EventArgs e)
{
this.cmbFeatures.Items.Clear();
if(this.cmbServer.SelectedItem != null)
{
var item = this.GattDeviceServices.Where(u=>u.Uuid == new Guid(this.cmbServer.SelectedItem.ToString())).FirstOrDefault();
this.bleCore.FindCharacteristic(item);
}
else
{
MessageBox.Show("请选择蓝牙服务!");
}
}
private void btnOperator_Click(object sender, EventArgs e)
{
if(this.cmbFeatures.SelectedItem != null)
{
var item = this.GattCharacteristics.Where(u => u.Uuid == new Guid(this.cmbFeatures.SelectedItem.ToString())).FirstOrDefault();
this.bleCore.SetOpertor(item);
if(item.CharacteristicProperties == (GattCharacteristicProperties.Notify |
GattCharacteristicProperties.Read | GattCharacteristicProperties.Write))
{
this.btnReader.Enabled = true;
this.btnSend.Enabled = true;
}
}
else
{
MessageBox.Show("选择蓝牙特征!");
}
}
private void btnReader_Click(object sender, EventArgs e)
{
}
private void btnSend_Click(object sender, EventArgs e)
{
byte[] dataBytes = new byte[6];
dataBytes[0] = 0x23;
dataBytes[1] = 0x00;
dataBytes[2] = 0x02;
dataBytes[3] = 0x01;
dataBytes[4] = (byte)(dataBytes[1] + dataBytes[2] + dataBytes[3]);
dataBytes[5] = 0x2A;
this.bleCore.Write(dataBytes);
//小米体重称
//GattCharacteristic gattCharacteristic = GattCharacteristics.Find((x) => { return x.Uuid.Equals(new Guid("00002a2f-0000-3512-2118-0009af100700")); });
//bleCore.SetOpertor(gattCharacteristic);
//bleCore.Write(new byte[] { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, });
//bleCore.Write(new byte[] { 0x02 });
}
}
}