using Shared; using System; using System.Collections.Generic; using System.Text; namespace HDL_ON.Stan { #if __Android__ public class HdlBluetoothLogic { #region ■ 变量声明___________________________ /// /// 安卓蓝牙的逻辑 /// private static HdlBluetoothLogic m_Current = null; /// /// 安卓蓝牙的逻辑 /// public static HdlBluetoothLogic Current { get { if (m_Current == null) { m_Current = new HdlBluetoothLogic(); } return m_Current; } } /// /// 当前蓝牙客户端 /// private Blufi.Espressif.BlufiClient nowBlufiClient = null; /// /// 接收事件 /// private Action ReceiveEvent = null; /// /// 发送状态(0:发送失败 1:发送成功) /// private int sendStatuValue = -1; #endregion #region ■ 蓝牙所需功能检测___________________ /// /// 检测是否能够搜索蓝牙(内部会弹出Msg框,因为内部需要检测系统权限,所以参数采用回调的方式) /// /// 检测结果事件 public void CheckCanScanBluetooth(Action resultEvent) { var adapter = Android.Bluetooth.BluetoothAdapter.DefaultAdapter; var scanner = adapter.BluetoothLeScanner; if (adapter.IsEnabled == false || scanner == null) { HdlMessageLogic.Current.ShowMassage(ShowMsgType.Tip, Language.StringByID(StringId.PleaseTurnOnBluetooth)); resultEvent?.Invoke(false); return; } //检测是否打开了系统功能 if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.M) { var locationManager = (Android.Locations.LocationManager)Application.Activity.GetSystemService(Android.Content.Context.LocationService); if (locationManager == null) { //位置信息(GBS)不可用 HdlMessageLogic.Current.ShowMassage(ShowMsgType.Tip, Language.StringByID(StringId.GbsIsNotAvailable)); resultEvent?.Invoke(false); return; } if (locationManager.IsProviderEnabled("network") == false) { HdlMessageLogic.Current.ShowMassage(ShowMsgType.Tip, Language.StringByID(StringId.NetworkIsNotAvailable)); resultEvent?.Invoke(false); return; } if (locationManager.IsProviderEnabled("gps") == false) { //位置信息(GBS)不可用 HdlMessageLogic.Current.ShowMassage(ShowMsgType.Tip, Language.StringByID(StringId.GbsIsNotAvailable)); resultEvent?.Invoke(false); return; } } //检测蓝牙需要的权限 ((BaseActivity)Application.Activity).SetPermission((result1) => { if (result1 == false) { resultEvent?.Invoke(false); return; } ((BaseActivity)Application.Activity).SetPermission((result2) => { if (result2 == false) { resultEvent?.Invoke(false); return; } //全部通过 resultEvent?.Invoke(true); }, "android.permission.ACCESS_FINE_LOCATION"); }, "android.permission.ACCESS_COARSE_LOCATION"); } #endregion #region ■ 蓝牙扫描___________________________ /// /// 搜索蓝牙 /// /// 搜索时间(秒) /// 搜索结束的事件 public void ScanBluetooth(int waitTime, Action> FinishEvent) { HdlThreadLogic.Current.RunMain(() => { //再次检测是否能够搜索蓝牙 this.CheckCanScanBluetooth((result) => { if (result == true) { HdlThreadLogic.Current.RunThread(() => { //开始搜索蓝牙 this.DoScanBluetooth(waitTime, FinishEvent); }); } }); }); } /// /// 开始搜索蓝牙 /// /// 搜索时间(秒) /// 搜索结束的事件 private void DoScanBluetooth(int waitTime, Action> FinishEvent) { var listBluetoothInfo = new List(); BluetoothScanCallback scanCallback = null; Android.Bluetooth.BluetoothAdapter adapter = null; Android.Bluetooth.LE.BluetoothLeScanner scanner = null; //以防万一,蓝牙都丢在主线程中运行 HdlThreadLogic.Current.RunMain(() => { adapter = Android.Bluetooth.BluetoothAdapter.DefaultAdapter; scanner = adapter.BluetoothLeScanner; scanCallback = new BluetoothScanCallback(); scanner.StartScan(null, new Android.Bluetooth.LE.ScanSettings.Builder().SetScanMode(Android.Bluetooth.LE.ScanMode.LowLatency).Build(), scanCallback); }, ShowErrorMode.NO); //等待 System.Threading.Thread.Sleep(waitTime * 1000); HdlThreadLogic.Current.RunMain(() => { scanner.StopScan(scanCallback); adapter.Dispose(); foreach (var data in scanCallback.listData) { listBluetoothInfo.Add(data); } scanCallback.listData.Clear(); FinishEvent?.Invoke(listBluetoothInfo); }); } /// /// 蓝牙的回调对象 /// private class BluetoothScanCallback : Android.Bluetooth.LE.ScanCallback { /// /// 蓝牙列表 /// public List listData = new List(); /// /// 重复检测 /// private List listCheck = new List(); /// /// 蓝牙结果接收 /// /// public override void OnBatchScanResults(IList listResult) { foreach (var result in listResult) { this.AddBluetoothResult(result); } } /// /// 蓝牙结果接收 /// /// /// public override void OnScanResult(Android.Bluetooth.LE.ScanCallbackType callbackType, Android.Bluetooth.LE.ScanResult result) { this.AddBluetoothResult(result); } /// /// 添加蓝牙缓存 /// /// private void AddBluetoothResult(Android.Bluetooth.LE.ScanResult result) { var device = result.Device; if (device == null || listCheck.Contains(device.Address) == true) { return; } listCheck.Add(device.Address); var data = new BluetoothInfo(); data.Name = device.Name; if (data.Name == null) { data.Name = string.Empty; } data.Address = device.Address; data.Device = device; listData.Add(data); } } #endregion #region ■ 蓝牙链接___________________________ /// /// 蓝牙链接(false:连接失败 true:连接成功) /// /// 需要链接的蓝牙对象 /// 因为需要对方反馈,所以使用回调(链接结果 false:连接失败 true:连接成功) public void ContectBluetooth(BluetoothInfo bluetooth, Action connectEvent) { HdlThreadLogic.Current.RunMain(() => { try { this.nowBlufiClient = new Blufi.Espressif.BlufiClient(Application.Activity, bluetooth.Device); //一个回调事件 var callback = new InnerGattCallback(); callback.ConnectionStateEvent += (div, newState) => { if (div == 1) { if (newState == Android.Bluetooth.ProfileState.Connected) { //链接建立成功 connectEvent?.Invoke(true); //只通知一次 connectEvent = null; } else if (newState == Android.Bluetooth.ProfileState.Disconnected) { //关闭链接 this.DisContectBluetooth(); connectEvent?.Invoke(false); //只通知一次 connectEvent = null; } } else if (div == -1) { //关闭链接 this.DisContectBluetooth(); connectEvent?.Invoke(false); //只通知一次 connectEvent = null; } }; nowBlufiClient.SetGattCallback(callback); //另外一个回调事件 var blufiCall = new BlufiCallbackMain(); blufiCall.StateEvent += (div, data) => { //-1:异常 1:正常 2:发送数据成功 3:发送数据失败 if (div == StatuEnum.A异常) { //关闭链接 this.DisContectBluetooth(); connectEvent?.Invoke(false); //只通知一次 connectEvent = null; } else if (div == StatuEnum.A发送成功 || div == StatuEnum.A发送失败) { sendStatuValue = div == StatuEnum.A发送成功 ? 1 : 0; } else if (div == StatuEnum.A蓝牙反馈) { //蓝牙返回的结果 this.ReceiveEvent?.Invoke(data); } }; nowBlufiClient.SetBlufiCallback(blufiCall); //执行链接 nowBlufiClient.Connect(); } catch { connectEvent?.Invoke(false); connectEvent = null; } }); } /// /// 先这么定义一个空的继承 /// private class InnerGattCallback : Android.Bluetooth.BluetoothGattCallback { /// /// 状态事件回调(-1:异常 1:OnConnectionStateChange) /// public Action ConnectionStateEvent = null; /// /// 链接状态改变 /// /// /// /// public override void OnConnectionStateChange(Android.Bluetooth.BluetoothGatt gatt, Android.Bluetooth.GattStatus status, Android.Bluetooth.ProfileState newState) { if (status == Android.Bluetooth.GattStatus.Success) { //回调事件 this.ConnectionStateEvent?.Invoke(1, newState); } else { //回调事件 this.ConnectionStateEvent?.Invoke(-1, 0); } } /// /// 成功发现设备的services时,调用此方法 /// /// /// public override void OnServicesDiscovered(Android.Bluetooth.BluetoothGatt gatt, Android.Bluetooth.GattStatus status) { if (status != Android.Bluetooth.GattStatus.Success) { //回调事件 this.ConnectionStateEvent?.Invoke(-1, 0); } } /// /// 应该是写入事件吧 /// /// /// /// public override void OnCharacteristicWrite(Android.Bluetooth.BluetoothGatt gatt, Android.Bluetooth.BluetoothGattCharacteristic characteristic, Android.Bluetooth.GattStatus status) { if (status != Android.Bluetooth.GattStatus.Success) { //回调事件 this.ConnectionStateEvent?.Invoke(-1, 0); } } } /// /// 抄SDK的,我也不知道这个是什么 /// private class BlufiCallbackMain : Blufi.Espressif.BlufiCallback { /// /// 状态事件回调 当第一个参数为"A蓝牙反馈"时,第二个参数为蓝牙返回的信息 /// public Action StateEvent = null; /// /// 抄SDK的,我也不知道这个是什么 /// /// /// /// /// /// public override void OnGattPrepared(Blufi.Espressif.BlufiClient client, Android.Bluetooth.BluetoothGatt gatt, Android.Bluetooth.BluetoothGattService service, Android.Bluetooth.BluetoothGattCharacteristic writeChar, Android.Bluetooth.BluetoothGattCharacteristic notifyChar) { if (service == null || writeChar == null || notifyChar == null) { StateEvent?.Invoke(StatuEnum.A异常, null); return; } try { int mtu = 128; if ((int)Android.OS.Build.VERSION.SdkInt == 29 && Android.OS.Build.Manufacturer.ToLower().StartsWith("samsung") == true) { mtu = 23; } var requestMtu = gatt.RequestMtu(mtu); if (!requestMtu) { //Request mtu failed client.SetPostPackageLengthLimit(20); } StateEvent?.Invoke(StatuEnum.A正常, null); ; } catch { StateEvent?.Invoke(StatuEnum.A异常, null); return; } } /// /// 手机端发送数据到蓝牙的结果 /// /// /// 0:成功 其他都是失败 /// 手机端发送的数据 public override void OnPostCustomDataResult(Blufi.Espressif.BlufiClient client, int status, byte[] data) { StateEvent?.Invoke(status == 0 ? StatuEnum.A发送成功 : StatuEnum.A发送失败, null); } /// /// 蓝牙回复的结果 /// /// /// 0:成功 其他都是失败 /// 蓝牙回复的数据 public override void OnReceiveCustomData(Blufi.Espressif.BlufiClient client, int status, byte[] data) { if (status == 0) { var receiveData = System.Text.Encoding.UTF8.GetString(data); StateEvent?.Invoke(StatuEnum.A蓝牙反馈, receiveData); } } } #endregion #region ■ 蓝牙关闭___________________________ /// /// 关闭蓝牙链接 /// public void DisContectBluetooth() { HdlThreadLogic.Current.RunMain(() => { this.nowBlufiClient?.RequestCloseConnection(); this.nowBlufiClient = null; m_Current = null; }, ShowErrorMode.NO); } /// /// 摧毁 /// public void Dispone() { //关闭蓝牙链接 this.DisContectBluetooth(); this.ReceiveEvent = null; m_Current = null; } #endregion #region ■ 发送数据___________________________ /// /// 发送数据给蓝牙 /// /// 发送的数据 /// 等待时间(秒),如果设置为0,则只要发送不出现异常,直接判定为成功 public bool SendData(string i_data, int waiTime = 0) { if (this.nowBlufiClient == null) { return false; } try { this.sendStatuValue = -1; HdlThreadLogic.Current.RunMain(() => { //发送数据 var byteData = System.Text.Encoding.UTF8.GetBytes(i_data); this.nowBlufiClient.PostCustomData(byteData); }, ShowErrorMode.NO); if (waiTime == 0) { return true; } waiTime *= 5; while (this.sendStatuValue == -1 && waiTime > 0) { System.Threading.Thread.Sleep(200); waiTime--; } return this.sendStatuValue == 1; } catch { return false; } } #endregion #region ■ 一般方法___________________________ /// /// 添加蓝牙的接收事件 /// /// 蓝牙接收事件 public void AddReceiveEvent(Action i_ReceiveEvent) { this.ReceiveEvent = i_ReceiveEvent; } /// /// 移除蓝牙的接收事件 /// public void RemoveReceiveEvent() { this.ReceiveEvent = null; } #endregion #region ■ 结构体_____________________________ /// /// 蓝牙返回的信息 /// public class BluetoothInfo { /// /// 名字(此名字不会null,如果它本身是null,只会是string.empty) /// public string Name = string.Empty; /// /// 地址 /// public string Address = string.Empty; /// /// 蓝牙设备 /// public Android.Bluetooth.BluetoothDevice Device = null; } /// /// 状态枚举 /// private enum StatuEnum { A异常 = -1, A正常 = 1, A发送成功 = 2, A发送失败 = 3, A蓝牙反馈 = 4 } #endregion } #endif }