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:
Mr剑侠客
2023-10-10 05:01:25 -05:00
committed by GitHub
parent 073c2b9a2e
commit 79c50d638d
113 changed files with 9125 additions and 4560 deletions

View File

@ -1,3 +1,37 @@
## 3.0.0
* Add `PeripheralManager` api.
* Add `CentralManager#readRSSI` method.
* Add `CentralManager.instance` api.
* Add `PeripheralManager.instance` api.
* Move `CentralController` to `CentralManager`.
* Move `CentralState` to `BluetoothLowEnergyState`.
* Move `CentralDiscoveredEventArgs` to `DiscoveredEventArgs`.
* Move `Advertisement` class to `AdvertiseData` class.
* Move `setUp` method from `BluetoothLowEnergy` class to `BluetoothLowEnergyManger` class.
* Change the type of `manufacturerSpecificData` from `Map<int, Uint8List>` to `ManufacturerSpecificData`.
* [Fix the issue that `UUID.fromString()` throw FormatException with 32 bits UUID string.](https://github.com/yanshouwang/bluetooth_low_energy/issues/13)
* Fix known issues.
## 3.0.0-dev.4
* Move `Advertisement` class to `AdvertiseData` class.
## 3.0.0-dev.3
* [Fix the issue that `UUID.fromString()` throw FormatException with 32 bits UUID string.](https://github.com/yanshouwang/bluetooth_low_energy/issues/13)
* Change the type of `manufacturerSpecificData` from `Map<int, Uint8List>` to `ManufacturerSpecificData`.
## 3.0.0-dev.2
* Move `setUp` method from `BluetoothLowEnergy` class to `BluetoothLowEnergyManger` class.
* Add `CentralManager.instance` api.
* Add `PeripheralManager.instance` api.
## 3.0.0-dev.1
* Implement new api.
## 2.2.0
* Add `CentralController#getMaximumWriteLength` method.

View File

@ -17,7 +17,9 @@ public class BluetoothLowEnergyDarwin: NSObject, FlutterPlugin {
#else
#error("Unsupported platform.")
#endif
let centralController = MyCentralController(binaryMessenger)
MyCentralControllerHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: centralController)
let centralManager = MyCentralManager(binaryMessenger)
let peripheralManager = MyPeripheralManager(binaryMessenger)
MyCentralManagerHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: centralManager)
MyPeripheralManagerHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: peripheralManager)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,286 @@
//
// MyApi.swift
// bluetooth_low_energy_darwin
//
// Created by on 2023/9/28.
//
import Foundation
import CoreBluetooth
#if os(iOS)
import Flutter
#elseif os(macOS)
import FlutterMacOS
#else
#error("Unsupported platform.")
#endif
extension CBManagerState {
func toArgs() -> MyBluetoothLowEnergyStateArgs {
switch self {
case .unauthorized:
return .unauthorized
case .poweredOff:
return .poweredOff
case .poweredOn:
return .poweredOn
default:
return .unsupported
}
}
}
extension CBPeer {
var uuidArgs: String { identifier.uuidString }
}
extension CBCentral {
func toArgs() -> MyCentralArgs {
let hashCodeArgs = Int64(hash)
return MyCentralArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs)
}
}
extension CBPeripheral {
func toArgs() -> MyPeripheralArgs {
let hashCodeArgs = Int64(hash)
return MyPeripheralArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs)
}
}
extension CBAttribute {
var uuidArgs: String { uuid.uuidString }
}
extension CBService {
func toArgs(_ characteristicsArgs: [MyGattCharacteristicArgs]) -> MyGattServiceArgs {
let hashCodeArgs = Int64(hash)
return MyGattServiceArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs, characteristicsArgs: characteristicsArgs)
}
}
extension CBCharacteristic {
func toArgs(_ descriptorsArgs: [MyGattDescriptorArgs]) -> MyGattCharacteristicArgs {
let hashCodeArgs = Int64(hash)
return MyGattCharacteristicArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs, propertyNumbersArgs: propertyNumbersArgs, descriptorsArgs: descriptorsArgs)
}
var propertyNumbersArgs: [Int64] {
var propertiesArgs = [MyGattCharacteristicPropertyArgs]()
let properties = self.properties
if properties.contains(.read) {
propertiesArgs.append(.read)
}
if properties.contains(.write) {
propertiesArgs.append(.write)
}
if properties.contains(.writeWithoutResponse) {
propertiesArgs.append(.writeWithoutResponse)
}
if properties.contains(.notify) {
propertiesArgs.append(.notify)
}
if properties.contains(.indicate) {
propertiesArgs.append(.indicate)
}
return propertiesArgs.map { args in Int64(args.rawValue) }
}
}
extension CBDescriptor {
func toArgs() -> MyGattDescriptorArgs {
let hashCodeArgs = Int64(hash)
return MyGattDescriptorArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs)
}
}
extension MyGattCharacteristicWriteTypeArgs {
func toWriteType() -> CBCharacteristicWriteType {
switch self {
case .withResponse:
return .withResponse
case .withoutResponse:
return .withoutResponse
}
}
}
extension String {
var data: Data { data(using: String.Encoding.utf8)! }
}
extension NSNumber {
var data: Data {
var source = self
return Data(bytes: &source, count: MemoryLayout<NSNumber>.size)
}
}
extension UInt16 {
var data: Data {
var source = self
return Data(bytes: &source, count: MemoryLayout<UInt16>.size)
}
}
extension [String: Any] {
func toAdvertiseDataArgs() -> MyAdvertiseDataArgs {
let nameArgs = self[CBAdvertisementDataLocalNameKey] as? String
let serviceUUIDs = self[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] ?? []
let serviceUUIDsArgs = serviceUUIDs.map { uuid in uuid.uuidString }
let serviceData = self[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data] ?? [:]
let serviceDataArgsKeyWithValues = serviceData.map { (uuid, data) in
let uuidArgs = uuid.uuidString
let dataArgs = FlutterStandardTypedData(bytes: data)
return (uuidArgs, dataArgs)
}
let serviceDataArgs = [String?: FlutterStandardTypedData?](uniqueKeysWithValues: serviceDataArgsKeyWithValues)
let manufacturerSpecificData = self[CBAdvertisementDataManufacturerDataKey] as? Data
let manufacturerSpecificDataArgs = manufacturerSpecificData?.toManufacturerSpecificDataArgs()
return MyAdvertiseDataArgs(nameArgs: nameArgs, serviceUUIDsArgs: serviceUUIDsArgs, serviceDataArgs: serviceDataArgs, manufacturerSpecificDataArgs: manufacturerSpecificDataArgs)
}
}
extension Data {
func toManufacturerSpecificDataArgs() -> MyManufacturerSpecificDataArgs? {
if count > 2 {
let idArgs = Int64(self[0]) | (Int64(self[1]) << 8)
let data = self[2...count - 1]
let dataArgs = FlutterStandardTypedData(bytes: data)
return MyManufacturerSpecificDataArgs(idArgs: idArgs, dataArgs: dataArgs)
} else {
return nil
}
}
}
extension MyAdvertiseDataArgs {
func toAdvertiseData() throws -> [String : Any] {
// CoreBluetooth only support `CBAdvertisementDataLocalNameKey` and `CBAdvertisementDataServiceUUIDsKey`, see https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393252-startadvertising
var advertiseData = [String: Any]()
if nameArgs != nil {
let name = nameArgs!
advertiseData[CBAdvertisementDataLocalNameKey] = name
}
if serviceUUIDsArgs.count > 0 {
var serviceUUIDs = [CBUUID]()
for args in serviceUUIDsArgs {
guard let uuidArgs = args else {
throw MyError.illegalArgument
}
let uuid = CBUUID(string: uuidArgs)
serviceUUIDs.append(uuid)
}
advertiseData[CBAdvertisementDataServiceUUIDsKey] = serviceUUIDs
}
// if serviceDataArgs.count > 0 {
// var serviceData = [CBUUID: Data]()
// for args in serviceDataArgs {
// guard let uuidArgs = args.key else {
// throw MyError.illegalArgument
// }
// guard let dataArgs = args.value else {
// throw MyError.illegalArgument
// }
// let uuid = CBUUID(string: uuidArgs)
// let data = dataArgs.data
// serviceData[uuid] = data
// }
// advertiseData[CBAdvertisementDataServiceDataKey] = serviceData
// }
// if manufacturerSpecificDataArgs != nil {
// let manufacturerSpecificData = manufacturerSpecificDataArgs!.toManufacturerSpecificData()
// advertiseData[CBAdvertisementDataManufacturerDataKey] = manufacturerSpecificData
// }
return advertiseData
}
}
//extension MyManufacturerSpecificDataArgs {
// func toManufacturerSpecificData() -> Data {
// let id = UInt16(idArgs).data
// let data = dataArgs.data
// return id + data
// }
//}
extension MyGattServiceArgs {
func toService() -> CBMutableService {
let type = CBUUID(string: uuidArgs)
let primary = true
return CBMutableService(type: type, primary: primary)
}
}
extension MyGattCharacteristicArgs {
func toCharacteristic() -> CBMutableCharacteristic {
let type = CBUUID(string: uuidArgs)
return CBMutableCharacteristic(type: type, properties: properties, value: nil, permissions: permissions)
}
var properties: CBCharacteristicProperties {
var properties: CBCharacteristicProperties = []
for args in propertyNumbersArgs {
guard let rawArgs = args else {
continue
}
let rawValue = Int(rawArgs)
let property = MyGattCharacteristicPropertyArgs(rawValue: rawValue)
switch property {
case .read:
properties.insert(.read)
case .write:
properties.insert(.write)
case .writeWithoutResponse:
properties.insert(.writeWithoutResponse)
case .notify:
properties.insert(.notify)
case .indicate:
properties.insert(.indicate)
default:
continue
}
}
return properties
}
var permissions: CBAttributePermissions {
var permissions: CBAttributePermissions = []
for args in propertyNumbersArgs {
guard let rawArgs = args else {
continue
}
let rawValue = Int(rawArgs)
let property = MyGattCharacteristicPropertyArgs(rawValue: rawValue)
switch property {
case .read:
permissions.insert(.readable)
case .write, .writeWithoutResponse:
permissions.insert(.writeable)
default:
continue
}
}
return permissions
}
}
extension MyGattDescriptorArgs {
func toDescriptor() -> CBMutableDescriptor {
let type = CBUUID(string: uuidArgs)
let value = valueArgs?.data
return CBMutableDescriptor(type: type, value: value)
}
}
extension Dictionary {
mutating func getOrPut(_ key: Key, _ defaultValue: () -> Value) -> Value {
guard let value = self[key] else {
let value1 = defaultValue()
self[key] = value1
return value1
}
return value
}
}

View File

