fix(ble): restore peripheral state and keep advertising
This commit is contained in:
@@ -16,6 +16,7 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
||||
static let serviceUUID = CBUUID(string: "A0B0C0D0-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
||||
static let feedTxUUID = CBUUID(string: "A0B0C0D1-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
||||
static let controlRxUUID = CBUUID(string: "A0B0C0D2-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
||||
private static let restoreIdentifier = "iris.ble.peripheral.v1"
|
||||
|
||||
@Published private(set) var bluetoothState: CBManagerState = .unknown
|
||||
@Published var advertisingEnabled: Bool = true
|
||||
@@ -31,7 +32,13 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
||||
@Published private(set) var lastDataAt: Date? = nil
|
||||
|
||||
private let queue = DispatchQueue(label: "iris.ble.peripheral.queue")
|
||||
private lazy var peripheral = CBPeripheralManager(delegate: self, queue: queue)
|
||||
private lazy var peripheral = CBPeripheralManager(
|
||||
delegate: self,
|
||||
queue: queue,
|
||||
options: [
|
||||
CBPeripheralManagerOptionRestoreIdentifierKey: Self.restoreIdentifier,
|
||||
]
|
||||
)
|
||||
|
||||
private var service: CBMutableService?
|
||||
private var feedTx: CBMutableCharacteristic?
|
||||
@@ -111,8 +118,6 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
||||
guard peripheral.state == .poweredOn else { return }
|
||||
guard service == nil else { return }
|
||||
|
||||
peripheral.removeAllServices()
|
||||
|
||||
let feedTx = CBMutableCharacteristic(
|
||||
type: Self.feedTxUUID,
|
||||
properties: [.notify, .read],
|
||||
@@ -139,7 +144,7 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
||||
stopAdvertising()
|
||||
return
|
||||
}
|
||||
if advertisingEnabled, subscribedCentralIds.isEmpty {
|
||||
if advertisingEnabled {
|
||||
startAdvertising()
|
||||
} else {
|
||||
stopAdvertising()
|
||||
@@ -147,16 +152,21 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
||||
}
|
||||
|
||||
private func startAdvertising() {
|
||||
guard !isAdvertising else { return }
|
||||
guard !peripheral.isAdvertising else {
|
||||
publish { self.isAdvertising = true }
|
||||
return
|
||||
}
|
||||
peripheral.startAdvertising([
|
||||
CBAdvertisementDataLocalNameKey: "GlassNow",
|
||||
CBAdvertisementDataServiceUUIDsKey: [Self.serviceUUID],
|
||||
])
|
||||
publish { self.isAdvertising = true }
|
||||
}
|
||||
|
||||
private func stopAdvertising() {
|
||||
guard isAdvertising else { return }
|
||||
guard peripheral.isAdvertising else {
|
||||
publish { self.isAdvertising = false }
|
||||
return
|
||||
}
|
||||
peripheral.stopAdvertising()
|
||||
publish { self.isAdvertising = false }
|
||||
}
|
||||
@@ -313,6 +323,27 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
||||
}
|
||||
|
||||
extension BlePeripheralManager: CBPeripheralManagerDelegate {
|
||||
func peripheralManager(_ peripheral: CBPeripheralManager, willRestoreState dict: [String: Any]) {
|
||||
queue.async { [weak self] in
|
||||
guard let self else { return }
|
||||
|
||||
if let services = dict[CBPeripheralManagerRestoredStateServicesKey] as? [CBService],
|
||||
let restoredService = services.first(where: { $0.uuid == Self.serviceUUID }),
|
||||
let restoredMutableService = restoredService as? CBMutableService,
|
||||
let characteristics = restoredService.characteristics {
|
||||
self.service = restoredMutableService
|
||||
self.feedTx = characteristics.first(where: { $0.uuid == Self.feedTxUUID }) as? CBMutableCharacteristic
|
||||
self.controlRx = characteristics.first(where: { $0.uuid == Self.controlRxUUID }) as? CBMutableCharacteristic
|
||||
}
|
||||
|
||||
self.publish {
|
||||
self.isAdvertising = peripheral.isAdvertising
|
||||
}
|
||||
|
||||
self.applyAdvertisingPolicy()
|
||||
}
|
||||
}
|
||||
|
||||
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
|
||||
queue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
@@ -9,11 +9,13 @@ import SwiftUI
|
||||
|
||||
@main
|
||||
struct irisApp: App {
|
||||
@Environment(\.scenePhase) private var scenePhase
|
||||
@StateObject private var ble: BlePeripheralManager
|
||||
@StateObject private var orchestrator: ContextOrchestrator
|
||||
|
||||
init() {
|
||||
let bleManager = BlePeripheralManager()
|
||||
bleManager.start()
|
||||
_ble = StateObject(wrappedValue: bleManager)
|
||||
_orchestrator = StateObject(wrappedValue: ContextOrchestrator(ble: bleManager))
|
||||
}
|
||||
@@ -23,6 +25,11 @@ struct irisApp: App {
|
||||
ContentView()
|
||||
.environmentObject(ble)
|
||||
.environmentObject(orchestrator)
|
||||
.onChange(of: scenePhase) { phase in
|
||||
if phase == .active || phase == .background {
|
||||
ble.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user