BLE in the iOS Simulator
BLESwift 2.1.0 makes BLE work in the iOS Simulator, where CoreBluetooth is non-functional. Purely additive — no breaking API changes.
Added
- Simulator link — new
BLESwiftLink,BLESwiftSimulatorLink, andBLESwiftProviderproducts plus ableswift-providerexecutable. CallSimulatorLink.install()in your simulator build and every subsequently-constructedCentral()/PeripheralHost()is routed over a localhost TCP link to ableswift-providerprocess on the host Mac, which serves it from the Mac's real radio (--passthrough), an in-process virtual radio, or both. Endpoint is configurable viaBLESWIFT_LINK, andSimulatorLink.isProviderReachable()probes for a running provider. See the "Running in the iOS Simulator" DocC article. - Virtual devices — a declarative JSON fixture format (
bleswift-provider --fixture) for virtual devices with advertisements and GATT databases, plusProvider.addVirtualDevice(_:advertising:)for hosting virtual devices written in Swift and driving them through aVirtualDeviceHandle. BackendRegistry(BLESwiftCore) — process-wide optional backend factories consulted byCentral(configuration:)/PeripheralHost(configuration:)when building their default backend. Nothing registered means CoreBluetooth is constructed exactly as before.- BLESwiftExplorer — an Advertise tab driving
PeripheralHost, and--auto-advertise/--auto-scanlaunch arguments for automated runs. - Two-simulator end-to-end test (
Scripts/sim-to-sim-e2e.sh) and CI job: two simulator apps meet on the provider's virtual radio — one advertising, one scanning and connecting — with no Bluetooth hardware and no entitlements.
Fixed
HostSessionno longer counts backend-refused duplicateaddServicerequests againstmaximumHostedServices, so repeated duplicate adds can't exhaust the service budget (#26).CentralSession's L2CAP pump now identity-checks before forwarding inbound bytes, so a torn-down bridge can't write a dead channel's bytes under a re-issued channel id (#27).Provider.addVirtualDeviceregistrations that race an overlappingstop()are rolled back instead of stranding the device on the radio (#29).- A failed
Provider.start()(e.g. port already in use) now rolls back its fixture registrations, so a retry doesn't double-register fixtures and strand vended handles (#30). - Hardened provider session lifecycle and L2CAP bookkeeping (#39), plus review-finding fixes across the virtual radio, composites, and link shutdown (#41).
Known limitation
- The
--passthroughL2CAP path pairs channel-open completions by arrival order per peripheral (CoreBluetooth's callback carries nothing naming the open it answers); a completion arriving after a reconnect-and-reopen can be taken for the new open. Documented in the "Running in the iOS Simulator" article; virtual devices are unaffected (#28).
Full Changelog: 2.0.0...2.1.0