@ -1,737 +0,0 @@
//
// 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 MyCentralController: MyCentralControllerHostApi {
init(_ binaryMessenger: FlutterBinaryMessenger) {
myApi = MyCentralControllerFlutterApi(binaryMessenger: binaryMessenger)
}
private let myApi: MyCentralControllerFlutterApi
private lazy var myCentralManagerDelegate = MyCentralManagerDelegate(self)
private lazy var myPeripheralDelegate = MyPeripheralDelegate(self)
private let centralManager = CBCentralManager()
private var cachedPeripherals = [Int: CBPeripheral]()
private var cachedServices = [Int: [Int: CBService]]()
private var cachedCharacteristics = [Int: [Int: CBCharacteristic]]()
private var cachedDescriptors = [Int: [Int: CBDescriptor]]()
var setUpCompletion: ((Result<MyCentralControllerArgs, Error>) -> Void)?
var connectCompletions = [Int: (Result<Void, Error>) -> Void]()
var disconnectCompletions = [Int: (Result<Void, Error>) -> Void]()
var discoverGattCompletions = [Int: (Result<Void, Error>) -> Void]()
var unfinishedServices = [Int: [CBService]]()
var unfinishedCharacteristics = [Int: [CBCharacteristic]]()
var readCharacteristicCompletions = [Int: (Result<FlutterStandardTypedData, Error>) -> Void]()
var writeCharacteristicCompletions = [Int: (Result<Void, Error>) -> Void]()
var notifyCharacteristicCompletions = [Int: (Result<Void, Error>) -> Void]()
var readDescriptorCompletions = [Int: (Result<FlutterStandardTypedData, Error>) -> Void]()
var writeDescriptorCompletions = [Int: (Result<Void, Error>) -> Void]()
func setUp(completion: @escaping (Result<MyCentralControllerArgs, Error>) -> Void) {
do {
let unfinishedCompletion = setUpCompletion
if unfinishedCompletion != nil {
throw MyError.illegalState
}
centralManager.delegate = myCentralManagerDelegate
if centralManager.state == .unknown {
setUpCompletion = completion
} else {
let myStateArgs = centralManager.state.toMyArgs()
let myStateNumber = Int64(myStateArgs.rawValue)
let myArgs = MyCentralControllerArgs(myStateNumber: myStateNumber)
completion(.success(myArgs))
}
} catch {
completion(.failure(error))
}
}
func tearDown() throws {
centralManager.delegate = nil
if(centralManager.isScanning) {
centralManager.stopScan()
}
for peripheral in cachedPeripherals.values {
peripheral.delegate = nil
if peripheral.state != .disconnected {
centralManager.cancelPeripheralConnection(peripheral)
}
}
cachedPeripherals.removeAll()
cachedServices.removeAll()
cachedCharacteristics.removeAll()
cachedDescriptors.removeAll()
}
func startDiscovery() throws {
let options = [CBCentralManagerScanOptionAllowDuplicatesKey: true]
centralManager.scanForPeripherals(withServices: nil, options: options)
}
func stopDiscovery() throws {
centralManager.stopScan()
}
func connect(myPeripheralKey: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
do {
let peripheralKey = Int(myPeripheralKey)
let unfinishedCompletion = connectCompletions[peripheralKey]
if unfinishedCompletion != nil {
throw MyError.illegalState
}
guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument
}
centralManager.connect(peripheral)
connectCompletions[peripheralKey] = completion
} catch {
completion(.failure(error))
}
}
func disconnect(myPeripheralKey: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
do {
let peripheralKey = Int(myPeripheralKey)
let unfinishedCompletion = disconnectCompletions[peripheralKey]
if unfinishedCompletion != nil {
throw MyError.illegalState
}
guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument
}
centralManager.cancelPeripheralConnection(peripheral)
disconnectCompletions[peripheralKey] = completion
} catch {
completion(.failure(error))
}
}
func getMaximumWriteLength(myPeripheralKey: Int64, myTypeNumber: Int64) throws -> Int64 {
let peripheralKey = Int(myPeripheralKey)
guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument
}
let myTypeRawValue = Int(myTypeNumber)
guard let myTypeArgs = MyGattCharacteristicWriteTypeArgs(rawValue: myTypeRawValue) else {
throw MyError.illegalArgument
}
let type = myTypeArgs.toType()
let maximumWriteLength32 = peripheral.maximumWriteValueLength(for: type)
let maximumWriteLength = Int64(maximumWriteLength32)
return maximumWriteLength
}
func discoverGATT(myPeripheralKey: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
do {
let peripheralKey = Int(myPeripheralKey)
let unfinishedCompletion = discoverGattCompletions[peripheralKey]
if unfinishedCompletion != nil {
throw MyError.illegalState
}
guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument
}
peripheral.discoverServices(nil)
discoverGattCompletions[peripheralKey] = completion
} catch {
completion(.failure(error))
}
}
func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] {
let peripheralKey = Int(myPeripheralKey)
guard let services = cachedServices[peripheralKey] else {
throw MyError.illegalArgument
}
return services.map { (key, service) in
return service.toMyArgs()
}
}
func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] {
let serviceKey = Int(myServiceKey)
guard let characteristics = cachedCharacteristics[serviceKey] else {
throw MyError.illegalArgument
}
return characteristics.map { (key, characteristic) in
return characteristic.toMyArgs()
}
}
func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] {
let characteristicKey = Int(myCharacteristicKey)
guard let descriptors = cachedDescriptors[characteristicKey] else {
throw MyError.illegalArgument
}
return descriptors.map { (key, descriptor) in
return descriptor.toMyArgs()
}
}
func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
do {
let peripheralKey = Int(myPeripheralKey)
guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument
}
let serviceKey = Int(myServiceKey)
guard let characteristics = cachedCharacteristics[serviceKey] else {
throw MyError.illegalArgument
}
let characteristicKey = Int(myCharacteristicKey)
guard let characteristic = characteristics[characteristicKey] else {
throw MyError.illegalArgument
}
let unfinishedCompletion = readCharacteristicCompletions[characteristicKey]
if unfinishedCompletion != nil {
throw MyError.illegalState
}
peripheral.readValue(for: characteristic)
readCharacteristicCompletions[characteristicKey] = completion
} catch {
completion(.failure(error))
}
}
func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
do {
let peripheralKey = Int(myPeripheralKey)
guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument
}
let serviceKey = Int(myServiceKey)
guard let characteristics = cachedCharacteristics[serviceKey] else {
throw MyError.illegalArgument
}
let characteristicKey = Int(myCharacteristicKey)
guard let characteristic = characteristics[characteristicKey] else {
throw MyError.illegalArgument
}
let data = value.data
let myTypeRawValue = Int(myTypeNumber)
guard let myTypeArgs = MyGattCharacteristicWriteTypeArgs(rawValue: myTypeRawValue) else {
throw MyError.illegalArgument
}
let type = myTypeArgs.toType()
let unfinishedCompletion = writeCharacteristicCompletions[characteristicKey]
if unfinishedCompletion != nil {
throw MyError.illegalState
}
peripheral.writeValue(data, for: characteristic, type: type)
writeCharacteristicCompletions[characteristicKey] = completion
} catch {
completion(.failure(error))
}
}
func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
do {
let peripheralKey = Int(myPeripheralKey)
guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument
}
let serviceKey = Int(myServiceKey)
guard let characteristics = cachedCharacteristics[serviceKey] else {
throw MyError.illegalArgument
}
let characteristicKey = Int(myCharacteristicKey)
guard let characteristic = characteristics[characteristicKey] else {
throw MyError.illegalArgument
}
let unfinishedCompletion = notifyCharacteristicCompletions[characteristicKey]
if unfinishedCompletion != nil {
throw MyError.illegalState
}
peripheral.setNotifyValue(state, for: characteristic)
notifyCharacteristicCompletions[characteristicKey] = completion
} catch {
completion(.failure(error))
}
}
func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
do {
let peripheralKey = Int(myPeripheralKey)
guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument
}
let characteristicKey = Int(myCharacteristicKey)
guard let descriptors = cachedDescriptors[characteristicKey] else {
throw MyError.illegalArgument
}
let descriptorKey = Int(myDescriptorKey)
guard let descriptor = descriptors[descriptorKey] else {
throw MyError.illegalArgument
}
let unfinishedCompletion = readDescriptorCompletions[descriptorKey]
if unfinishedCompletion != nil {
throw MyError.illegalState
}
peripheral.readValue(for: descriptor)
readDescriptorCompletions[descriptorKey] = completion
} catch {
completion(.failure(error))
}
}
func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void) {
do {
let peripheralKey = Int(myPeripheralKey)
guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument
}
let characteristicKey = Int(myCharacteristicKey)
guard let descriptors = cachedDescriptors[characteristicKey] else {
throw MyError.illegalArgument
}
let descriptorKey = Int(myDescriptorKey)
guard let descriptor = descriptors[descriptorKey] else {
throw MyError.illegalArgument
}
let data = value.data
let unfinishedCompletion = writeDescriptorCompletions[descriptorKey]
if unfinishedCompletion != nil {
throw MyError.illegalState
}
peripheral.writeValue(data, for: descriptor)
writeDescriptorCompletions[descriptorKey] = completion
} catch {
completion(.failure(error))
}
}
func didUpdateState(_ state: CBManagerState) {
let completion = setUpCompletion
if state != .unknown && completion != nil {
let myStateArgs = state.toMyArgs()
let myStateNumber = Int64(myStateArgs.rawValue)
let myArgs = MyCentralControllerArgs(myStateNumber: myStateNumber)
completion!(.success(myArgs))
setUpCompletion = nil
}
let myStateArgs = state.toMyArgs()
let myStateNumber = Int64(myStateArgs.rawValue)
myApi.onStateChanged(myStateNumber: myStateNumber) {}
}
func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssiNumber: NSNumber) {
let peripheralKey = peripheral.hash
if cachedPeripherals[peripheralKey] == nil {
peripheral.delegate = myPeripheralDelegate
cachedPeripherals[peripheralKey] = peripheral
}
let myPeripheralArgs = peripheral.toMyArgs()
let rssi = rssiNumber.int64Value
let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String
let rawManufacturerSpecificData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data
var manufacturerSpecificData = [Int64: FlutterStandardTypedData]()
if rawManufacturerSpecificData != nil {
do {
guard let data = rawManufacturerSpecificData else {
throw MyError.illegalArgument
}
guard data.count >= 2 else {
throw MyError.illegalArgument
}
let key = Int64(data[0]) | (Int64(data[1]) << 8)
let bytes = data.count > 2 ? data[2...data.count-1] : Data()
let value = FlutterStandardTypedData(bytes: bytes)
manufacturerSpecificData[key] = value
} catch {
manufacturerSpecificData = [:]
}
}
let rawServiceUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] ?? []
let serviceUUIDs = rawServiceUUIDs.map { uuid in uuid.uuidString }
let rawServiceData = advertisementData[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data] ?? [:]
let elements = rawServiceData.map { (uuid, data) in
let key = uuid.uuidString
let value = FlutterStandardTypedData(bytes: data)
return (key, value)
}
let serviceData = [String?: FlutterStandardTypedData?](uniqueKeysWithValues: elements)
let myAdvertisementArgs = MyAdvertisementArgs(name: name, manufacturerSpecificData: manufacturerSpecificData, serviceUUIDs: serviceUUIDs, serviceData: serviceData)
myApi.onDiscovered(myPeripheralArgs: myPeripheralArgs, rssi: rssi, myAdvertisementArgs: myAdvertisementArgs) {}
}
func didConnect(_ peripheral: CBPeripheral) {
let peripheralKey = peripheral.hash
let myPeripheralKey = Int64(peripheralKey)
myApi.onPeripheralStateChanged(myPeripheralKey: myPeripheralKey, state: true) {}
guard let completion = connectCompletions.removeValue(forKey: peripheralKey) else {
return
}
completion(.success(()))
}
func didFailToConnect(_ peripheral: CBPeripheral, _ error: Error?) {
let peripheralKey = peripheral.hash
guard let completion = connectCompletions.removeValue(forKey: peripheralKey) else {
return
}
completion(.failure(error ?? MyError.unknown))
}
func didDisconnectPeripheral(_ peripheral: CBPeripheral, _ error: Error?) {
let peripheralKey = peripheral.hash
let myPeripheralKey = Int64(peripheralKey)
let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralKey)
if discoverGattCompletion != nil {
didDiscoverGATT(peripheral, error ?? MyError.unknown)
}
let services = cachedServices[peripheralKey] ?? [:]
for service in services {
let characteristics = cachedCharacteristics[service.key] ?? [:]
for characteristic in characteristics {
let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristic.key)
let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristic.key)
if readCharacteristicCompletion != nil {
readCharacteristicCompletion!(.failure(MyError.illegalState))
}
if writeCharacteristicCompletion != nil {
writeCharacteristicCompletion!(.failure(MyError.illegalState))
}
let descriptors = cachedDescriptors[characteristic.key] ?? [:]
for descriptor in descriptors {
let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptor.key)
let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptor.key)
if readDescriptorCompletion != nil {
readDescriptorCompletion!(.failure(MyError.illegalState))
}
if writeDescriptorCompletion != nil {
writeDescriptorCompletion!(.failure(MyError.illegalState))
}
}
}
}
myApi.onPeripheralStateChanged(myPeripheralKey: myPeripheralKey, state: false) {}
guard let completion = disconnectCompletions.removeValue(forKey: peripheralKey) else {
return
}
if error == nil {
completion(.success(()))
} else {
completion(.failure(error!))
}
}
func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) {
let peripheralKey = peripheral.hash
if error == nil {
var services = peripheral.services ?? []
if services.isEmpty {
didDiscoverGATT(peripheral, error)
} else {
let service = services.removeFirst()
unfinishedServices[peripheralKey] = services
peripheral.discoverCharacteristics(nil, for: service)
}
} else {
didDiscoverGATT(peripheral, error)
}
}
func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) {
let peripheralKey = peripheral.hash
if error == nil {
var characteristics = service.characteristics ?? []
if characteristics.isEmpty {
var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? []
if services.isEmpty {
didDiscoverGATT(peripheral, error)
} else {
let service = services.removeFirst()
unfinishedServices[peripheralKey] = services
peripheral.discoverCharacteristics(nil, for: service)
}
} else {
let characteristic = characteristics.removeFirst()
unfinishedCharacteristics[peripheralKey] = characteristics
peripheral.discoverDescriptors(for: characteristic)
}
} else {
didDiscoverGATT(peripheral, error)
}
}
func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) {
let peripheralKey = peripheral.hash
if error == nil {
var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralKey) ?? []
if (characteristics.isEmpty) {
var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? []
if services.isEmpty {
didDiscoverGATT(peripheral, error)
} else {
let service = services.removeFirst()
unfinishedServices[peripheralKey] = services
peripheral.discoverCharacteristics(nil, for: service)
}
} else {
let characteristic = characteristics.removeFirst()
unfinishedCharacteristics[peripheralKey] = characteristics
peripheral.discoverDescriptors(for: characteristic)
}
} else {
didDiscoverGATT(peripheral, error)
}
}
private func didDiscoverGATT(_ peripheral: CBPeripheral, _ error: Error?) {
let peripheralKey = peripheral.hash
unfinishedServices.removeValue(forKey: peripheralKey)
unfinishedCharacteristics.removeValue(forKey: peripheralKey)
guard let completion = discoverGattCompletions.removeValue(forKey: peripheralKey) else {
return
}
if error == nil {
let services = peripheral.services ?? []
var cachedServices = [Int: CBService]()
for service in services {
let serviceKey = service.hash
cachedServices[serviceKey] = service
let characteristics = service.characteristics ?? []
var cachedCharacteristics = [Int: CBCharacteristic]()
for characteristic in characteristics {
let characteristicKey = characteristic.hash
cachedCharacteristics[characteristicKey] = characteristic
let descriptors = characteristic.descriptors ?? []
var cachedDescriptors = [Int: CBDescriptor]()
for descriptor in descriptors {
let descriptorKey = descriptor.hash
cachedDescriptors[descriptorKey] = descriptor
}
self.cachedDescriptors[characteristicKey] = cachedDescriptors
}
self.cachedCharacteristics[serviceKey] = cachedCharacteristics
}
self.cachedServices[peripheralKey] = cachedServices
completion(.success(()))
} else {
completion(.failure(error!))
}
}
func didUpdateCharacteristicValue(_ characteristic: CBCharacteristic, _ error: Error?) {
let characteristicKey = characteristic.hash
guard let completion = readCharacteristicCompletions.removeValue(forKey: characteristicKey) else {
let myCharacteristicKey = Int64(characteristicKey)
let rawValue = characteristic.value ?? Data()
let value = FlutterStandardTypedData(bytes: rawValue)
myApi.onCharacteristicValueChanged(myCharacteristicKey: myCharacteristicKey, value: value) {}
return
}
if error == nil {
let rawValue = characteristic.value ?? Data()
let value = FlutterStandardTypedData(bytes: rawValue)
completion(.success(value))
} else {
completion(.failure(error!))
}
}
func didWriteCharacteristicValue(_ characteristic: CBCharacteristic, _ error: Error?) {
let characteristicKey = characteristic.hash
guard let completion = writeCharacteristicCompletions.removeValue(forKey: characteristicKey) else {
return
}
if error == nil {
completion(.success(()))
} else {
completion(.failure(error!))
}
}
func didUpdateNotificationState(_ characteristic: CBCharacteristic, _ error: Error?) {
let characteristicKey = characteristic.hash
guard let completion = notifyCharacteristicCompletions.removeValue(forKey: characteristicKey) else {
return
}
if error == nil {
completion(.success(()))
} else {
completion(.failure(error!))
}
}
func didUpdateDescriptorValue(_ descriptor: CBDescriptor, _ error: Error?) {
let descriptorKey = descriptor.hash
guard let completion = readDescriptorCompletions.removeValue(forKey: descriptorKey) else {
return
}
if error == nil {
// TODO: Need to confirm wheather the corresponding descriptor type and value is correct.
let value: FlutterStandardTypedData
let rawValue = descriptor.value
do {
switch descriptor.uuid.uuidString {
case CBUUIDCharacteristicExtendedPropertiesString:
fallthrough
case CBUUIDClientCharacteristicConfigurationString:
fallthrough
case CBUUIDServerCharacteristicConfigurationString:
guard let rawNumber = rawValue as? NSNumber else {
throw MyError.illegalArgument
}
value = FlutterStandardTypedData(bytes: rawNumber.data)
case CBUUIDCharacteristicUserDescriptionString:
fallthrough
case CBUUIDCharacteristicAggregateFormatString:
guard let rawString = rawValue as? String else {
throw MyError.illegalArgument
}
value = FlutterStandardTypedData(bytes: rawString.data)
case CBUUIDCharacteristicFormatString:
guard let rawData = rawValue as? Data else {
throw MyError.illegalArgument
}
value = FlutterStandardTypedData(bytes: rawData)
case CBUUIDL2CAPPSMCharacteristicString:
guard let rawU16 = rawValue as? UInt16 else {
throw MyError.illegalArgument
}
value = FlutterStandardTypedData(bytes: rawU16.data)
default:
throw MyError.illegalArgument
}
} catch {
value = FlutterStandardTypedData()
}
completion(.success((value)))
} else {
completion(.failure(error!))
}
}
func didWriteDescriptorValue(_ descriptor: CBDescriptor, _ error: Error?) {
let descriptorKey = descriptor.hash
guard let completion = writeDescriptorCompletions.removeValue(forKey: descriptorKey) else {
return
}
if error == nil {
completion(.success(()))
} else {
completion(.failure(error!))
}
}
}
extension CBManagerState {
func toMyArgs() -> MyCentralStateArgs {
switch self {
case .unauthorized:
return .unauthorized
case .poweredOff:
return .poweredOff
case .poweredOn:
return .poweredOn
default:
return .unsupported
}
}
}
extension CBPeripheral {
func toMyArgs() -> MyPeripheralArgs {
let key = Int64(hash)
let uuid = identifier.uuidString
return MyPeripheralArgs(key: key, uuid: uuid)
}
}
extension CBService {
func toMyArgs() -> MyGattServiceArgs {
let key = Int64(hash)
let uuid = uuid.uuidString
return MyGattServiceArgs(key: key, uuid: uuid)
}
}
extension CBCharacteristic {
func toMyArgs() -> MyGattCharacteristicArgs {
let key = Int64(hash)
let uuid = uuid.uuidString
let myPropertyArgses = properties.toMyArgses()
let myPropertyNumbers = myPropertyArgses.map { myPropertyArgs in Int64(myPropertyArgs.rawValue) }
return MyGattCharacteristicArgs(key: key, uuid: uuid, myPropertyNumbers: myPropertyNumbers)
}
}
extension CBDescriptor {
func toMyArgs() -> MyGattDescriptorArgs {
let key = Int64(hash)
let uuid = uuid.uuidString
return MyGattDescriptorArgs(key: key, uuid: uuid)
}
}
extension CBCharacteristicProperties {
func toMyArgses() -> [MyGattCharacteristicPropertyArgs] {
var myPropertyArgs = [MyGattCharacteristicPropertyArgs]()
if contains(.read) {
myPropertyArgs.append(.read)
}
if contains(.write) {
myPropertyArgs.append(.write)
}
if contains(.writeWithoutResponse) {
myPropertyArgs.append(.writeWithoutResponse)
}
if contains(.notify) {
myPropertyArgs.append(.notify)
}
if contains(.indicate) {
myPropertyArgs.append(.indicate)
}
return myPropertyArgs
}
}
extension MyGattCharacteristicWriteTypeArgs {
func toType() -> CBCharacteristicWriteType {
switch self {
case .withResponse:
return .withResponse
case .withoutResponse:
return .withoutResponse
}
}
}
extension NSNumber {
var data: Data {
var source = self
return Data(bytes: &source, count: MemoryLayout<NSNumber>.size)
}
}
extension String {
var data: Data {
return data(using: String.Encoding.utf8)!
}
}
extension UInt16 {
var data: Data {
var source = self
return Data(bytes: &source, count: MemoryLayout<UInt16>.size)
}
}

