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:
286
bluetooth_low_energy_darwin/darwin/Classes/MyApi.swift
Normal file
286
bluetooth_low_energy_darwin/darwin/Classes/MyApi.swift
Normal 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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user