项目背景
MAUI的出现,赋予了广大.Net开发者开发多平台应用的能力,MAUI 是Xamarin.Forms演变而来,但是相比Xamarin性能更好,可扩展性更强,结构更简单。但是MAUI对于平台相关的实现并不完整。所以MASA团队开展了一个实验性项目,意在对微软MAUI的补充和扩展
前言
本系列文章面向移动开发小白,从零开始进行平台相关功能开发,演示如何参考平台的官方文档使用MAUI技术来开发相应功能。
介绍
之前两篇文章我们实现了安卓蓝牙BLE的相关功能,本文我们将IOS的BLE功能实现一下。考虑到Swift语法对于c#开发人员更友好,本文示例代码参考Swift,相关代码来自苹果开发者官网 https://developer.apple.com/documentation
开发步骤
修改项目
delegate: CBCentralManagerDelegate?,
queue: DispatchQueue?,
options: [String : Any]? = nil
)
{
private static BluetoothDelegate _delegate = new();
public static CBCentralManager _manager = new CBCentralManager(_delegate, DispatchQueue.DefaultGlobalQueue, new CBCentralInitOptions
{
ShowPowerAlert = true,
});
private sealed class BluetoothDelegate : CBCentralManagerDelegate
{
private readonly EventWaitHandle _eventWaitHandle = new(false, EventResetMode.AutoReset);
public List<BluetoothDevice> Devices { get; } = new();
public void WaitOne()
{
Task.Run(async () =>
{
await Task.Delay(5000);
_eventWaitHandle.Set();
});
_eventWaitHandle.WaitOne();
}
public override void DiscoveredPeripheral(CBCentralManager central, CBPeripheral peripheral,
NSDictionary advertisementData,
NSNumber RSSI)
{
System.Diagnostics.Debug.WriteLine("OnScanResult");
if (!Devices.Contains(peripheral))
{
Devices.Add(peripheral);
}
}
[Preserve]
public override void UpdatedState(CBCentralManager central)
{
}
}
}
我们自定义的BluetoothDelegate 继承自CBCentralManagerDelegate,篇幅问题我们这里先只重写DiscoveredPeripheral和 UpdatedState,我们这次的演示不需要实现UpdatedState,但是这里的重写必须先放上去,否则调试过程会出现下面的报错
ObjCRuntime.ObjCException: 'Objective-C exception thrown. Name: NSInvalidArgumentException Reason: -[Masa_Blazor_Maui_Plugin_Bluetooth_MasaMauiBluetoothService_BluetoothDelegate centralManagerDidUpdateState:]: unrecognized selector sent to instance 0x284bfe200
这里之所以可以Devices.Contains和Devices.Add是因为我们在BluetoothDevice类中实现了隐式转换
如下是iOS目录下BluetoothDevice.ios.cs的部分代码。
{
...
private BluetoothDevice(CBPeripheral peripheral)
{
_peripheral = peripheral;
}
public static implicit operator BluetoothDevice(CBPeripheral peripheral)
{
return peripheral == null ? null : new BluetoothDevice(peripheral);
}
public static implicit operator CBPeripheral(BluetoothDevice device)
{
return device._peripheral;
}
...
我们继续在MasaMauiBluetoothService添加一个扫描附件设备的方法,我们看一下Swift的文档
withServices serviceUUIDs: [CBUUID]?,
options: [String : Any]? = nil
)
option:提供扫描的选项,我们这里用到了AllowDuplicatesKey,该值指定扫描是否应在不重复筛选的情况下运行
我们参照实现以下我们的PlatformScanForDevices方法
{
if (!_manager.IsScanning)
{
_manager.ScanForPeripherals(new CBUUID[] { }, new PeripheralScanningOptions
{
AllowDuplicatesKey = true
});
await Task.Run(() => { _delegate.WaitOne(); });
_manager.StopScan();
_discoveredDevices = _delegate.Devices.AsReadOnly();
}
return _discoveredDevices;
}
我们还需实现PlatformIsEnabledIsEnabled和PlatformCheckAndRequestBluetoothPermission方法,用来在扫描之前检查蓝牙是否可用并且已经经过用户授权
{
return _manager.State == CBManagerState.PoweredOn;
}
public static async Task<PermissionStatus> PlatformCheckAndRequestBluetoothPermission()
{
PermissionStatus status = await Permissions.CheckStatusAsync<BluetoothPermissions>();
if (status == PermissionStatus.Granted)
return status;
if (status == PermissionStatus.Denied && DeviceInfo.Platform == DevicePlatform.iOS)
{
// Prompt the user to turn on in settings
// On iOS once a permission has been denied it may not be requested again from the application
return status;
}
status = await Permissions.RequestAsync<BluetoothPermissions>();
return status;
}
private class BluetoothPermissions : Permissions.BasePlatformPermission
{
protected override Func<IEnumerable<string>> RequiredInfoPlistKeys
=>
() => new string[] { "NSBluetoothAlwaysUsageDescription", "NSBluetoothPeripheralUsageDescription" };
public override Task<PermissionStatus> CheckStatusAsync()
{
EnsureDeclared();
return Task.FromResult(GetBleStatus());
}
private PermissionStatus GetBleStatus() //Todo:Needs to be replenished
{
var status = _cbCentralManager.State;
return status switch
{
CBManagerState.PoweredOn=> PermissionStatus.Granted,
CBManagerState.Unauthorized => PermissionStatus.Denied,
CBManagerState.Resetting => PermissionStatus.Restricted,
_ => PermissionStatus.Unknown,
};
}
}
Resetting, //手机蓝牙已断开连接
Unsupported, //手机蓝牙功能没有权限
Unauthorized, //手机蓝牙功能没有权限
PoweredOff,//手机蓝牙功能关闭
PoweredOn //蓝牙开启且可用
{
private static IReadOnlyCollection<BluetoothDevice> _discoveredDevices;
public static Task<IReadOnlyCollection<BluetoothDevice>> ScanForDevicesAsync()
{
return PlatformScanForDevices();
}
public static bool IsEnabled()
{
return PlatformIsEnabledIsEnabled();
}
public static async Task<PermissionStatus> CheckAndRequestBluetoothPermission()
{
return await PlatformCheckAndRequestBluetoothPermission();
}
}
使用
在Masa.Blazor.Maui.Plugin.BlueToothSample项目的Platforms->iOS->Info.plist中添加蓝牙相关权限
<string>App required to access Bluetooth</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>App required to access Bluetooth</string>
iOS调试及错误排查
Could not find executable for C:\Users\xxx\AppData\Local\Temp\hbjayi2h.ydn
找不到文件的情况,右键选择清理项目即可,如果无法解决手动删除bin和obj目录重试