View File

@ -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!))
}
}
}

View File

@ -9,30 +9,29 @@ import Foundation
import CoreBluetooth
class MyCentralManagerDelegate: NSObject, CBCentralManagerDelegate {
private let myCentralController: MyCentralController
init(_ myCentralController: MyCentralController) {
self.myCentralController = myCentralController
init(_ centralManager: MyCentralManager) {
self.centralManager = centralManager
}
private let centralManager: MyCentralManager
func centralManagerDidUpdateState(_ central: CBCentralManager) {
let state = central.state
myCentralController.didUpdateState(state)
centralManager.didUpdateState()
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
myCentralController.didDiscover(peripheral, advertisementData, RSSI)
centralManager.didDiscover(peripheral, advertisementData, RSSI)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
myCentralController.didConnect(peripheral)
centralManager.didConnect(peripheral)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
myCentralController.didFailToConnect(peripheral, error)
centralManager.didFailToConnect(peripheral, error)
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
myCentralController.didDisconnectPeripheral(peripheral, error)
centralManager.didDisconnectPeripheral(peripheral, error)
}
}

View File

@ -9,41 +9,45 @@ import Foundation
import CoreBluetooth
class MyPeripheralDelegate: NSObject, CBPeripheralDelegate {
private let myCentralController: MyCentralController
private let centralManager: MyCentralManager
init(_ myCentralController: MyCentralController) {
self.myCentralController = myCentralController
init(_ centralManager: MyCentralManager) {
self.centralManager = centralManager
}
func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
centralManager.didReadRSSI(peripheral, RSSI, error)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
myCentralController.didDiscoverServices(peripheral, error)
centralManager.didDiscoverServices(peripheral, error)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
myCentralController.didDiscoverCharacteristics(peripheral, service, error)
centralManager.didDiscoverCharacteristics(peripheral, service, error)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
myCentralController.didDiscoverDescriptors(peripheral, characteristic, error)
centralManager.didDiscoverDescriptors(peripheral, characteristic, error)
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
myCentralController.didUpdateCharacteristicValue(characteristic, error)
centralManager.didUpdateCharacteristicValue(characteristic, error)
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
myCentralController.didWriteCharacteristicValue(characteristic, error)
centralManager.didWriteCharacteristicValue(characteristic, error)
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
myCentralController.didUpdateNotificationState(characteristic, error)
centralManager.didUpdateNotificationState(characteristic, error)
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor descriptor: CBDescriptor, error: Error?) {
myCentralController.didUpdateDescriptorValue(descriptor, error)
centralManager.didUpdateDescriptorValue(descriptor, error)
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
myCentralController.didWriteDescriptorValue(descriptor, error)
centralManager.didWriteDescriptorValue(descriptor, error)
}
}

View File

@ -0,0 +1,375 @@
//
// MyPeripheralManager.swift
// bluetooth_low_energy_darwin
//
// Created by on 2023/10/7.
//
import Foundation
import CoreBluetooth
#if os(iOS)
import Flutter
#elseif os(macOS)
import FlutterMacOS
#else
#error("Unsupported platform.")
#endif
class MyPeripheralManager: MyPeripheralManagerHostApi {
init(_ binaryMessenger: FlutterBinaryMessenger) {
self.binaryMessenger = binaryMessenger
}
private let binaryMessenger: FlutterBinaryMessenger
private let peripheralManager = CBPeripheralManager()
private lazy var api = MyPeripheralManagerFlutterApi(binaryMessenger: binaryMessenger)
private lazy var peripheralManagerDelegate = MyPeripheralManagerDelegate(self)
private var centrals = [Int64: CBCentral]()
private var services = [Int64: CBMutableService]()
private var characteristics = [Int64: CBMutableCharacteristic]()
private var descriptors = [Int64: CBMutableDescriptor]()
private var requests = [Int64: CBATTRequest]()
private var centralsArgs = [Int: MyCentralArgs]()
private var servicesArgs = [Int: MyGattServiceArgs]()
private var characteristicsArgs = [Int: MyGattCharacteristicArgs]()
private var descriptorsArgs = [Int: MyGattDescriptorArgs]()
private var setUpCompletion: ((Result<MyPeripheralManagerArgs, Error>) -> Void)?
private var addServiceCompletion: ((Result<Void, Error>) -> Void)?
private var startAdvertisingCompletion: ((Result<Void, Error>) -> Void)?
private var notifyCharacteristicValueChangedCallbacks = [() -> Void]()
func setUp(completion: @escaping (Result<MyPeripheralManagerArgs, Error>) -> Void) {
do {
if setUpCompletion != nil {
throw MyError.illegalState
}
try tearDown()
peripheralManager.delegate = peripheralManagerDelegate
if peripheralManager.state == .unknown {
setUpCompletion = completion
} else {
let stateArgs = peripheralManager.state.toArgs()
let stateNumberArgs = Int64(stateArgs.rawValue)
let args = MyPeripheralManagerArgs(stateNumberArgs: stateNumberArgs)
completion(.success(args))
}
} catch {
completion(.failure(error))
}
}
func tearDown() throws {
if(peripheralManager.isAdvertising) {
peripheralManager.stopAdvertising()
}
centrals.removeAll()
services.removeAll()
characteristics.removeAll()
descriptors.removeAll()
requests.removeAll()
centralsArgs.removeAll()
servicesArgs.removeAll()
characteristicsArgs.removeAll()
descriptorsArgs.removeAll()
setUpCompletion = nil
addServiceCompletion = nil
startAdvertisingCompletion = nil
notifyCharacteristicValueChangedCallbacks.removeAll()
}
func addService(serviceArgs: MyGattServiceArgs, completion: @escaping (Result<Void, Error>) -> Void) {
do {
if addServiceCompletion != nil {
throw MyError.illegalState
}
let service = serviceArgs.toService()
var characteristics = [CBMutableCharacteristic]()
let characteristicsArgs = serviceArgs.characteristicsArgs
for args in characteristicsArgs {
guard let characteristicArgs = args else {
continue
}
let characteristic = characteristicArgs.toCharacteristic()
var descriptors = [CBMutableDescriptor]()
let descriptorsArgs = characteristicArgs.descriptorsArgs
for args in descriptorsArgs {
guard let descriptorArgs = args else {
continue
}
let descriptor = descriptorArgs.toDescriptor()
descriptors.append(descriptor)
let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
let descriptorHashCode = descriptor.hash
self.descriptorsArgs[descriptorHashCode] = descriptorArgs
self.descriptors[descriptorHashCodeArgs] = descriptor
}
characteristic.descriptors = descriptors
characteristics.append(characteristic)
let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
let characteristicHashCode = characteristic.hash
self.characteristicsArgs[characteristicHashCode] = characteristicArgs
self.characteristics[characteristicHashCodeArgs] = characteristic
}
service.characteristics = characteristics
let serviceHashCodeArgs = serviceArgs.hashCodeArgs
let serviceHashCode = service.hash
self.servicesArgs[serviceHashCode] = serviceArgs
self.services[serviceHashCodeArgs] = service
peripheralManager.add(service)
addServiceCompletion = completion
} catch {
freeService(serviceArgs)
completion(.failure(error))
}
}
func removeService(serviceHashCodeArgs: Int64) throws {
guard let service = services[serviceHashCodeArgs] else {
throw MyError.illegalArgument
}
let serviceHashCode = service.hash
guard let serviceArgs = servicesArgs[serviceHashCode] else {
throw MyError.illegalArgument
}
peripheralManager.remove(service)
freeService(serviceArgs)
}
func clearServices() throws {
peripheralManager.removeAllServices()
let servicesArgs = self.servicesArgs.values
for serviceArgs in servicesArgs {
freeService(serviceArgs)
}
}
private func freeService(_ serviceArgs: MyGattServiceArgs) {
let characteristicsArgs = serviceArgs.characteristicsArgs
for args in characteristicsArgs {
guard let characteristicArgs = args else {
continue
}
let descriptorsArgs = characteristicArgs.descriptorsArgs
for args in descriptorsArgs {
guard let descriptorArgs = args else {
continue
}
let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
guard let descriptor = self.descriptors.removeValue(forKey: descriptorHashCodeArgs) else {
continue
}
let descriptorHashCode = descriptor.hash
self.descriptorsArgs.removeValue(forKey: descriptorHashCode)
}
let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
guard let characteristic = self.characteristics.removeValue(forKey: characteristicHashCodeArgs) else {
continue
}
let characteristicHashCode = characteristic.hash
self.characteristicsArgs.removeValue(forKey: characteristicHashCode)
}
let serviceHashCodeArgs = serviceArgs.hashCodeArgs
guard let service = self.services.removeValue(forKey: serviceHashCodeArgs) else {
return
}
let serviceHashCode = service.hash
self.servicesArgs.removeValue(forKey: serviceHashCode)
}
func startAdvertising(advertiseDataArgs: MyAdvertiseDataArgs, completion: @escaping (Result<Void, Error>) -> Void) {
do {
if startAdvertisingCompletion != nil {
throw MyError.illegalState
}
let advertisementData = try advertiseDataArgs.toAdvertiseData()
peripheralManager.startAdvertising(advertisementData)
startAdvertisingCompletion = completion
} catch {
completion(.failure(error))
}
}
func stopAdvertising() throws {
peripheralManager.stopAdvertising()
}
func getMaximumWriteLength(centralHashCodeArgs: Int64) throws -> Int64 {
guard let central = centrals[centralHashCodeArgs] else {
throw MyError.illegalArgument
}
let maximumWriteLength = central.maximumUpdateValueLength
let maximumWriteLengthArgs = Int64(maximumWriteLength)
return maximumWriteLengthArgs
}
func sendReadCharacteristicReply(centralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, idArgs: Int64, offsetArgs: Int64, statusArgs: Bool, valueArgs: FlutterStandardTypedData) throws {
guard let request = requests[idArgs] else {
throw MyError.illegalArgument
}
request.value = valueArgs.data
let result = statusArgs ? CBATTError.Code.success : CBATTError.Code.requestNotSupported
peripheralManager.respond(to: request, withResult: result)
}
func sendWriteCharacteristicReply(centralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, idArgs: Int64, offsetArgs: Int64, statusArgs: Bool) throws {
guard let request = requests[idArgs] else {
throw MyError.illegalArgument
}
let result = statusArgs ? CBATTError.Code.success : CBATTError.Code.requestNotSupported
peripheralManager.respond(to: request, withResult: result)
}
func notifyCharacteristicValueChanged(centralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, valueArgs: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void) {
do {
if notifyCharacteristicValueChangedCallbacks.count > 0 {
throw MyError.illegalState
}
let value = valueArgs.data
guard let characteristic = characteristics[characteristicHashCodeArgs] else {
throw MyError.illegalArgument
}
guard let central = centrals[centralHashCodeArgs] else {
throw MyError.illegalArgument
}
let centrals = [central]
let updated = peripheralManager.updateValue(value, for: characteristic, onSubscribedCentrals: centrals)
if updated {
completion(.success(()))
} else {
notifyCharacteristicValueChangedCallbacks.append {
let updated = self.peripheralManager.updateValue(value, for: characteristic, onSubscribedCentrals: centrals)
if updated {
completion(.success(()))
} else {
completion(.failure(MyError.unknown))
}
}
}
} catch {
completion(.failure(error))
}
}
func didUpdateState() {
let state = peripheralManager.state
let stateArgs = state.toArgs()
let stateNumberArgs = Int64(stateArgs.rawValue)
if state != .unknown && setUpCompletion != nil {
let args = MyPeripheralManagerArgs(stateNumberArgs: stateNumberArgs)
setUpCompletion!(.success(args))
setUpCompletion = nil
}
api.onStateChanged(stateNumberArgs: stateNumberArgs) {}
}
func didAdd(_ service: CBService, _ error: Error?) {
guard let completion = addServiceCompletion else {
return
}
addServiceCompletion = nil
if error == nil {
completion(.success(()))
} else {
completion(.failure(error!))
let serviceHashCode = service.hash
guard let serviceArgs = servicesArgs[serviceHashCode] else {
return
}
freeService(serviceArgs)
}
}
func didStartAdvertising(_ error: Error?) {
guard let completion = startAdvertisingCompletion else {
return
}
startAdvertisingCompletion = nil
if error == nil {
completion(.success(()))
} else {
completion(.failure(error!))
}
}
func didReceiveRead(_ request: CBATTRequest) {
let central = request.central
let centralHashCode = central.hash
let centralArgs = centralsArgs.getOrPut(centralHashCode) { central.toArgs() }
let centralHashCodeArgs = centralArgs.hashCodeArgs
centrals[centralHashCodeArgs] = central
let characteristic = request.characteristic
let characteristicHashCode = characteristic.hash
guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else {
peripheralManager.respond(to: request, withResult: .attributeNotFound)
return
}
let idArgs = Int64(request.hash)
requests[idArgs] = request
let offsetArgs = Int64(request.offset)
api.onReadCharacteristicCommandReceived(centralArgs: centralArgs, characteristicArgs: characteristicArgs, idArgs: idArgs, offsetArgs: offsetArgs) {}
}
func didReceiveWrite(_ requests: [CBATTRequest]) {
for request in requests {
let central = request.central
let centralHashCode = central.hash
let centralArgs = centralsArgs.getOrPut(centralHashCode) { central.toArgs() }
let centralHashCodeArgs = centralArgs.hashCodeArgs
centrals[centralHashCodeArgs] = central
let characteristic = request.characteristic
let characteristicHashCode = characteristic.hash
guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else {
peripheralManager.respond(to: request, withResult: .attributeNotFound)
return
}
let idArgs = Int64(request.hash)
self.requests[idArgs] = request
let offsetArgs = Int64(request.offset)
guard let value = request.value else {
peripheralManager.respond(to: request, withResult: .requestNotSupported)
return
}
let valueArgs = FlutterStandardTypedData(bytes: value)
api.onWriteCharacteristicCommandReceived(centralArgs: centralArgs, characteristicArgs: characteristicArgs, idArgs: idArgs, offsetArgs: offsetArgs, valueArgs: valueArgs) {}
}
}
func didSubscribeTo(_ central: CBCentral, _ characteristic: CBCharacteristic) {
let centralHashCode = central.hash
let centralArgs = centralsArgs.getOrPut(centralHashCode) { central.toArgs() }
let centralHashCodeArgs = centralArgs.hashCodeArgs
centrals[centralHashCodeArgs] = central
let characteristicHashCode = characteristic.hash
guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else {
return
}
let stateArgs = true
api.onNotifyCharacteristicCommandReceived(centralArgs: centralArgs, characteristicArgs: characteristicArgs, stateArgs: stateArgs) {}
}
func didUnsubscribeFrom(_ central: CBCentral, _ characteristic: CBCharacteristic) {
let centralHashCode = central.hash
let centralArgs = centralsArgs.getOrPut(centralHashCode) { central.toArgs() }
let centralHashCodeArgs = centralArgs.hashCodeArgs
centrals[centralHashCodeArgs] = central
let characteristicHashCode = characteristic.hash
guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else {
return
}
let stateArgs = false
api.onNotifyCharacteristicCommandReceived(centralArgs: centralArgs, characteristicArgs: characteristicArgs, stateArgs: stateArgs) {}
}
func isReadyToUpdateSubscribers() {
let callbacks = notifyCharacteristicValueChangedCallbacks
notifyCharacteristicValueChangedCallbacks.removeAll()
for callback in callbacks {
callback()
}
}
}

View File

@ -0,0 +1,49 @@
//
// MyPeripheralManagerDelegate.swift
// bluetooth_low_energy_darwin
//
// Created by on 2023/10/7.
//
import Foundation
import CoreBluetooth
class MyPeripheralManagerDelegate: NSObject, CBPeripheralManagerDelegate {
init(_ peripheralManager: MyPeripheralManager) {
self.peripheralManager = peripheralManager
}
private let peripheralManager: MyPeripheralManager
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
peripheralManager.didUpdateState()
}
func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
peripheralManager.didAdd(service, error)
}
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
peripheralManager.didStartAdvertising(error)
}
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
peripheralManager.didReceiveRead(request)
}
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
peripheralManager.didReceiveWrite(requests)
}
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
peripheralManager.didSubscribeTo(central, characteristic)
}
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic) {
peripheralManager.didUnsubscribeFrom(central, characteristic)
}
func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
peripheralManager.isReadyToUpdateSubscribers()
}
}

