feat: 支持外围设备接口,优化中心设备接口 (#18)
* 临时提交 * 临时提交 * 临时提交 * fix: 调整接口 * fix: 修复问题 * fix: 调整 iOS 实现 * fix: 添加注释 * fix: 修改预览版本号 * fix: 修复已知问题 * fix: 优化接口 * fix: 解决 32 位 UUID 报错问题 * fix: 修复问题 * fix: 修复依赖项 * fix: 移除多余代码 * fix: 修复已知问题 * fix: 修复问题 * fix: 修改版本号 * fix: 修复问题 * fix: 发布正式版本
This commit is contained in:
@ -0,0 +1,650 @@
|
||||
//
|
||||
// MyCentralController.swift
|
||||
// bluetooth_low_energy_ios
|
||||
//
|
||||
// Created by 闫守旺 on 2023/8/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreBluetooth
|
||||
|
||||
#if os(iOS)
|
||||
import Flutter
|
||||
#elseif os(macOS)
|
||||
import FlutterMacOS
|
||||
#else
|
||||
#error("Unsupported platform.")
|
||||
#endif
|
||||
|
||||
class MyCentralManager: MyCentralManagerHostApi {
|
||||
init(_ binaryMessenger: FlutterBinaryMessenger) {
|
||||
self.binaryMessenger = binaryMessenger
|
||||
}
|
||||
|
||||
private let binaryMessenger: FlutterBinaryMessenger
|
||||
private let centralManager = CBCentralManager()
|
||||
|
||||
private lazy var api = MyCentralManagerFlutterApi(binaryMessenger: binaryMessenger)
|
||||
private lazy var centralManagerDelegate = MyCentralManagerDelegate(self)
|
||||
private lazy var peripheralDelegate = MyPeripheralDelegate(self)
|
||||
|
||||
private var peripherals = [Int64: CBPeripheral]()
|
||||
private var services = [Int64: CBService]()
|
||||
private var characteristics = [Int64: CBCharacteristic]()
|
||||
private var descriptors = [Int64: CBDescriptor]()
|
||||
|
||||
private var peripheralsArgs = [Int: MyPeripheralArgs]()
|
||||
private var servicesArgsOfPeripheralsArgs = [Int64: [MyGattServiceArgs]]()
|
||||
private var servicesArgs = [Int: MyGattServiceArgs]()
|
||||
private var characteristicsArgs = [Int: MyGattCharacteristicArgs]()
|
||||
private var descriptorsArgs = [Int: MyGattDescriptorArgs]()
|
||||
|
||||
private var setUpCompletion: ((Result<MyCentralManagerArgs, Error>) -> Void)?
|
||||
private var connectCompletions = [Int64: (Result<Void, Error>) -> Void]()
|
||||
private var disconnectCompletions = [Int64: (Result<Void, Error>) -> Void]()
|
||||
private var readRssiCompletions = [Int64: (Result<Int64, Error>) -> Void]()
|
||||
private var discoverGattCompletions = [Int64: (Result<[MyGattServiceArgs], Error>) -> Void]()
|
||||
private var unfinishedServices = [Int64: [CBService]]()
|
||||
private var unfinishedCharacteristics = [Int64: [CBCharacteristic]]()
|
||||
private var readCharacteristicCompletions = [Int64: (Result<FlutterStandardTypedData, Error>) -> Void]()
|
||||
private var writeCharacteristicCompletions = [Int64: (Result<Void, Error>) -> Void]()
|
||||
private var notifyCharacteristicCompletions = [Int64: (Result<Void, Error>) -> Void]()
|
||||
private var readDescriptorCompletions = [Int64: (Result<FlutterStandardTypedData, Error>) -> Void]()
|
||||
private var writeDescriptorCompletions = [Int64: (Result<Void, Error>) -> Void]()
|
||||
|
||||
func setUp(completion: @escaping (Result<MyCentralManagerArgs, Error>) -> Void) {
|
||||
do {
|
||||
if setUpCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
try tearDown()
|
||||
centralManager.delegate = centralManagerDelegate
|
||||
if centralManager.state == .unknown {
|
||||
setUpCompletion = completion
|
||||
} else {
|
||||
let stateArgs = centralManager.state.toArgs()
|
||||
let stateNumberArgs = Int64(stateArgs.rawValue)
|
||||
let args = MyCentralManagerArgs(stateNumberArgs: stateNumberArgs)
|
||||
completion(.success(args))
|
||||
}
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func tearDown() throws {
|
||||
if(centralManager.isScanning) {
|
||||
centralManager.stopScan()
|
||||
}
|
||||
for peripheral in peripherals.values {
|
||||
if peripheral.state != .disconnected {
|
||||
centralManager.cancelPeripheralConnection(peripheral)
|
||||
}
|
||||
}
|
||||
peripherals.removeAll()
|
||||
services.removeAll()
|
||||
characteristics.removeAll()
|
||||
descriptors.removeAll()
|
||||
peripheralsArgs.removeAll()
|
||||
servicesArgsOfPeripheralsArgs.removeAll()
|
||||
servicesArgs.removeAll()
|
||||
characteristicsArgs.removeAll()
|
||||
descriptorsArgs.removeAll()
|
||||
setUpCompletion = nil
|
||||
connectCompletions.removeAll()
|
||||
disconnectCompletions.removeAll()
|
||||
readRssiCompletions.removeAll()
|
||||
discoverGattCompletions.removeAll()
|
||||
unfinishedServices.removeAll()
|
||||
unfinishedCharacteristics.removeAll()
|
||||
readCharacteristicCompletions.removeAll()
|
||||
writeCharacteristicCompletions.removeAll()
|
||||
notifyCharacteristicCompletions.removeAll()
|
||||
readDescriptorCompletions.removeAll()
|
||||
writeDescriptorCompletions.removeAll()
|
||||
}
|
||||
|
||||
func startDiscovery() throws {
|
||||
let options = [CBCentralManagerScanOptionAllowDuplicatesKey: true]
|
||||
centralManager.scanForPeripherals(withServices: nil, options: options)
|
||||
}
|
||||
|
||||
func stopDiscovery() throws {
|
||||
centralManager.stopScan()
|
||||
}
|
||||
|
||||
func connect(peripheralHashCodeArgs: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
do {
|
||||
let unfinishedCompletion = connectCompletions[peripheralHashCodeArgs]
|
||||
if unfinishedCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
centralManager.connect(peripheral)
|
||||
connectCompletions[peripheralHashCodeArgs] = completion
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func disconnect(peripheralHashCodeArgs: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
do {
|
||||
let unfinishedCompletion = disconnectCompletions[peripheralHashCodeArgs]
|
||||
if unfinishedCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
centralManager.cancelPeripheralConnection(peripheral)
|
||||
disconnectCompletions[peripheralHashCodeArgs] = completion
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func getMaximumWriteLength(peripheralHashCodeArgs: Int64, typeNumberArgs: Int64) throws -> Int64 {
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
let typeRawValue = Int(typeNumberArgs)
|
||||
guard let typeArgs = MyGattCharacteristicWriteTypeArgs(rawValue: typeRawValue) else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
let type = typeArgs.toWriteType()
|
||||
let maximumWriteLength = peripheral.maximumWriteValueLength(for: type)
|
||||
let maximumWriteLengthArgs = Int64(maximumWriteLength)
|
||||
return maximumWriteLengthArgs
|
||||
}
|
||||
|
||||
func readRSSI(peripheralHashCodeArgs: Int64, completion: @escaping (Result<Int64, Error>) -> Void) {
|
||||
do {
|
||||
let unfinishedCompletion = readRssiCompletions[peripheralHashCodeArgs]
|
||||
if unfinishedCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
peripheral.readRSSI()
|
||||
readRssiCompletions[peripheralHashCodeArgs] = completion
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func discoverGATT(peripheralHashCodeArgs: Int64, completion: @escaping (Result<[MyGattServiceArgs], Error>) -> Void) {
|
||||
do {
|
||||
let unfinishedCompletion = discoverGattCompletions[peripheralHashCodeArgs]
|
||||
if unfinishedCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
peripheral.discoverServices(nil)
|
||||
discoverGattCompletions[peripheralHashCodeArgs] = completion
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func readCharacteristic(peripheralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
|
||||
do {
|
||||
let unfinishedCompletion = readCharacteristicCompletions[characteristicHashCodeArgs]
|
||||
if unfinishedCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
guard let characteristic = characteristics[characteristicHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
peripheral.readValue(for: characteristic)
|
||||
readCharacteristicCompletions[characteristicHashCodeArgs] = completion
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func writeCharacteristic(peripheralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, valueArgs: FlutterStandardTypedData, typeNumberArgs: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
do {
|
||||
let unfinishedCompletion = writeCharacteristicCompletions[characteristicHashCodeArgs]
|
||||
if unfinishedCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
guard let characteristic = characteristics[characteristicHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
let data = valueArgs.data
|
||||
let typeRawValue = Int(typeNumberArgs)
|
||||
guard let typeArgs = MyGattCharacteristicWriteTypeArgs(rawValue: typeRawValue) else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
let type = typeArgs.toWriteType()
|
||||
peripheral.writeValue(data, for: characteristic, type: type)
|
||||
writeCharacteristicCompletions[characteristicHashCodeArgs] = completion
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func notifyCharacteristic(peripheralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, stateArgs: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
do {
|
||||
let unfinishedCompletion = notifyCharacteristicCompletions[characteristicHashCodeArgs]
|
||||
if unfinishedCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
guard let characteristic = characteristics[characteristicHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
let enabled = stateArgs
|
||||
peripheral.setNotifyValue(enabled, for: characteristic)
|
||||
notifyCharacteristicCompletions[characteristicHashCodeArgs] = completion
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func readDescriptor(peripheralHashCodeArgs: Int64, descriptorHashCodeArgs: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
|
||||
do {
|
||||
let unfinishedCompletion = readDescriptorCompletions[descriptorHashCodeArgs]
|
||||
if unfinishedCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
guard let descriptor = descriptors[descriptorHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
peripheral.readValue(for: descriptor)
|
||||
readDescriptorCompletions[descriptorHashCodeArgs] = completion
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func writeDescriptor(peripheralHashCodeArgs: Int64, descriptorHashCodeArgs: Int64, valueArgs: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
do {
|
||||
let unfinishedCompletion = writeDescriptorCompletions[descriptorHashCodeArgs]
|
||||
if unfinishedCompletion != nil {
|
||||
throw MyError.illegalState
|
||||
}
|
||||
guard let peripheral = peripherals[peripheralHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
guard let descriptor = descriptors[descriptorHashCodeArgs] else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
let data = valueArgs.data
|
||||
peripheral.writeValue(data, for: descriptor)
|
||||
writeDescriptorCompletions[descriptorHashCodeArgs] = completion
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func didUpdateState() {
|
||||
let state = centralManager.state
|
||||
let stateArgs = state.toArgs()
|
||||
let stateNumberArgs = Int64(stateArgs.rawValue)
|
||||
if state != .unknown && setUpCompletion != nil {
|
||||
let args = MyCentralManagerArgs(stateNumberArgs: stateNumberArgs)
|
||||
setUpCompletion!(.success(args))
|
||||
setUpCompletion = nil
|
||||
}
|
||||
api.onStateChanged(stateNumberArgs: stateNumberArgs) {}
|
||||
}
|
||||
|
||||
|
||||
func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssi: NSNumber) {
|
||||
let peripheralArgs = peripheral.toArgs()
|
||||
let peripheralHashCode = peripheral.hash
|
||||
let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
peripheral.delegate = peripheralDelegate
|
||||
peripherals[peripheralHashCodeArgs] = peripheral
|
||||
peripheralsArgs[peripheralHashCode] = peripheralArgs
|
||||
let rssiArgs = rssi.int64Value
|
||||
let advertiseDataArgs = advertisementData.toAdvertiseDataArgs()
|
||||
api.onDiscovered(peripheralArgs: peripheralArgs, rssiArgs: rssiArgs, advertiseDataArgs: advertiseDataArgs) {}
|
||||
}
|
||||
|
||||
func didConnect(_ peripheral: CBPeripheral) {
|
||||
let peripheralHashCode = peripheral.hash
|
||||
guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else {
|
||||
return
|
||||
}
|
||||
let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
let completion = connectCompletions.removeValue(forKey: peripheralHashCodeArgs)
|
||||
completion?(.success(()))
|
||||
let stateArgs = true
|
||||
api.onPeripheralStateChanged(peripheralArgs: peripheralArgs, stateArgs: stateArgs) {}
|
||||
}
|
||||
|
||||
func didFailToConnect(_ peripheral: CBPeripheral, _ error: Error?) {
|
||||
let peripheralHashCode = peripheral.hash
|
||||
guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else {
|
||||
return
|
||||
}
|
||||
let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
let completion = connectCompletions.removeValue(forKey: peripheralHashCodeArgs)
|
||||
completion?(.failure(error ?? MyError.unknown))
|
||||
}
|
||||
|
||||
func didDisconnectPeripheral(_ peripheral: CBPeripheral, _ error: Error?) {
|
||||
let peripheralHashCode = peripheral.hash
|
||||
guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else {
|
||||
return
|
||||
}
|
||||
let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
let readRssiCompletion = readRssiCompletions.removeValue(forKey: peripheralHashCodeArgs)
|
||||
readRssiCompletion?(.failure(error ?? MyError.unknown))
|
||||
let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralHashCodeArgs)
|
||||
discoverGattCompletion?(.failure(error ?? MyError.unknown))
|
||||
unfinishedServices.removeValue(forKey: peripheralHashCodeArgs)
|
||||
unfinishedCharacteristics.removeValue(forKey: peripheralHashCodeArgs)
|
||||
let servicesArgs = servicesArgsOfPeripheralsArgs[peripheralHashCodeArgs] ?? []
|
||||
for serviceArgs in servicesArgs {
|
||||
let characteristicsArgs = serviceArgs.characteristicsArgs.map { args in args! }
|
||||
for characteristicArgs in characteristicsArgs {
|
||||
let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs)
|
||||
let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs)
|
||||
let notifyCharacteristicCompletion = notifyCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs)
|
||||
readCharacteristicCompletion?(.failure(error ?? MyError.unknown))
|
||||
writeCharacteristicCompletion?(.failure(error ?? MyError.unknown))
|
||||
notifyCharacteristicCompletion?(.failure(error ?? MyError.unknown))
|
||||
let descriptorsArgs = characteristicArgs.descriptorsArgs.map { args in args! }
|
||||
for descriptorArgs in descriptorsArgs {
|
||||
let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptorHashCodeArgs)
|
||||
let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptorHashCodeArgs)
|
||||
readDescriptorCompletion?(.failure(error ?? MyError.unknown))
|
||||
writeDescriptorCompletion?(.failure(error ?? MyError.unknown))
|
||||
}
|
||||
}
|
||||
}
|
||||
let stateArgs = false
|
||||
api.onPeripheralStateChanged(peripheralArgs: peripheralArgs, stateArgs: stateArgs) {}
|
||||
guard let completion = disconnectCompletions.removeValue(forKey: peripheralHashCodeArgs) else {
|
||||
return
|
||||
}
|
||||
if error == nil {
|
||||
completion(.success(()))
|
||||
} else {
|
||||
completion(.failure(error!))
|
||||
}
|
||||
}
|
||||
|
||||
func didReadRSSI(_ peripheral: CBPeripheral, _ rssi: NSNumber, _ error: Error?) {
|
||||
let peripheralHashCode = peripheral.hash
|
||||
guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else {
|
||||
return
|
||||
}
|
||||
let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
guard let completion = readRssiCompletions.removeValue(forKey: peripheralHashCodeArgs) else {
|
||||
return
|
||||
}
|
||||
if error == nil {
|
||||
let rssiArgs = rssi.int64Value
|
||||
completion(.success((rssiArgs)))
|
||||
} else {
|
||||
completion(.failure(error!))
|
||||
}
|
||||
}
|
||||
|
||||
func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) {
|
||||
let peripheralHashCode = peripheral.hash
|
||||
guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else {
|
||||
return
|
||||
}
|
||||
let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
if error == nil {
|
||||
var services = peripheral.services ?? []
|
||||
if services.isEmpty {
|
||||
didDiscoverGATT(peripheral, error)
|
||||
} else {
|
||||
let service = services.removeFirst()
|
||||
unfinishedServices[peripheralHashCodeArgs] = services
|
||||
peripheral.discoverCharacteristics(nil, for: service)
|
||||
}
|
||||
} else {
|
||||
didDiscoverGATT(peripheral, error)
|
||||
}
|
||||
}
|
||||
|
||||
func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) {
|
||||
let peripheralHashCode = peripheral.hash
|
||||
guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else {
|
||||
return
|
||||
}
|
||||
let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
if error == nil {
|
||||
var characteristics = service.characteristics ?? []
|
||||
if characteristics.isEmpty {
|
||||
var services = unfinishedServices.removeValue(forKey: peripheralHashCodeArgs) ?? []
|
||||
if services.isEmpty {
|
||||
didDiscoverGATT(peripheral, error)
|
||||
} else {
|
||||
let service = services.removeFirst()
|
||||
unfinishedServices[peripheralHashCodeArgs] = services
|
||||
peripheral.discoverCharacteristics(nil, for: service)
|
||||
}
|
||||
} else {
|
||||
let characteristic = characteristics.removeFirst()
|
||||
unfinishedCharacteristics[peripheralHashCodeArgs] = characteristics
|
||||
peripheral.discoverDescriptors(for: characteristic)
|
||||
}
|
||||
} else {
|
||||
didDiscoverGATT(peripheral, error)
|
||||
}
|
||||
}
|
||||
|
||||
func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) {
|
||||
let peripheralHashCode = peripheral.hash
|
||||
guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else {
|
||||
return
|
||||
}
|
||||
let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
if error == nil {
|
||||
var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralHashCodeArgs) ?? []
|
||||
if (characteristics.isEmpty) {
|
||||
var services = unfinishedServices.removeValue(forKey: peripheralHashCodeArgs) ?? []
|
||||
if services.isEmpty {
|
||||
didDiscoverGATT(peripheral, error)
|
||||
} else {
|
||||
let service = services.removeFirst()
|
||||
unfinishedServices[peripheralHashCodeArgs] = services
|
||||
peripheral.discoverCharacteristics(nil, for: service)
|
||||
}
|
||||
} else {
|
||||
let characteristic = characteristics.removeFirst()
|
||||
unfinishedCharacteristics[peripheralHashCodeArgs] = characteristics
|
||||
peripheral.discoverDescriptors(for: characteristic)
|
||||
}
|
||||
} else {
|
||||
didDiscoverGATT(peripheral, error)
|
||||
}
|
||||
}
|
||||
|
||||
private func didDiscoverGATT(_ peripheral: CBPeripheral, _ error: Error?) {
|
||||
let peripheralHashCode = peripheral.hash
|
||||
guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else {
|
||||
return
|
||||
}
|
||||
let peripheralhashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
guard let completion = discoverGattCompletions.removeValue(forKey: peripheralhashCodeArgs) else {
|
||||
return
|
||||
}
|
||||
if error == nil {
|
||||
let services = peripheral.services ?? []
|
||||
var servicesArgs = [MyGattServiceArgs]()
|
||||
for service in services {
|
||||
let characteristics = service.characteristics ?? []
|
||||
var characteristicsArgs = [MyGattCharacteristicArgs]()
|
||||
for characteristic in characteristics {
|
||||
let descriptors = characteristic.descriptors ?? []
|
||||
var descriptorsArgs = [MyGattDescriptorArgs]()
|
||||
for descriptor in descriptors {
|
||||
let descriptorArgs = descriptor.toArgs()
|
||||
let descriptorHashCode = descriptor.hash
|
||||
let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
self.descriptors[descriptorHashCodeArgs] = descriptor
|
||||
self.descriptorsArgs[descriptorHashCode] = descriptorArgs
|
||||
descriptorsArgs.append(descriptorArgs)
|
||||
}
|
||||
let characteristicArgs = characteristic.toArgs(descriptorsArgs)
|
||||
let characteristicHashCode = characteristic.hash
|
||||
let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
self.characteristics[characteristicHashCodeArgs] = characteristic
|
||||
self.characteristicsArgs[characteristicHashCode] = characteristicArgs
|
||||
characteristicsArgs.append(characteristicArgs)
|
||||
}
|
||||
let serviceArgs = service.toArgs(characteristicsArgs)
|
||||
let serviceHashCode = service.hash
|
||||
let servcieHashCodeArgs = serviceArgs.hashCodeArgs
|
||||
self.services[servcieHashCodeArgs] = service
|
||||
self.servicesArgs[serviceHashCode] = serviceArgs
|
||||
servicesArgs.append(serviceArgs)
|
||||
}
|
||||
servicesArgsOfPeripheralsArgs[peripheralhashCodeArgs] = servicesArgs
|
||||
completion(.success((servicesArgs)))
|
||||
} else {
|
||||
completion(.failure(error!))
|
||||
unfinishedServices.removeValue(forKey: peripheralhashCodeArgs)
|
||||
unfinishedCharacteristics.removeValue(forKey: peripheralhashCodeArgs)
|
||||
}
|
||||
}
|
||||
|
||||
func didUpdateCharacteristicValue(_ characteristic: CBCharacteristic, _ error: Error?) {
|
||||
let characteristicHashCode = characteristic.hash
|
||||
guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else {
|
||||
return
|
||||
}
|
||||
let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
guard let completion = readCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs) else {
|
||||
let value = characteristic.value ?? Data()
|
||||
let valueArgs = FlutterStandardTypedData(bytes: value)
|
||||
api.onCharacteristicValueChanged(characteristicArgs: characteristicArgs, valueArgs: valueArgs) {}
|
||||
return
|
||||
}
|
||||
if error == nil {
|
||||
let value = characteristic.value ?? Data()
|
||||
let valueArgs = FlutterStandardTypedData(bytes: value)
|
||||
completion(.success(valueArgs))
|
||||
} else {
|
||||
completion(.failure(error!))
|
||||
}
|
||||
}
|
||||
|
||||
func didWriteCharacteristicValue(_ characteristic: CBCharacteristic, _ error: Error?) {
|
||||
let characteristicHashCode = characteristic.hash
|
||||
guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else {
|
||||
return
|
||||
}
|
||||
let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
guard let completion = writeCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs) else {
|
||||
return
|
||||
}
|
||||
if error == nil {
|
||||
completion(.success(()))
|
||||
} else {
|
||||
completion(.failure(error!))
|
||||
}
|
||||
}
|
||||
|
||||
func didUpdateNotificationState(_ characteristic: CBCharacteristic, _ error: Error?) {
|
||||
let characteristicHashCode = characteristic.hash
|
||||
guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else {
|
||||
return
|
||||
}
|
||||
let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
guard let completion = notifyCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs) else {
|
||||
return
|
||||
}
|
||||
if error == nil {
|
||||
completion(.success(()))
|
||||
} else {
|
||||
completion(.failure(error!))
|
||||
}
|
||||
}
|
||||
|
||||
func didUpdateDescriptorValue(_ descriptor: CBDescriptor, _ error: Error?) {
|
||||
let descriptorHashCode = descriptor.hash
|
||||
guard let descriptorArgs = descriptorsArgs[descriptorHashCode] else {
|
||||
return
|
||||
}
|
||||
let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
guard let completion = readDescriptorCompletions.removeValue(forKey: descriptorHashCodeArgs) else {
|
||||
return
|
||||
}
|
||||
if error == nil {
|
||||
// TODO: Need to confirm wheather the corresponding descriptor type and value is correct.
|
||||
let valueArgs: FlutterStandardTypedData
|
||||
let value = descriptor.value
|
||||
do {
|
||||
switch descriptor.uuid.uuidString {
|
||||
case CBUUIDCharacteristicExtendedPropertiesString:
|
||||
fallthrough
|
||||
case CBUUIDClientCharacteristicConfigurationString:
|
||||
fallthrough
|
||||
case CBUUIDServerCharacteristicConfigurationString:
|
||||
guard let numberValue = value as? NSNumber else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
valueArgs = FlutterStandardTypedData(bytes: numberValue.data)
|
||||
case CBUUIDCharacteristicUserDescriptionString:
|
||||
fallthrough
|
||||
case CBUUIDCharacteristicAggregateFormatString:
|
||||
guard let stringValue = value as? String else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
valueArgs = FlutterStandardTypedData(bytes: stringValue.data)
|
||||
case CBUUIDCharacteristicFormatString:
|
||||
guard let bytes = value as? Data else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
valueArgs = FlutterStandardTypedData(bytes: bytes)
|
||||
case CBUUIDL2CAPPSMCharacteristicString:
|
||||
guard let uint16Value = value as? UInt16 else {
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
valueArgs = FlutterStandardTypedData(bytes: uint16Value.data)
|
||||
default:
|
||||
throw MyError.illegalArgument
|
||||
}
|
||||
} catch {
|
||||
valueArgs = FlutterStandardTypedData()
|
||||
}
|
||||
completion(.success((valueArgs)))
|
||||
} else {
|
||||
completion(.failure(error!))
|
||||
}
|
||||
}
|
||||
|
||||
func didWriteDescriptorValue(_ descriptor: CBDescriptor, _ error: Error?) {
|
||||
let descriptorHashCode = descriptor.hash
|
||||
guard let descriptorArgs = descriptorsArgs[descriptorHashCode] else {
|
||||
return
|
||||
}
|
||||
let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
guard let completion = writeDescriptorCompletions.removeValue(forKey: descriptorHashCodeArgs) else {
|
||||
return
|
||||
}
|
||||
if error == nil {
|
||||
completion(.success(()))
|
||||
} else {
|
||||
completion(.failure(error!))
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user