payfrit-beacon-ios/PayfritBeacon/Provisioners/FallbackProvisioner.swift
Schwifty c243235237 fix: connection callback bug + add provisioning diagnostics
BIG FIX: Provisioners were calling centralManager.connect() but
BLEManager is the CBCentralManagerDelegate — provisioners never
received didConnect/didFailToConnect callbacks, so connections
ALWAYS timed out after 5s regardless. This is why provisioning
kept failing. Fixed by:
1. Adding didConnect/didFailToConnect/didDisconnect to BLEManager
2. Provisioners register connection callbacks via bleManager
3. Increased connection timeout from 5s to 10s

DIAGNOSTICS: Added ProvisionLog system so failures show a timestamped
step-by-step log of what happened (with Share button). Every phase
is logged: init, API calls, connect attempts, service discovery,
auth, write commands, and errors.
2026-03-22 23:12:06 +00:00

77 lines
2.7 KiB
Swift

import Foundation
import CoreBluetooth
/// Tries KBeacon DXSmart BlueCharm in sequence for unknown beacon types.
/// Matches Android's fallback behavior when beacon type can't be determined.
final class FallbackProvisioner: BeaconProvisioner {
private let peripheral: CBPeripheral
private let centralManager: CBCentralManager
private var activeProvisioner: (any BeaconProvisioner)?
private(set) var isConnected: Bool = false
var diagnosticLog: ProvisionLog?
var bleManager: BLEManager?
init(peripheral: CBPeripheral, centralManager: CBCentralManager) {
self.peripheral = peripheral
self.centralManager = centralManager
}
func connect() async throws {
let provisioners: [() -> any BeaconProvisioner] = [
{ [self] in
var p = KBeaconProvisioner(peripheral: peripheral, centralManager: centralManager)
p.diagnosticLog = diagnosticLog
p.bleManager = bleManager
return p
},
{ [self] in
var p = DXSmartProvisioner(peripheral: peripheral, centralManager: centralManager)
p.diagnosticLog = diagnosticLog
p.bleManager = bleManager
return p
},
{ [self] in
var p = BlueCharmProvisioner(peripheral: peripheral, centralManager: centralManager)
p.diagnosticLog = diagnosticLog
p.bleManager = bleManager
return p
},
]
let typeNames = ["KBeacon", "DXSmart", "BlueCharm"]
var lastError: Error = ProvisionError.connectionTimeout
for (index, makeProvisioner) in provisioners.enumerated() {
await diagnosticLog?.log("fallback", "Trying \(typeNames[index]) provisioner…")
let provisioner = makeProvisioner()
do {
try await provisioner.connect()
activeProvisioner = provisioner
isConnected = true
await diagnosticLog?.log("fallback", "\(typeNames[index]) connected successfully")
return
} catch {
provisioner.disconnect()
lastError = error
await diagnosticLog?.log("fallback", "\(typeNames[index]) failed: \(error.localizedDescription)", isError: true)
}
}
throw lastError
}
func writeConfig(_ config: BeaconConfig) async throws {
guard let provisioner = activeProvisioner else {
throw ProvisionError.notConnected
}
try await provisioner.writeConfig(config)
}
func disconnect() {
activeProvisioner?.disconnect()
activeProvisioner = nil
isConnected = false
}
}