View File

@ -1,9 +1,9 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'src/my_central_controller.dart';
import 'src/my_bluetooth_low_energy.dart';
abstract class BluetoothLowEnergyDarwin {
static void registerWith() {
CentralController.instance = MyCentralController();
BluetoothLowEnergy.instance = MyBluetoothLowEnergy();
}
}

View File

@ -0,0 +1,224 @@
import 'dart:typed_data';
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_gatt_characteristic2.dart';
import 'my_gatt_descriptor2.dart';
import 'my_gatt_service2.dart';
export 'my_api.g.dart';
extension MyBluetoothLowEnergyStateArgsX on MyBluetoothLowEnergyStateArgs {
BluetoothLowEnergyState toState() {
return BluetoothLowEnergyState.values[index];
}
}
extension MyAdvertiseDataArgsX on MyAdvertiseDataArgs {
AdvertiseData toAdvertiseData() {
final name = nameArgs;
final serviceUUIDs = serviceUUIDsArgs
.cast<String>()
.map((args) => UUID.fromString(args))
.toList();
final serviceData = serviceDataArgs.cast<String, Uint8List>().map(
(uuidArgs, dataArgs) {
final uuid = UUID.fromString(uuidArgs);
final data = dataArgs;
return MapEntry(uuid, data);
},
);
final manufacturerSpecificData =
manufacturerSpecificDataArgs?.toManufacturerSpecificData();
return AdvertiseData(
name: name,
serviceUUIDs: serviceUUIDs,
serviceData: serviceData,
manufacturerSpecificData: manufacturerSpecificData,
);
}
}
extension MyManufacturerSpecificDataArgsX on MyManufacturerSpecificDataArgs {
ManufacturerSpecificData toManufacturerSpecificData() {
final id = idArgs;
final data = dataArgs;
return ManufacturerSpecificData(
id: id,
data: data,
);
}
}
extension MyGattCharacteristicPropertyArgsX
on MyGattCharacteristicPropertyArgs {
GattCharacteristicProperty toProperty() {
return GattCharacteristicProperty.values[index];
}
}
extension GattCharacteristicWriteTypeX on GattCharacteristicWriteType {
MyGattCharacteristicWriteTypeArgs toArgs() {
return MyGattCharacteristicWriteTypeArgs.values[index];
}
}
extension MyPeripheralArgsX on MyPeripheralArgs {
Peripheral toPeripheral() {
final hashCode = hashCodeArgs;
final uuid = UUID.fromString(uuidArgs);
return MyPeripheral(
hashCode: hashCode,
uuid: uuid,
);
}
}
extension MyGattServiceArgsX on MyGattServiceArgs {
MyGattService2 toService2() {
final hashCode = hashCodeArgs;
final uuid = UUID.fromString(uuidArgs);
final characteristics = characteristicsArgs
.cast<MyGattCharacteristicArgs>()
.map((args) => args.toCharacteristic2())
.toList();
return MyGattService2(
hashCode: hashCode,
uuid: uuid,
characteristics: characteristics,
);
}
}
extension MyGattCharacteristicArgsX on MyGattCharacteristicArgs {
MyGattCharacteristic2 toCharacteristic2() {
final hashCode = hashCodeArgs;
final uuid = UUID.fromString(uuidArgs);
final properties = propertyNumbersArgs.cast<int>().map(
(args) {
final propertyArgs = MyGattCharacteristicPropertyArgs.values[args];
return propertyArgs.toProperty();
},
).toList();
final descriptors = descriptorsArgs
.cast<MyGattDescriptorArgs>()
.map((args) => args.toDescriptor2())
.toList();
return MyGattCharacteristic2(
hashCode: hashCode,
uuid: uuid,
properties: properties,
descriptors: descriptors,
);
}
}
extension MyGattDescriptorArgsX on MyGattDescriptorArgs {
MyGattDescriptor2 toDescriptor2() {
final hashCode = hashCodeArgs;
final uuid = UUID.fromString(uuidArgs);
return MyGattDescriptor2(
hashCode: hashCode,
uuid: uuid,
);
}
}
extension MyCentralArgsX on MyCentralArgs {
MyCentral toCentral() {
final hashCode = hashCodeArgs;
final uuid = UUID.fromString(uuidArgs);
return MyCentral(
hashCode: hashCode,
uuid: uuid,
);
}
}
extension AdvertiseDataX on AdvertiseData {
MyAdvertiseDataArgs toArgs() {
final nameArgs = name;
final serviceUUIDsArgs =
serviceUUIDs.map((uuid) => uuid.toString()).toList();
final serviceDataArgs = serviceData.map((uuid, data) {
final uuidArgs = uuid.toString();
final dataArgs = data;
return MapEntry(uuidArgs, dataArgs);
});
final manufacturerSpecificDataArgs = manufacturerSpecificData?.toArgs();
return MyAdvertiseDataArgs(
nameArgs: nameArgs,
serviceUUIDsArgs: serviceUUIDsArgs,
serviceDataArgs: serviceDataArgs,
manufacturerSpecificDataArgs: manufacturerSpecificDataArgs,
);
}
}
extension ManufacturerSpecificDataX on ManufacturerSpecificData {
MyManufacturerSpecificDataArgs toArgs() {
final idArgs = id;
final dataArgs = data;
return MyManufacturerSpecificDataArgs(
idArgs: idArgs,
dataArgs: dataArgs,
);
}
}
extension MyGattServiceX on MyGattService {
MyGattServiceArgs toArgs() {
final hashCodeArgs = hashCode;
final uuidArgs = uuid.toString();
final characteristicsArgs = characteristics
.cast<MyGattCharacteristic>()
.map((characteristic) => characteristic.toArgs())
.toList();
return MyGattServiceArgs(
hashCodeArgs: hashCodeArgs,
uuidArgs: uuidArgs,
characteristicsArgs: characteristicsArgs,
);
}
}
extension MyGattCharacteristicX on MyGattCharacteristic {
MyGattCharacteristicArgs toArgs() {
final hashCodeArgs = hashCode;
final uuidArgs = uuid.toString();
final propertyNumbersArgs = properties.map((property) {
final propertyArgs = property.toArgs();
return propertyArgs.index;
}).toList();
final descriptorsArgs = descriptors
.cast<MyGattDescriptor>()
.map((descriptor) => descriptor.toArgs())
.toList();
return MyGattCharacteristicArgs(
hashCodeArgs: hashCodeArgs,
uuidArgs: uuidArgs,
propertyNumbersArgs: propertyNumbersArgs,
descriptorsArgs: descriptorsArgs,
);
}
}
extension MyGattDescriptorX on MyGattDescriptor {
MyGattDescriptorArgs toArgs() {
final hashCodeArgs = hashCode;
final uuidArgs = uuid.toString();
final valueArgs = value;
return MyGattDescriptorArgs(
hashCodeArgs: hashCodeArgs,
uuidArgs: uuidArgs,
valueArgs: valueArgs,
);
}
}
extension GattCharacteristicPropertyX on GattCharacteristicProperty {
MyGattCharacteristicPropertyArgs toArgs() {
return MyGattCharacteristicPropertyArgs.values[index];
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_central_manager.dart';
import 'my_peripheral_manager.dart';
class MyBluetoothLowEnergy extends BluetoothLowEnergy {
@override
final MyCentralManager centralManager;
@override
final MyPeripheralManager peripheralManager;
MyBluetoothLowEnergy()
: centralManager = MyCentralManager(),
peripheralManager = MyPeripheralManager();
}

View File

@ -0,0 +1,39 @@
import 'dart:async';
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'package:flutter/foundation.dart';
abstract class MyBluetoothLowEnergyManager extends BluetoothLowEnergyManager {
MyBluetoothLowEnergyManager()
: _state = BluetoothLowEnergyState.unknown,
_stateChangedController = StreamController.broadcast();
final StreamController<BluetoothLowEnergyStateChangedEventArgs>
_stateChangedController;
BluetoothLowEnergyState _state;
@override
BluetoothLowEnergyState get state => _state;
@protected
set state(BluetoothLowEnergyState value) {
if (_state == value) {
return;
}
_state = value;
final eventArgs = BluetoothLowEnergyStateChangedEventArgs(state);
_stateChangedController.add(eventArgs);
}
@override
Stream<BluetoothLowEnergyStateChangedEventArgs> get stateChanged =>
_stateChangedController.stream;
@protected
Future<void> throwWithoutState(BluetoothLowEnergyState state) async {
if (this.state != state) {
throw BluetoothLowEnergyError(
'$state is expected, but current state is ${this.state}.',
);
}
}
}

View File

@ -1,370 +0,0 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_gatt_characteristic.dart';
import 'my_gatt_descriptor.dart';
import 'my_gatt_service.dart';
import 'my_peripheral.dart';
class MyCentralController extends CentralController
implements MyCentralControllerFlutterApi {
MyCentralController()
: _myApi = MyCentralControllerHostApi(),
_stateChangedController = StreamController.broadcast(),
_discoveredController = StreamController.broadcast(),
_peripheralStateChangedController = StreamController.broadcast(),
_characteristicValueChangedController = StreamController.broadcast(),
_myPeripherals = {},
_myServices = {},
_myCharacteristics = {},
_myDescriptors = {},
_state = CentralState.unknown;
final MyCentralControllerHostApi _myApi;
final StreamController<CentralStateChangedEventArgs> _stateChangedController;
final StreamController<CentralDiscoveredEventArgs> _discoveredController;
final StreamController<PeripheralStateChangedEventArgs>
_peripheralStateChangedController;
final StreamController<GattCharacteristicValueChangedEventArgs>
_characteristicValueChangedController;
final Map<int, MyPeripheral> _myPeripherals;
final Map<int, MyGattService> _myServices;
final Map<int, MyGattCharacteristic> _myCharacteristics;
final Map<int, MyGattDescriptor> _myDescriptors;
CentralState _state;
@override
CentralState get state => _state;
@override
Stream<CentralStateChangedEventArgs> get stateChanged =>
_stateChangedController.stream;
@override
Stream<CentralDiscoveredEventArgs> get discovered =>
_discoveredController.stream;
@override
Stream<PeripheralStateChangedEventArgs> get peripheralStateChanged =>
_peripheralStateChangedController.stream;
@override
Stream<GattCharacteristicValueChangedEventArgs>
get characteristicValueChanged =>
_characteristicValueChangedController.stream;
Future<void> _throwWithState(CentralState state) async {
if (this.state == state) {
throw BluetoothLowEnergyError('$state is unexpected.');
}
}
Future<void> _throwWithoutState(CentralState state) async {
if (this.state != state) {
throw BluetoothLowEnergyError(
'$state is expected, but current state is ${this.state}.',
);
}
}
@override
Future<void> setUp() async {
await _throwWithoutState(CentralState.unknown);
final args = await _myApi.setUp();
final myStateArgs = MyCentralStateArgs.values[args.myStateNumber];
_state = myStateArgs.toState();
MyCentralControllerFlutterApi.setup(this);
}
@override
Future<void> tearDown() async {
await _throwWithState(CentralState.unknown);
await _myApi.tearDown();
MyCentralControllerFlutterApi.setup(null);
_myPeripherals.clear();
_myServices.clear();
_myCharacteristics.clear();
_myDescriptors.clear();
_state = CentralState.unknown;
}
@override
Future<void> startDiscovery() async {
await _throwWithoutState(CentralState.poweredOn);
await _myApi.startDiscovery();
}
@override
Future<void> stopDiscovery() async {
await _throwWithoutState(CentralState.poweredOn);
await _myApi.stopDiscovery();
}
@override
Future<void> connect(Peripheral peripheral) async {
await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral;
await _myApi.connect(myPeripheral.hashCode);
}
@override
Future<void> disconnect(Peripheral peripheral) async {
await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral;
await _myApi.disconnect(myPeripheral.hashCode);
}
@override
Future<int> getMaximumWriteLength(
Peripheral peripheral, {
required GattCharacteristicWriteType type,
}) async {
await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral;
final myTypeArgs = type.toMyArgs();
final myTypeNumber = myTypeArgs.index;
final maximumWriteLength = await _myApi.getMaximumWriteLength(
myPeripheral.hashCode,
myTypeNumber,
);
return maximumWriteLength;
}
@override
Future<void> discoverGATT(Peripheral peripheral) async {
await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral;
await _myApi.discoverGATT(myPeripheral.hashCode);
}
@override
Future<List<GattService>> getServices(Peripheral peripheral) async {
await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral;
final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode);
return myServiceArgses.cast<MyGattServiceArgs>().map(
(myServiceArgs) {
final myService = MyGattService.fromMyArgs(
myPeripheral,
myServiceArgs,
);
_myServices[myService.hashCode] = myService;
return myService;
},
).toList();
}
@override
Future<List<GattCharacteristic>> getCharacteristics(
GattService service,
) async {
await _throwWithoutState(CentralState.poweredOn);
final myService = service as MyGattService;
final myCharactersiticArgses = await _myApi.getCharacteristics(
myService.hashCode,
);
return myCharactersiticArgses.cast<MyGattCharacteristicArgs>().map(
(myCharacteristicArgs) {
final myCharacteristic = MyGattCharacteristic.fromMyArgs(
myService,
myCharacteristicArgs,
);
_myCharacteristics[myCharacteristic.hashCode] = myCharacteristic;
return myCharacteristic;
},
).toList();
}
@override
Future<List<GattDescriptor>> getDescriptors(
GattCharacteristic characteristic,
) async {
await _throwWithoutState(CentralState.poweredOn);
final myCharacteristic = characteristic as MyGattCharacteristic;
final myDescriptorArgses = await _myApi.getDescriptors(
myCharacteristic.hashCode,
);
return myDescriptorArgses.cast<MyGattDescriptorArgs>().map(
(myDescriptorArgs) {
final myDescriptor = MyGattDescriptor.fromMyArgs(
myCharacteristic,
myDescriptorArgs,
);
_myDescriptors[myDescriptor.hashCode] = myDescriptor;
return myDescriptor;
},
).toList();
}
@override
Future<Uint8List> readCharacteristic(
GattCharacteristic characteristic,
) async {
await _throwWithoutState(CentralState.poweredOn);
final myCharacteristic = characteristic as MyGattCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
final value = await _myApi.readCharacteristic(
myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode,
);
return value;
}
@override
Future<void> writeCharacteristic(
GattCharacteristic characteristic, {
required Uint8List value,
required GattCharacteristicWriteType type,
}) async {
await _throwWithoutState(CentralState.poweredOn);
final myCharacteristic = characteristic as MyGattCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
final myTypeArgs = type.toMyArgs();
final myTypeNumber = myTypeArgs.index;
await _myApi.writeCharacteristic(
myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode,
value,
myTypeNumber,
);
}
@override
Future<void> notifyCharacteristic(
GattCharacteristic characteristic, {
required bool state,
}) async {
await _throwWithoutState(CentralState.poweredOn);
final myCharacteristic = characteristic as MyGattCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
await _myApi.notifyCharacteristic(
myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode,
state,
);
}
@override
Future<Uint8List> readDescriptor(GattDescriptor descriptor) async {
await _throwWithoutState(CentralState.poweredOn);
final myDescriptor = descriptor as MyGattDescriptor;
final myCharacteristic = myDescriptor.myCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
final value = await _myApi.readDescriptor(
myPeripheral.hashCode,
myCharacteristic.hashCode,
myDescriptor.hashCode,
);
return value;
}
@override
Future<void> writeDescriptor(
GattDescriptor descriptor, {
required Uint8List value,
}) async {
await _throwWithoutState(CentralState.poweredOn);
final myDescriptor = descriptor as MyGattDescriptor;
final myCharacteristic = myDescriptor.myCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
await _myApi.writeDescriptor(
myPeripheral.hashCode,
myCharacteristic.hashCode,
myDescriptor.hashCode,
value,
);
}
@override
void onStateChanged(int myStateNumber) {
final myStateArgs = MyCentralStateArgs.values[myStateNumber];
final state = myStateArgs.toState();
if (_state == state) {
return;
}
_state = state;
final eventArgs = CentralStateChangedEventArgs(state);
_stateChangedController.add(eventArgs);
}
@override
void onDiscovered(
MyPeripheralArgs myPeripheralArgs,
int rssi,
MyAdvertisementArgs myAdvertisementArgs,
) {
final myPeripheral = MyPeripheral.fromMyArgs(myPeripheralArgs);
_myPeripherals[myPeripheral.hashCode] = myPeripheral;
final advertisement = myAdvertisementArgs.toAdvertisement();
final eventArgs = CentralDiscoveredEventArgs(
myPeripheral,
rssi,
advertisement,
);
_discoveredController.add(eventArgs);
}
@override
void onPeripheralStateChanged(int myPeripheralKey, bool state) {
final myPeripheral = _myPeripherals[myPeripheralKey];
if (myPeripheral == null) {
return;
}
final eventArgs = PeripheralStateChangedEventArgs(myPeripheral, state);
_peripheralStateChangedController.add(eventArgs);
}
@override
void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value) {
final myCharacteristic =
_myCharacteristics[myCharacteristicKey] as MyGattCharacteristic;
final eventArgs = GattCharacteristicValueChangedEventArgs(
myCharacteristic,
value,
);
_characteristicValueChangedController.add(eventArgs);
}
}
extension on MyAdvertisementArgs {
Advertisement toAdvertisement() {
final serviceUUIDs = this
.serviceUUIDs
.cast<String>()
.map((uuid) => UUID.fromString(uuid))
.toList();
final serviceData = this.serviceData.cast<String, Uint8List>().map(
(uuid, data) {
final key = UUID.fromString(uuid);
final value = data;
return MapEntry(key, value);
},
);
return Advertisement(
name: name,
manufacturerSpecificData: manufacturerSpecificData.cast<int, Uint8List>(),
serviceUUIDs: serviceUUIDs,
serviceData: serviceData,
);
}
}
extension on MyCentralStateArgs {
CentralState toState() {
return CentralState.values[index];
}
}
extension on GattCharacteristicWriteType {
MyGattCharacteristicWriteTypeArgs toMyArgs() {
return MyGattCharacteristicWriteTypeArgs.values[index];
}
}

