diff --git a/README.md b/README.md index c71ad9a..580d875 100644 --- a/README.md +++ b/README.md @@ -425,6 +425,35 @@ func setupLogging() { } ``` +## Advanced Features + +### Escape Hatch: Accessing CoreBluetooth Objects + +For advanced use cases, you can access underlying CoreBluetooth objects directly: + +```swift +@MainActor +func useEscapeHatch() async throws { + let central = BluetoothCentral() + let devices = try await central.scanForPeripherals(timeout: 5.0) + guard let device = devices.first else { return } + let peripheral = try await central.connect(device, timeout: 10.0) + + // Access underlying CBPeripheral + let cbPeripheral = peripheral.underlyingPeripheral() + let maxWriteLength = cbPeripheral.maximumWriteValueLength(for: .withResponse) +} +``` + +**Available methods:** +- `underlyingCentralManager()` → `CBCentralManager?` +- `underlyingPeripheral(for:)` → `CBPeripheral?` +- `underlyingPeripheral()` → `CBPeripheral` +- `underlyingService()` → `CBService` +- `underlyingCharacteristic()` → `CBCharacteristic` + +⚠️ **Warning**: Bypasses actor-based safety. Don't modify delegates or use for primary API operations. + ## Installation ### Swift Package Manager diff --git a/Sources/ActorCoreBluetooth/BluetoothCentral.swift b/Sources/ActorCoreBluetooth/BluetoothCentral.swift index fb89f56..3d7b6ea 100644 --- a/Sources/ActorCoreBluetooth/BluetoothCentral.swift +++ b/Sources/ActorCoreBluetooth/BluetoothCentral.swift @@ -644,6 +644,20 @@ public final class BluetoothCentral { logger?.centralNotice("BluetoothCentral cleanup completed") } + // MARK: - Escape Hatch: CoreBluetooth Object Access + + /// Access the underlying CBCentralManager for advanced use cases. + /// - Warning: Bypasses actor-based safety. Don't modify delegates. + public func underlyingCentralManager() -> CBCentralManager? { + return cbCentralManager + } + + /// Access the underlying CBPeripheral for a connected peripheral. + /// - Warning: Bypasses actor-based safety. Don't modify delegates. + public func underlyingPeripheral(for peripheralID: UUID) -> CBPeripheral? { + return connectedPeripherals[peripheralID] + } + // MARK: - Internal Delegate Handling Methods /// Handle peripheral state changes, managing both operation completion and state monitoring diff --git a/Sources/ActorCoreBluetooth/ConnectedPeripheral.swift b/Sources/ActorCoreBluetooth/ConnectedPeripheral.swift index b8596e9..87c12b7 100644 --- a/Sources/ActorCoreBluetooth/ConnectedPeripheral.swift +++ b/Sources/ActorCoreBluetooth/ConnectedPeripheral.swift @@ -570,6 +570,14 @@ public final class ConnectedPeripheral { return servicesWithCharacteristics } + // MARK: - Escape Hatch: CoreBluetooth Object Access + + /// Access the underlying CBPeripheral for advanced use cases. + /// - Warning: Bypasses actor-based safety. Don't modify delegates. + public func underlyingPeripheral() -> CBPeripheral { + return cbPeripheral + } + // MARK: - Internal Delegate Handling Methods // Called by delegate proxy when services are discovered diff --git a/Sources/ActorCoreBluetooth/SendableWrappers/BluetoothCharacteristic.swift b/Sources/ActorCoreBluetooth/SendableWrappers/BluetoothCharacteristic.swift index d425ff3..db30832 100644 --- a/Sources/ActorCoreBluetooth/SendableWrappers/BluetoothCharacteristic.swift +++ b/Sources/ActorCoreBluetooth/SendableWrappers/BluetoothCharacteristic.swift @@ -23,4 +23,12 @@ public struct BluetoothCharacteristic: Sendable { self.value = cbCharacteristic.value self.cbCharacteristic = Unchecked(cbCharacteristic) } + + // MARK: - Escape Hatch: CoreBluetooth Object Access + + /// Access the underlying CBCharacteristic for advanced use cases. + /// - Warning: Bypasses actor-based safety. + public func underlyingCharacteristic() -> CBCharacteristic { + return cbCharacteristic.value + } } diff --git a/Sources/ActorCoreBluetooth/SendableWrappers/BluetoothService.swift b/Sources/ActorCoreBluetooth/SendableWrappers/BluetoothService.swift index a66b485..35f4ac2 100644 --- a/Sources/ActorCoreBluetooth/SendableWrappers/BluetoothService.swift +++ b/Sources/ActorCoreBluetooth/SendableWrappers/BluetoothService.swift @@ -23,4 +23,12 @@ public struct BluetoothService: Sendable { self.characteristics = characteristics self.cbService = Unchecked(cbService) } + + // MARK: - Escape Hatch: CoreBluetooth Object Access + + /// Access the underlying CBService for advanced use cases. + /// - Warning: Bypasses actor-based safety. + public func underlyingService() -> CBService { + return cbService.value + } } diff --git a/Sources/ActorCoreBluetooth/SendableWrappers/DiscoveredPeripheral.swift b/Sources/ActorCoreBluetooth/SendableWrappers/DiscoveredPeripheral.swift index 376cef3..f7a3d30 100644 --- a/Sources/ActorCoreBluetooth/SendableWrappers/DiscoveredPeripheral.swift +++ b/Sources/ActorCoreBluetooth/SendableWrappers/DiscoveredPeripheral.swift @@ -25,4 +25,12 @@ public struct DiscoveredPeripheral: Sendable { self.advertisementData = AdvertisementData(cbAdvertisementData: advertisementData) self.cbPeripheral = Unchecked(cbPeripheral) } + + // MARK: - Escape Hatch: CoreBluetooth Object Access + + /// Access the underlying CBPeripheral for advanced use cases. + /// - Warning: Bypasses actor-based safety. Don't modify delegates. + public func underlyingPeripheral() -> CBPeripheral { + return cbPeripheral.value + } }