之前在文章系统权限的获取中对蓝牙权限的获取的表述有些问题,这几天终于重新整理了下蓝牙权限的获取方法,这次用Swift写的,都在一个类文件里,注释详细,所以没什么太多要说的,都在代码里了:
import UIKit
import CoreBluetooth
/**无参常规回调**/
typealias TenBluetoothNormalAction = (() -> Void);
@objcMembers class TenBluetoothAuthManager: NSObject {
/**对象单例**/
private static let shareInstance = TenBluetoothAuthManager.init();
/**回调数组**/
private var onceAuthStateUpdateActions:[TenBluetoothNormalAction] = [TenBluetoothNormalAction]();
/**获取权限用的暂存蓝牙管理类**/
private lazy var centralManager:CBCentralManager = {
return CBCentralManager.init(delegate: TenBluetoothAuthManager.shareInstance, queue: nil, options: [
CBCentralManagerOptionShowPowerAlertKey : false,//不弹出链接新设备的系统弹窗
]);
}();
/**数据处理的队列**/
private let barrierQueue = DispatchQueue.init(label: "com.ten.bluetoothAuthBarrierQueue", qos: .default, attributes: .concurrent);
}
//MARK: Public class method
extension TenBluetoothAuthManager {
/**
请求蓝牙权限状态
- Parameter restrictedAction: APP无权使用,并且用户无法更改(需要在【屏幕使用时间 -> 隐私访问限制中】修改设置).
- Parameter deniedAction: 对APP拒绝授权(要跳转设置中对该APP打开蓝牙权限).
- Parameter unsupportedAction: APP已授权蓝牙,但蓝牙在设备上不可用(手机的蓝牙坏了,一般不会出现).
- Parameter offAction: APP已授权蓝牙,但蓝牙被关闭了(系统设置关闭或者控制中心关闭).
- Parameter onAction: APP已授权蓝牙,并且蓝牙可用(可以进行扫描和链接的操作).
- Returns: Void.
*/
static func requestAuthStateAction(restrictedAction:TenBluetoothNormalAction? = nil,
deniedAction:TenBluetoothNormalAction? = nil,
unsupportedAction:TenBluetoothNormalAction? = nil,
offAction:TenBluetoothNormalAction? = nil,
onAction:TenBluetoothNormalAction? = nil) {
if #available(iOS 13.0, *) {
//iOS13以上才有针对APP的蓝牙权限,13中是对象方法
var authState:CBManagerAuthorization = self.shareInstance.centralManager.authorization;
if #available(iOS 13.1, *) {
//iOS13.1后改为类方法
authState = CBCentralManager.authorization;
}
//针对蓝牙对APP的权限做对应处理
switch authState {
case .notDetermined:
//用户未作出选择(需要第一次请求授权)
//请求一次蓝牙状态变更的回调,在回调中重新处理蓝牙权限判断逻辑
self.askOnceAuthStateUpdateAction {
self.requestAuthStateAction(restrictedAction: restrictedAction, deniedAction: deniedAction, unsupportedAction: unsupportedAction, offAction: offAction, onAction: onAction);
};
break;
case .restricted:
//APP无权使用,并且用户无法更改(需要在【屏幕使用时间 -> 隐私访问限制中】修改设置)
self.performAction(inMainQueue: restrictedAction);
break;
case .denied:
//APP无权使用(未对APP授权),此时state == unauthorized,需跳转给APP授权蓝牙
self.performAction(inMainQueue: deniedAction);
break;
case .allowedAlways:
//开启并有权使用
//判断当前的设置中的蓝牙的状态
self.dealAllowedAction(unsupportedAction: unsupportedAction, unauthorizedAction: deniedAction, offAction: offAction, onAction: onAction);
break;
}
}else {
//iOS13以下 没有APP授权的概念,所以直接判断蓝牙的状态
self.dealAllowedAction(unsupportedAction: unsupportedAction, unauthorizedAction: deniedAction, offAction: offAction, onAction: onAction);
}
}
}
//MARK: Private class method
extension TenBluetoothAuthManager {
/**
处理蓝牙状态判断逻辑
- Parameter unsupportedAction: 该平台不支持蓝牙(蓝牙坏了,一般不会用到).
- Parameter unauthorizedAction: 该应用未授权(用户禁止APP使用蓝牙权限).
- Parameter offAction: 蓝牙关闭(设置中或者控制中心中关闭).
- Parameter onAction: 蓝牙打开并可以连接.
- Returns: Void.
*/
private static func dealAllowedAction(unsupportedAction:TenBluetoothNormalAction?,
unauthorizedAction:TenBluetoothNormalAction?,
offAction:TenBluetoothNormalAction?,
onAction:TenBluetoothNormalAction?) {
let state = self.shareInstance.centralManager.state;
switch state {
case .unknown, .resetting:
//未知状态 || 与系统服务丢失状态(立即更新)
//因为会立即更新,因此请求一次状态更新回调,对更新后的状态再判断处理
self.askOnceAuthStateUpdateAction {
self.dealAllowedAction(unsupportedAction: unsupportedAction, unauthorizedAction: unauthorizedAction, offAction: offAction, onAction: onAction);
};
break;
case .unsupported:
//该平台不支持蓝牙(蓝牙坏了,一般不会用到)
self.performAction(inMainQueue: unsupportedAction);
break;
case .unauthorized:
//该应用未授权(用户禁止了蓝牙权限)
self.performAction(inMainQueue: unauthorizedAction);
break;
case .poweredOff:
//蓝牙关闭(设置中或者控制中心中关闭)
self.performAction(inMainQueue: offAction);
break;
case .poweredOn:
//蓝牙打开并可以连接
self.performAction(inMainQueue: onAction);
break;
}
}
/**
请求一次权限授权状态变更(单次,首次会弹出系统弹窗)
- Parameter action: 权限变化的回调(在这里通过requestAuthStateAction处理后续逻辑).
- Returns: Void.
*/
private static func askOnceAuthStateUpdateAction(action:TenBluetoothNormalAction?) {
self.shareInstance.askOnceAuthStateUpdateAction(action: action);
}
/**主线程中回调**/
private static func performAction(inMainQueue action:TenBluetoothNormalAction?) {
DispatchQueue.main.async {
action?();
}
}
}
//MARK: Private object method
extension TenBluetoothAuthManager {
/**
请求一次权限授权状态变更(单次,首次会弹出系统弹窗)
- Parameter action: 权限变化的回调(在这里通过requestAuthStateAction处理后续逻辑).
- Returns: Void.
*/
private func askOnceAuthStateUpdateAction(action:TenBluetoothNormalAction?) {
if let action = action {
//需要回调,保存回调
self.barrierQueue.sync { [weak self] in
guard let `self` = self else { return }
self.onceAuthStateUpdateActions.append(action);
}
}
}
/**蓝牙设备状态更新处理**/
private func dealCentralManagerDidUpdateState(_ central: CBCentralManager) {
for action in self.onceAuthStateUpdateActions {
Self.performAction(inMainQueue: action);
}
self.barrierQueue.sync { [weak self] in
guard let `self` = self else { return }
self.onceAuthStateUpdateActions = .init();
}
}
}
//MARK: CBCentralManagerDelegate
extension TenBluetoothAuthManager: CBCentralManagerDelegate {
/**蓝牙设备状态更新**/
func centralManagerDidUpdateState(_ central: CBCentralManager) {
self.dealCentralManagerDidUpdateState(central);
}
}
另外需要注意的是info.plist设置
iOS13之后:Privacy - Bluetooth Always Usage Description
iOS13之前:Privacy - Bluetooth Peripheral Usage Description