Guides

Background sessions

Keep a Meta Ray-Ban session alive when your app backgrounds — the Android foreground service for mic, iOS background modes, and which capabilities survive.

By default, capability subscriptions (glasses.audio.*, the assistant) run on the SDK's coroutine scope, which is bound to your process — not to any Activity. While your app is foreground, that's enough. To keep the glasses listening (a voice assistant or live transcription) while your app is backgrounded, you need an OS-level keep-alive: a foreground service on Android, background modes on iOS. This guide covers what's required, what survives, and what doesn't.

Kotlin leads the snippets. Android uses the bundled foreground service; iOS uses background modes — a genuinely different OS mechanism, covered in its own section below.

What "background session" means

The glasses connection itself doesn't end the moment your app loses focus — but the OS will reclaim a backgrounded process (and with it your ExtentosGlasses instance and its transport) under memory pressure or after enough time, unless you hold a foreground service or background-mode budget. So "keeping the session alive" is really "keeping your process alive and the audio path running while backgrounded."

This is a separate concern from handling a disconnect when it does happen — see handle disconnects for the recovery path.

Android: the bundled foreground service

For background-surviving microphone capture, the library ships a foreground service so you don't write one:

import com.extentos.glasses.core.service.GlassesForegroundService

// AFTER RECORD_AUDIO is granted at runtime — typically in the grant callback:
GlassesForegroundService.start(this)   // 'this' is any Context

// When background capture is no longer needed:
GlassesForegroundService.stop(this)

The service is declared for you in the library manifest as:

<service
    android:name="com.extentos.glasses.core.service.GlassesForegroundService"
    android:foregroundServiceType="microphone"
    android:exported="false" />

You don't declare it — you start it. The rules that matter (see Android lifecycle and manifest setup):

  • Permission first. RECORD_AUDIO must already be granted at runtime. On Android 14+, starting a microphone-type foreground service without the grant throws SecurityException at service-create time and crashes the app.
  • Declare the foreground-service permissions. Your app's manifest needs FOREGROUND_SERVICE and FOREGROUND_SERVICE_MICROPHONE (Android 14+) — getPermissions derives these from your continuous-capture capabilities. The library declares the <service> element; the permissions are app-owned.
  • Start from an Activity, not Application.onCreate. The grant can't exist that early. Start it from your permission-grant callback, or after a checkSelfPermission(...) == PERMISSION_GRANTED check.
  • Idempotent. Calling start again while running just updates the notification.
  • Stop it when done to drop the notification and release the foreground budget.

Camera in the background is not covered by the bundled service. GlassesForegroundService is microphone-type only. Surviving a videoFrames() stream in the background requires a camera-type foreground service, which Android requires the consumer app to declare itself (the library can't declare a camera FGS on your behalf without forcing it on every app). Subclass GlassesForegroundService and declare your own <service android:foregroundServiceType="camera" /> with the matching runtime rules. Most apps only need background mic.

iOS: background modes

iOS doesn't use foreground services — a backgrounded app keeps running only within a declared background mode budget. For an audio-driven glasses session, the relevant UIBackgroundModes entries (bluetooth-central, bluetooth-peripheral, external-accessory — plus audio, which you must add yourself when you stream the mic; generateConnectionModule emits only the three Bluetooth/accessory modes) must be present in Info.plist; generateConnectionModule(platform: "ios") includes the background-mode and UISupportedExternalAccessoryProtocols keys. iOS background execution is more constrained than an Android foreground service — validate background behavior on a real device before relying on it.

What survives backgrounding

CapabilityBackgrounded behavior
glasses.audio.transcriptions() / recordDiscrete() / the assistantSurvives with the foreground service (Android) / audio background mode (iOS) running. Without it, capture stops when the process is reclaimed.
glasses.audio.speak()Plays while the audio path is alive; same keep-alive requirement.
glasses.camera.*Needs a consumer-declared camera-type FGS on Android (not the bundled mic service).
The connection statePersists while the process lives; on process death you re-create(...) and reconnect — see process death. The dev-loop pairing identity is persisted to filesDir, but the live connection is re-established from scratch.

Camera-only or strictly foreground apps don't need any of this — the foreground-service declaration is harmless if unused.

Honest limits

  • The OS can still kill you. A foreground service and background modes reduce — they don't eliminate — OS reclamation. Under hard memory pressure or aggressive battery-saver/OEM policies, a backgrounded session can still be terminated. Design for it: observe glasses.connection.state, handle the Disconnected cause, and reconnect cleanly. See handle disconnects.
  • Battery cost is real. A live mic + Bluetooth audio path in the background drains both the phone and the glasses. Start the service only while you actually need background capture, and stop it as soon as you don't.
  • Sim ≠ hardware here. The browser simulator does not exercise OS background lifecycle at all — there's no foreground service, no battery-saver kill, no process reclamation in a browser tab. A session that "stays alive when backgrounded" in the simulator tells you nothing about real-device background survival. Verify backgrounding on real hardware.