View File

@ -0,0 +1,272 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.dart';
import 'my_bluetooth_low_energy_manager.dart';
import 'my_gatt_characteristic2.dart';
import 'my_gatt_descriptor2.dart';
class MyCentralManager extends MyBluetoothLowEnergyManager
implements CentralManager, MyCentralManagerFlutterApi {
MyCentralManager()
: _api = MyCentralManagerHostApi(),
_discoveredController = StreamController.broadcast(),
_peripheralStateChangedController = StreamController.broadcast(),
_characteristicValueChangedController = StreamController.broadcast();
final MyCentralManagerHostApi _api;
final StreamController<DiscoveredEventArgs> _discoveredController;
final StreamController<PeripheralStateChangedEventArgs>
_peripheralStateChangedController;
final StreamController<GattCharacteristicValueChangedEventArgs>
_characteristicValueChangedController;
@override
Stream<DiscoveredEventArgs> get discovered => _discoveredController.stream;
@override
Stream<PeripheralStateChangedEventArgs> get peripheralStateChanged =>
_peripheralStateChangedController.stream;
@override
Stream<GattCharacteristicValueChangedEventArgs>
get characteristicValueChanged =>
_characteristicValueChangedController.stream;
@override
Future<void> setUp() async {
await throwWithoutState(BluetoothLowEnergyState.unknown);
final args = await _api.setUp();
final stateArgs =
MyBluetoothLowEnergyStateArgs.values[args.stateNumberArgs];
state = stateArgs.toState();
MyCentralManagerFlutterApi.setup(this);
}
@override
Future<void> startDiscovery() async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
await _api.startDiscovery();
}
@override
Future<void> stopDiscovery() async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
await _api.stopDiscovery();
}
@override
Future<void> connect(Peripheral peripheral) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final peripheralHashCodeArgs = peripheral.hashCode;
await _api.connect(peripheralHashCodeArgs);
}
@override
Future<void> disconnect(Peripheral peripheral) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final peripheralHashCodeArgs = peripheral.hashCode;
await _api.disconnect(peripheralHashCodeArgs);
}
@override
Future<int> getMaximumWriteLength(
Peripheral peripheral, {
required GattCharacteristicWriteType type,
}) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final peripheralHashCodeArgs = peripheral.hashCode;
final typeArgs = type.toArgs();
final typeNumberArgs = typeArgs.index;
final maximumWriteLength = await _api.getMaximumWriteLength(
peripheralHashCodeArgs,
typeNumberArgs,
);
return maximumWriteLength;
}
@override
Future<int> readRSSI(Peripheral peripheral) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final peripheralHashCodeArgs = peripheral.hashCode;
final rssi = await _api.readRSSI(peripheralHashCodeArgs);
return rssi;
}
@override
Future<List<GattService>> discoverGATT(Peripheral peripheral) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
if (peripheral is! MyPeripheral) {
throw TypeError();
}
final peripheralHashCodeArgs = peripheral.hashCode;
final servicesArgs = await _api.discoverGATT(peripheralHashCodeArgs);
final services = servicesArgs
.cast<MyGattServiceArgs>()
.map((args) => args.toService2())
.toList();
for (var service in services) {
for (var charactersitic in service.characteristics) {
for (var descriptor in charactersitic.descriptors) {
descriptor.characteristic = charactersitic;
}
charactersitic.service = service;
}
service.peripheral = peripheral;
}
return services;
}
@override
Future<Uint8List> readCharacteristic(
GattCharacteristic characteristic,
) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
if (characteristic is! MyGattCharacteristic2) {
throw TypeError();
}
final service = characteristic.service;
final peripheral = service.peripheral;
final peripheralHashCodeArgs = peripheral.hashCode;
final characteristicHashCodeArgs = characteristic.hashCode;
final value = await _api.readCharacteristic(
peripheralHashCodeArgs,
characteristicHashCodeArgs,
);
return value;
}
@override
Future<void> writeCharacteristic(
GattCharacteristic characteristic, {
required Uint8List value,
required GattCharacteristicWriteType type,
}) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
if (characteristic is! MyGattCharacteristic2) {
throw TypeError();
}
final service = characteristic.service;
final peripheral = service.peripheral;
final peripheralHashCodeArgs = peripheral.hashCode;
final characteristicHashCodeArgs = characteristic.hashCode;
final valueArgs = value;
final typeArgs = type.toArgs();
final typeNumberArgs = typeArgs.index;
await _api.writeCharacteristic(
peripheralHashCodeArgs,
characteristicHashCodeArgs,
valueArgs,
typeNumberArgs,
);
}
@override
Future<void> notifyCharacteristic(
GattCharacteristic characteristic, {
required bool state,
}) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
if (characteristic is! MyGattCharacteristic2) {
throw TypeError();
}
final service = characteristic.service;
final peripheral = service.peripheral;
final peripheralHashCodeArgs = peripheral.hashCode;
final characteristicHashCodeArgs = characteristic.hashCode;
final stateArgs = state;
await _api.notifyCharacteristic(
peripheralHashCodeArgs,
characteristicHashCodeArgs,
stateArgs,
);
}
@override
Future<Uint8List> readDescriptor(GattDescriptor descriptor) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
if (descriptor is! MyGattDescriptor2) {
throw TypeError();
}
final characteristic = descriptor.characteristic;
final service = characteristic.service;
final peripheral = service.peripheral;
final peripheralHashCodeArgs = peripheral.hashCode;
final descriptorHashCodeArgs = descriptor.hashCode;
final value = await _api.readDescriptor(
peripheralHashCodeArgs,
descriptorHashCodeArgs,
);
return value;
}
@override
Future<void> writeDescriptor(
GattDescriptor descriptor, {
required Uint8List value,
}) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
if (descriptor is! MyGattDescriptor2) {
throw TypeError();
}
final characteristic = descriptor.characteristic;
final service = characteristic.service;
final peripheral = service.peripheral;
final peripheralHashCodeArgs = peripheral.hashCode;
final descriptorHashCodeArgs = descriptor.hashCode;
final valueArgs = value;
await _api.writeDescriptor(
peripheralHashCodeArgs,
descriptorHashCodeArgs,
valueArgs,
);
}
@override
void onStateChanged(int stateNumberArgs) {
final stateArgs = MyBluetoothLowEnergyStateArgs.values[stateNumberArgs];
state = stateArgs.toState();
}
@override
void onDiscovered(
MyPeripheralArgs peripheralArgs,
int rssiArgs,
MyAdvertiseDataArgs advertiseDataArgs,
) {
final peripheral = peripheralArgs.toPeripheral();
final rssi = rssiArgs;
final advertiseData = advertiseDataArgs.toAdvertiseData();
final eventArgs = DiscoveredEventArgs(
peripheral,
rssi,
advertiseData,
);
_discoveredController.add(eventArgs);
}
@override
void onPeripheralStateChanged(
MyPeripheralArgs peripheralArgs,
bool stateArgs,
) {
final peripheral = peripheralArgs.toPeripheral();
final state = stateArgs;
final eventArgs = PeripheralStateChangedEventArgs(peripheral, state);
_peripheralStateChangedController.add(eventArgs);
}
@override
void onCharacteristicValueChanged(
MyGattCharacteristicArgs characteristicArgs,
Uint8List valueArgs,
) {
final characteristic = characteristicArgs.toCharacteristic2();
final value = valueArgs;
final eventArgs = GattCharacteristicValueChangedEventArgs(
characteristic,
value,
);
_characteristicValueChangedController.add(eventArgs);
}
}

