AsyncBluetooth

一个小型库,为 CoreBluetooth API 添加并发功能。

特性

用法

扫描外围设备

通过调用中央管理器的 scanForPeripherals 函数开始扫描。 它返回一个 AsyncStream,您可以使用它来迭代发现的外围设备。 对扫描结果满意后,您可以跳出循环并停止扫描。

let centralManager = CentralManager()

try await centralManager.waitUntilReady()

let scanDataStream = try await centralManager.scanForPeripherals(withServices: nil)
for await scanData in scanDataStream {
    // Check scan data...
}

await centralManager.stopScan()

连接到外围设备

获得外围设备后,您可以使用中央管理器连接到它。 请注意,在连接期间,您必须保持对 Peripheral 的引用。

try await centralManager.connect(peripheral, options: nil)

订阅中央管理器事件

中央管理器发布多个事件。 您可以使用 eventPublisher 订阅这些事件。

centralManager.eventPublisher
    .sink {
        switch $0 {
        case .didConnectPeripheral(let peripheral):
            print("Connected to \(peripheral.identifier)")
        default:
            break
        }
    }
    .store(in: &cancellables)

请参阅 CentralManagerEvent 以查看可用事件。

从特征读取值

您可以使用便捷函数来读取特征。 它们将使用 UUID 查找特征,并将数据解析为适当的类型。

let value: String? = try await peripheral.readValue(
    forCharacteristicWithUUID: UUID(uuidString: "")!,
    ofServiceWithUUID: UUID(uuidString: "")!
)

将值写入特征

与读取类似,我们提供了用于写入特征的便捷函数。

try await peripheral.writeValue(
    value,
    forCharacteristicWithUUID: UUID(uuidString: "")!,
    ofServiceWithUUID: UUID(uuidString: "")!
)

订阅特征

为了在特征的值更新时收到通知,我们提供了一个您可以订阅的发布者。

let characteristicUUID = CBUUID()
peripheral.characteristicValueUpdatedPublisher
    .filter { $0.characteristic.uuid == characteristicUUID }
    .map { try? $0.parsedValue() as String? } // replace `String?` with your type
    .sink { value in
        print("Value updated to '\(value)'")
    }
    .store(in: &cancellables)

请记住,您应该在该特征上启用通知以接收更新的值。

try await peripheral.setNotifyValue(true, characteristicUUID, serviceUUID)

取消操作

要取消特定操作,您可以将您的调用封装在 Task

let fetchTask = Task {
    do {
        return try await peripheral.readValue(
            forCharacteristicWithUUID: UUID(uuidString: "")!,
            ofServiceWithUUID: UUID(uuidString: "")!
        )
    } catch {
        return ""
    }
}

fetchTask.cancel()

可能还存在您想要停止等待所有响应的情况。 例如,当蓝牙已关闭时。 可以这样做

centralManager.eventPublisher
    .sink {
        switch $0 {
        case .didUpdateState(let state):
            guard state == .poweredOff else {
                return
            }
            centralManager.cancelAllOperations()
            peripheral.cancelAllOperations()
        default:
            break
        }
    }
    .store(in: &cancellables)

日志记录

该库使用 os.log 为多个操作提供日志记录。 这些日志默认启用。 如果您希望禁用它们,您可以这样做

AsyncBluetoothLogging.setEnabled(false)

示例

您可以在 AsyncBluetooth Cookbook 中找到有关如何使用 AsyncBluetooth 的实用、美味的食谱。

安装

Swift Package Manager

可以通过将此库添加到您的 Package Dependencies,使用 Swift Package Manager 安装它。

要求

许可证

在 MIT 许可证下授权。