b-d.io / Notes
Reconnect smart glasses like headphones
Users expect glasses to come back on their own, the way earbuds do. Scanning won't get you there.
The problem
Our first version found glasses by scanning for their advertised names. It worked the first time — and then, after the glasses were switched off or walked out of range, it never found them again. Users had to open the vendor's app, let it connect, and come back.
The reason: once glasses are bonded to a phone, they often stop advertising their name (Even G2 does this). A scan for names sees nothing. The vendor app reconnects because it already knows the device; a scanning app doesn't.
The fix: remember the device, keep a pending connection
Bluetooth headphones don't scan — the phone remembers them and waits. You can do the same.
- Remember the peripheral identifiers the first time a session succeeds (for two-arm glasses like Even G2, both arms).
- On launch and after every disconnect, get those peripherals back by ID and call
connecton them — don't wait for a scan to find them. - Leave the connection pending. On iOS a
connectto a known peripheral doesn't time out: the system completes it whenever the glasses come back in range or turn on, even while your app is in the background. - Don't cancel a pending connection on a timeout. Use your attempt timer only for a half-finished connection (one arm connected, the other stuck). If nothing has answered yet, the glasses are simply off — keep waiting.
- Still scan and check already-connected devices as a fallback, for the first pairing and for glasses held by another app.
iOS (CoreBluetooth)
// After a successful session
UserDefaults.standard.set(arms.map { $0.identifier.uuidString }, forKey: "glassesArmIDs")
// On launch / after a disconnect
let ids = (UserDefaults.standard.stringArray(forKey: "glassesArmIDs") ?? [])
.compactMap(UUID.init(uuidString:))
for peripheral in central.retrievePeripherals(withIdentifiers: ids) {
central.connect(peripheral) // stays pending until the glasses are back
}
// Glasses connected by another app don't advertise either:
central.retrieveConnectedPeripherals(withServices: [glassesService, deviceInfo])
To keep this working when your app has been suspended or terminated, declare the bluetooth-central background mode and create the central with a restore identifier. iOS then keeps your pending connections and relaunches your app in the background when the glasses connect.
App Review rejects bluetooth-central if the reviewer can't see a Bluetooth feature in your app. If glasses are an optional add-on in your app, expect questions — a screen recording of the glasses feature helps.
Android
- Look up the remembered devices in
bondedDevicesand connect to them directly, rather than waiting for a scan result. connectGatt(context, autoConnect = true, …)is Android's equivalent of a pending connection: it waits for the device and connects when it appears.- Use a foreground service if the link has to survive your activity going to the background.
Glasses-specific details
- Even G2: two peripherals (left and right arm). Remember both; the session is ready only when both are connected and the handshake has run again. An unbonded phone is dropped after ~29 seconds, so bond first.
Status: this is the approach in the current Odasho build. We'll update this note with field results.