View File

@ -1,42 +0,0 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_gatt_service.dart';
import 'my_object.dart';
class MyGattCharacteristic extends MyObject implements GattCharacteristic {
final MyGattService myService;
@override
final UUID uuid;
@override
final List<GattCharacteristicProperty> properties;
MyGattCharacteristic(
super.hashCode,
this.myService,
this.uuid,
this.properties,
);
factory MyGattCharacteristic.fromMyArgs(
MyGattService myService,
MyGattCharacteristicArgs myArgs,
) {
final hashCode = myArgs.key;
final uuid = UUID.fromString(myArgs.uuid);
final properties = myArgs.myPropertyNumbers.cast<int>().map(
(myPropertyNumber) {
final myPropertyArgs =
MyGattCharacteristicPropertyArgs.values[myPropertyNumber];
return myPropertyArgs.toProperty();
},
).toList();
return MyGattCharacteristic(hashCode, myService, uuid, properties);
}
}
extension on MyGattCharacteristicPropertyArgs {
GattCharacteristicProperty toProperty() {
return GattCharacteristicProperty.values[index];
}
}

View File

@ -0,0 +1,19 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_gatt_descriptor2.dart';
import 'my_gatt_service2.dart';
class MyGattCharacteristic2 extends MyGattCharacteristic {
late final MyGattService2 service;
MyGattCharacteristic2({
super.hashCode,
required super.uuid,
required super.properties,
required List<MyGattDescriptor2> descriptors,
}) : super(descriptors: descriptors);
@override
List<MyGattDescriptor2> get descriptors =>
super.descriptors.cast<MyGattDescriptor2>();
}

