Skip to content

Last updated: 2026-11-10

Everything goes through one object, EvenDevicesNative.instance, and one event stream. Methods return once the request is submitted. The result of a connection, a time sync or a page arrives later as an event. This page uses the Flutter API. For Kotlin and Swift, see Native Android and iOS.

The flow ​

  1. Listen to events.
  2. Ask for Bluetooth permissions.
  3. Initialize with your license file.
  4. Scan and collect both sides of a pair of glasses.
  5. Connect, then wait for the whole device to be ready.
  6. Send commands.

Listen first ​

Subscribe before you call anything else. The SDK does not replay earlier events, so a listener added later misses them.

dart
final sdk = EvenDevicesNative.instance;
final found = <String, Map<String, G2Endpoint>>{};
var ready = false;

final subscription = sdk.events.listen((event) {
  if (event.type == 'discovery' && event.sn != null) {
    final sides = found.putIfAbsent(event.sn!, () => {});
    for (final device in event.devices) {
      sides[device.side] = device;
    }
  }
  if (event.type == 'g2' && event.phase == 'ready' && event.side == null) {
    ready = true;
  }
  if (event.type == 'g2' &&
      (event.phase == 'disconnected' || event.phase == 'failed')) {
    ready = false;
  }
});

Initialize ​

dart
if (!await sdk.requestBluetoothPermissions()) {
  throw StateError('Bluetooth permission denied');
}

await sdk.initialize(
  namespace: accountId,
  licenseJson: await rootBundle.loadString('assets/com.example.app.licenses.json'),
);
  • namespace identifies this session in every event, for example the signed-in user of your app.
  • licenseJson is the whole license file, passed as text. The native SDK validates it and throws a PlatformException if it is invalid.

Scan ​

dart
await sdk.scan();

Each discovery event carries the serial number in sn and the sides found so far in devices, each with its side (left or right), address and name. The two sides may arrive in separate events. A discovered device is not yet authorized.

Stop scanning with await sdk.stopScan().

Connect ​

Once both sides of a serial number have appeared, connect:

dart
final sides = found[sn]!;
await sdk.connectG2(sn: sn, left: sides['left'], right: sides['right']);
  • Android needs both scanned sides.
  • iOS takes both sides or neither. With neither, it looks them up from its own scan results. Passing only one side is rejected.

The SDK picks the license for that exact serial number from your license file and checks it on each side, then authenticates. A serial number with no license in the file is refused before any connection starts.

Ready ​

Each side reports its progress in g2 events with side set to left or right. The whole device is ready when a g2 event arrives with phase == 'ready' and side == null. Send commands only after that event.

phaseMeaning
waitingForForegroundiOS: waiting for the app to come to the foreground
connectingBluetooth connection in progress
enterpriseAuthorizingThe glasses are checking your license
businessAuthenticatingAuthentication after the license check
retryingA side is retrying
readyWith side == null: the whole device is ready
disconnectedThe connection ended
failedThe attempt failed; the reason is in failure

Time sync ​

After the device is ready, set the glasses clock from the phone:

dart
await sdk.syncG2Time();

The result arrives as a timeSync event with success, and failure when it did not succeed. The SDK refuses a time sync while an EvenHub page is open.

Update licenses ​

After you add devices in the portal, download the license file again and pass it in:

dart
await sdk.updateLicenses(newLicenseJson);

The SDK validates the whole file before replacing the old one. New connections use the new file.

Disconnect and reset ​

dart
await sdk.disconnectG2();
await sdk.reset();
await subscription.cancel();
  • Call reset() when the user signs out, switches accounts or the app shuts down. It tears down the native session and its pending callbacks.
  • Cancelling the subscription only removes your listener. It does not disconnect the glasses.
  • Use one EvenDevicesNative.instance per process, from a single Flutter engine.

Events ​

typeCarries
discoverySerial number and the sides found, before any authorization
g2Connection and license-check progress per side, and the whole-device ready
timeSyncThe result of syncG2Time()
evenHubPage lifecycle, user input and microphone audio, see EvenHub pages
otaFirmware update phase, operation ID and progress, see Firmware updates
transport, businessPlatform diagnostics; never a sign of readiness

Events also carry namespace, sn and side where they apply, and details, a map with every field the native SDK sent.