之前在文章系統權限的獲取中對藍牙權限的獲取的表述有些問題,這幾天終于重新整理了下藍牙權限的獲取方法,這次用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