View File

@ -1,22 +0,0 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_gatt_characteristic.dart';
import 'my_object.dart';
class MyGattDescriptor extends MyObject implements GattDescriptor {
final MyGattCharacteristic myCharacteristic;
@override
final UUID uuid;
MyGattDescriptor(super.hashCode, this.myCharacteristic, this.uuid);
factory MyGattDescriptor.fromMyArgs(
MyGattCharacteristic myCharacteristic,
MyGattDescriptorArgs myArgs,
) {
final hashCode = myArgs.key;
final uuid = UUID.fromString(myArgs.uuid);
return MyGattDescriptor(hashCode, myCharacteristic, uuid);
}
}

View File

@ -0,0 +1,12 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_gatt_characteristic2.dart';
class MyGattDescriptor2 extends MyGattDescriptor {
late final MyGattCharacteristic2 characteristic;
MyGattDescriptor2({
super.hashCode,
required super.uuid,
});
}

View File

@ -1,22 +0,0 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_object.dart';
import 'my_peripheral.dart';
class MyGattService extends MyObject implements GattService {
final MyPeripheral myPeripheral;
@override
final UUID uuid;
MyGattService(super.hashCode, this.myPeripheral, this.uuid);
factory MyGattService.fromMyArgs(
MyPeripheral myPeripheral,
MyGattServiceArgs myArgs,
) {
final hashCode = myArgs.key;
final uuid = UUID.fromString(myArgs.uuid);
return MyGattService(hashCode, myPeripheral, uuid);
}
}

View File

@ -0,0 +1,17 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_gatt_characteristic2.dart';
class MyGattService2 extends MyGattService {
late final MyPeripheral peripheral;
MyGattService2({
super.hashCode,
required super.uuid,
required List<MyGattCharacteristic2> characteristics,
}) : super(characteristics: characteristics);
@override
List<MyGattCharacteristic2> get characteristics =>
super.characteristics.cast<MyGattCharacteristic2>();
}

View File

@ -1,11 +0,0 @@
abstract class MyObject {
@override
final int hashCode;
MyObject(this.hashCode);
@override
bool operator ==(Object other) {
return other is MyObject && other.hashCode == hashCode;
}
}

View File

@ -1,17 +0,0 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_object.dart';
class MyPeripheral extends MyObject implements Peripheral {
@override
final UUID uuid;
MyPeripheral(super.hashCode, this.uuid);
factory MyPeripheral.fromMyArgs(MyPeripheralArgs myArgs) {
final hashCode = myArgs.key;
final uuid = UUID.fromString(myArgs.uuid);
return MyPeripheral(hashCode, uuid);
}
}

View File

@ -0,0 +1,228 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.dart';
import 'my_bluetooth_low_energy_manager.dart';
class MyPeripheralManager extends MyBluetoothLowEnergyManager
implements PeripheralManager, MyPeripheralManagerFlutterApi {
final MyPeripheralManagerHostApi _api;
final StreamController<ReadGattCharacteristicCommandEventArgs>
_readCharacteristicCommandReceivedController;
final StreamController<WriteGattCharacteristicCommandEventArgs>
_writeCharacteristicCommandReceivedController;
final StreamController<NotifyGattCharacteristicCommandEventArgs>
_notifyCharacteristicCommandReceivedController;
MyPeripheralManager()
: _api = MyPeripheralManagerHostApi(),
_readCharacteristicCommandReceivedController =
StreamController.broadcast(),
_writeCharacteristicCommandReceivedController =
StreamController.broadcast(),
_notifyCharacteristicCommandReceivedController =
StreamController.broadcast();
@override
Stream<ReadGattCharacteristicCommandEventArgs>
get readCharacteristicCommandReceived =>
_readCharacteristicCommandReceivedController.stream;
@override
Stream<WriteGattCharacteristicCommandEventArgs>
get writeCharacteristicCommandReceived =>
_writeCharacteristicCommandReceivedController.stream;
@override
Stream<NotifyGattCharacteristicCommandEventArgs>
get notifyCharacteristicCommandReceived =>
_notifyCharacteristicCommandReceivedController.stream;
@override
Future<void> setUp() async {
final args = await _api.setUp();
final stateArgs =
MyBluetoothLowEnergyStateArgs.values[args.stateNumberArgs];
state = stateArgs.toState();
MyPeripheralManagerFlutterApi.setup(this);
}
@override
Future<void> addService(GattService service) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
if (service is! MyGattService) {
throw TypeError();
}
final serviceArgs = service.toArgs();
await _api.addService(serviceArgs);
}
@override
Future<void> removeService(GattService service) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final serviceHashCodeArgs = service.hashCode;
await _api.removeService(serviceHashCodeArgs);
}
@override
Future<void> clearServices() async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
await _api.clearServices();
}
@override
Future<void> startAdvertising(AdvertiseData advertiseData) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final advertiseDataArgs = advertiseData.toArgs();
await _api.startAdvertising(advertiseDataArgs);
}
@override
Future<void> stopAdvertising() async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
await _api.stopAdvertising();
}
@override
Future<int> getMaximumWriteLength(Central central) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final centralHashCodeArgs = central.hashCode;
final maximumWriteLength =
await _api.getMaximumWriteLength(centralHashCodeArgs);
return maximumWriteLength;
}
@override
Future<void> sendReadCharacteristicReply(
Central central,
GattCharacteristic characteristic,
int id,
int offset,
bool status,
Uint8List value,
) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final centralHashCodeArgs = central.hashCode;
final characteristicHashCodeArgs = characteristic.hashCode;
final idArgs = id;
final offsetArgs = offset;
final statusArgs = status;
final valueArgs = value;
await _api.sendReadCharacteristicReply(
centralHashCodeArgs,
characteristicHashCodeArgs,
idArgs,
offsetArgs,
statusArgs,
valueArgs,
);
}
@override
Future<void> sendWriteCharacteristicReply(
Central central,
GattCharacteristic characteristic,
int id,
int offset,
bool status,
) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final centralHashCodeArgs = central.hashCode;
final characteristicHashCodeArgs = characteristic.hashCode;
final idArgs = id;
final offsetArgs = offset;
final statusArgs = status;
await _api.sendWriteCharacteristicReply(
centralHashCodeArgs,
characteristicHashCodeArgs,
idArgs,
offsetArgs,
statusArgs,
);
}
@override
Future<void> notifyCharacteristicValueChanged(
Central central,
GattCharacteristic characteristic,
Uint8List value,
) async {
await throwWithoutState(BluetoothLowEnergyState.poweredOn);
final centralHashCodeArgs = central.hashCode;
final characteristicHashCodeArgs = characteristic.hashCode;
final valueArgs = value;
await _api.notifyCharacteristicValueChanged(
centralHashCodeArgs,
characteristicHashCodeArgs,
valueArgs,
);
}
@override
void onStateChanged(int stateNumberArgs) {
final stateArgs = MyBluetoothLowEnergyStateArgs.values[stateNumberArgs];
state = stateArgs.toState();
}
@override
void onReadCharacteristicCommandReceived(
MyCentralArgs centralArgs,
MyGattCharacteristicArgs characteristicArgs,
int idArgs,
int offsetArgs,
) {
final central = centralArgs.toCentral();
final characteristic = characteristicArgs.toCharacteristic2();
final id = idArgs;
final offset = offsetArgs;
final eventArgs = ReadGattCharacteristicCommandEventArgs(
central,
characteristic,
id,
offset,
);
_readCharacteristicCommandReceivedController.add(eventArgs);
}
@override
void onWriteCharacteristicCommandReceived(
MyCentralArgs centralArgs,
MyGattCharacteristicArgs characteristicArgs,
int idArgs,
int offsetArgs,
Uint8List valueArgs,
) {
final central = centralArgs.toCentral();
final characteristic = characteristicArgs.toCharacteristic2();
final id = idArgs;
final offset = offsetArgs;
final value = valueArgs;
final eventArgs = WriteGattCharacteristicCommandEventArgs(
central,
characteristic,
id,
offset,
value,
);
_writeCharacteristicCommandReceivedController.add(eventArgs);
}
@override
void onNotifyCharacteristicCommandReceived(
MyCentralArgs centralArgs,
MyGattCharacteristicArgs characteristicArgs,
bool stateArgs,
) {
final central = centralArgs.toCentral();
final characteristic = characteristicArgs.toCharacteristic2();
final state = stateArgs;
final eventArgs = NotifyGattCharacteristicCommandEventArgs(
central,
characteristic,
state,
);
_notifyCharacteristicCommandReceivedController.add(eventArgs);
}
}

View File

@ -9,124 +9,213 @@ import 'package:pigeon/pigeon.dart';
),
)
@HostApi()
abstract class MyCentralControllerHostApi {
abstract class MyCentralManagerHostApi {
@async
MyCentralControllerArgs setUp();
void tearDown();
MyCentralManagerArgs setUp();
void startDiscovery();
void stopDiscovery();
@async
void connect(int myPeripheralKey);
void connect(int peripheralHashCodeArgs);
@async
void disconnect(int myPeripheralKey);
int getMaximumWriteLength(int myPeripheralKey, int myTypeNumber);
void disconnect(int peripheralHashCodeArgs);
int getMaximumWriteLength(int peripheralHashCodeArgs, int typeNumberArgs);
@async
void discoverGATT(int myPeripheralKey);
List<MyGattServiceArgs> getServices(int myPeripheralKey);
List<MyGattCharacteristicArgs> getCharacteristics(int myServiceKey);
List<MyGattDescriptorArgs> getDescriptors(int myCharacteristicKey);
int readRSSI(int peripheralHashCodeArgs);
@async
List<MyGattServiceArgs> discoverGATT(int peripheralHashCodeArgs);
@async
Uint8List readCharacteristic(
int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey,
int peripheralHashCodeArgs,
int characteristicHashCodeArgs,
);
@async
void writeCharacteristic(
int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey,
Uint8List value,
int myTypeNumber,
int peripheralHashCodeArgs,
int characteristicHashCodeArgs,
Uint8List valueArgs,
int typeNumberArgs,
);
@async
void notifyCharacteristic(
int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey,
bool state,
int peripheralHashCodeArgs,
int characteristicHashCodeArgs,
bool stateArgs,
);
@async
Uint8List readDescriptor(
int myPeripheralKey,
int myCharacteristicKey,
int myDescriptorKey,
int peripheralHashCodeArgs,
int descriptorHashCodeArgs,
);
@async
void writeDescriptor(
int myPeripheralKey,
int myCharacteristicKey,
int myDescriptorKey,
Uint8List value,
int peripheralHashCodeArgs,
int descriptorHashCodeArgs,
Uint8List valueArgs,
);
}
@FlutterApi()
abstract class MyCentralControllerFlutterApi {
void onStateChanged(int myStateNumber);
abstract class MyCentralManagerFlutterApi {
void onStateChanged(int stateNumberArgs);
void onDiscovered(
MyPeripheralArgs myPeripheralArgs,
int rssi,
MyAdvertisementArgs myAdvertisementArgs,
MyPeripheralArgs peripheralArgs,
int rssiArgs,
MyAdvertiseDataArgs advertiseDataArgs,
);
void onPeripheralStateChanged(
MyPeripheralArgs peripheralArgs,
bool stateArgs,
);
void onCharacteristicValueChanged(
MyGattCharacteristicArgs characteristicArgs,
Uint8List valueArgs,
);
void onPeripheralStateChanged(int myPeripheralKey, bool state);
void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value);
}
class MyCentralControllerArgs {
final int myStateNumber;
@HostApi()
abstract class MyPeripheralManagerHostApi {
@async
MyPeripheralManagerArgs setUp();
@async
void addService(MyGattServiceArgs serviceArgs);
void removeService(int serviceHashCodeArgs);
void clearServices();
@async
void startAdvertising(MyAdvertiseDataArgs advertiseDataArgs);
void stopAdvertising();
int getMaximumWriteLength(int centralHashCodeArgs);
void sendReadCharacteristicReply(
int centralHashCodeArgs,
int characteristicHashCodeArgs,
int idArgs,
int offsetArgs,
bool statusArgs,
Uint8List valueArgs,
);
void sendWriteCharacteristicReply(
int centralHashCodeArgs,
int characteristicHashCodeArgs,
int idArgs,
int offsetArgs,
bool statusArgs,
);
@async
void notifyCharacteristicValueChanged(
int centralHashCodeArgs,
int characteristicHashCodeArgs,
Uint8List valueArgs,
);
}
MyCentralControllerArgs(this.myStateNumber);
@FlutterApi()
abstract class MyPeripheralManagerFlutterApi {
void onStateChanged(int stateNumberArgs);
void onReadCharacteristicCommandReceived(
MyCentralArgs centralArgs,
MyGattCharacteristicArgs characteristicArgs,
int idArgs,
int offsetArgs,
);
void onWriteCharacteristicCommandReceived(
MyCentralArgs centralArgs,
MyGattCharacteristicArgs characteristicArgs,
int idArgs,
int offsetArgs,
Uint8List valueArgs,
);
void onNotifyCharacteristicCommandReceived(
MyCentralArgs centralArgs,
MyGattCharacteristicArgs characteristicArgs,
bool stateArgs,
);
}
class MyCentralManagerArgs {
final int stateNumberArgs;
MyCentralManagerArgs(this.stateNumberArgs);
}
class MyPeripheralManagerArgs {
final int stateNumberArgs;
MyPeripheralManagerArgs(this.stateNumberArgs);
}
class MyCentralArgs {
final int hashCodeArgs;
final String uuidArgs;
MyCentralArgs(this.hashCodeArgs, this.uuidArgs);
}
class MyPeripheralArgs {
final int key;
final String uuid;
final int hashCodeArgs;
final String uuidArgs;
MyPeripheralArgs(this.key, this.uuid);
MyPeripheralArgs(this.hashCodeArgs, this.uuidArgs);
}
class MyAdvertisementArgs {
final String? name;
final Map<int?, Uint8List?> manufacturerSpecificData;
final List<String?> serviceUUIDs;
final Map<String?, Uint8List?> serviceData;
class MyAdvertiseDataArgs {
final String? nameArgs;
final List<String?> serviceUUIDsArgs;
final Map<String?, Uint8List?> serviceDataArgs;
final MyManufacturerSpecificDataArgs? manufacturerSpecificDataArgs;
MyAdvertisementArgs(
this.name,
this.manufacturerSpecificData,
this.serviceUUIDs,
this.serviceData,
MyAdvertiseDataArgs(
this.nameArgs,
this.serviceUUIDsArgs,
this.serviceDataArgs,
this.manufacturerSpecificDataArgs,
);
}
class MyGattServiceArgs {
final int key;
final String uuid;
class MyManufacturerSpecificDataArgs {
final int idArgs;
final Uint8List dataArgs;
MyGattServiceArgs(this.key, this.uuid);
MyManufacturerSpecificDataArgs(this.idArgs, this.dataArgs);
}
class MyGattServiceArgs {
final int hashCodeArgs;
final String uuidArgs;
final List<MyGattCharacteristicArgs?> characteristicsArgs;
MyGattServiceArgs(
this.hashCodeArgs,
this.uuidArgs,
this.characteristicsArgs,
);
}
class MyGattCharacteristicArgs {
final int key;
final String uuid;
final List<int?> myPropertyNumbers;
final int hashCodeArgs;
final String uuidArgs;
final List<int?> propertyNumbersArgs;
final List<MyGattDescriptorArgs?> descriptorsArgs;
MyGattCharacteristicArgs(
this.key,
this.uuid,
this.myPropertyNumbers,
this.hashCodeArgs,
this.uuidArgs,
this.propertyNumbersArgs,
this.descriptorsArgs,
);
}
class MyGattDescriptorArgs {
final int key;
final String uuid;
final int hashCodeArgs;
final String uuidArgs;
final Uint8List? valueArgs;
MyGattDescriptorArgs(this.key, this.uuid);
MyGattDescriptorArgs(
this.hashCodeArgs,
this.uuidArgs,
this.valueArgs,
);
}
enum MyCentralStateArgs {
enum MyBluetoothLowEnergyStateArgs {
unknown,
unsupported,
unauthorized,

View File

@ -1,6 +1,6 @@
name: bluetooth_low_energy_darwin
description: iOS and macOS implementation of the bluetooth_low_energy plugin.
version: 2.2.0
version: 3.0.0
homepage: https://github.com/yanshouwang/bluetooth_low_energy
environment:
@ -10,13 +10,13 @@ environment:
dependencies:
flutter:
sdk: flutter
bluetooth_low_energy_platform_interface: ^2.2.0
bluetooth_low_energy_platform_interface: ^3.0.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
pigeon: ^10.1.6
pigeon: ^11.0.1
flutter:
plugin: