Public API - Practical Examples
All examples below assume:
import 'package:flutter/foundation.dart';
import 'package:eixam_connect_flutter/eixam_connect_flutter.dart';
late final EixamConnectSdk sdk;
These examples focus on the fields partner apps usually inspect in practice.
Bootstrap
These examples assume the signed session was created by the partner backend, not inside the mobile client.
bootstrap
final sdk = await EixamConnectSdk.bootstrap(
const EixamBootstrapConfig(
appId: 'partner-app',
environment: EixamEnvironment.sandbox,
initialSession: EixamSession.signed(
appId: 'partner-app',
externalUserId: 'partner-user-123',
userHash: 'signed-session-hash',
),
),
);
final session = await sdk.getCurrentSession();
debugPrint('user=${session?.externalUserId}');
For custom environments, a secure broker example currently looks like:
const EixamCustomEndpoints(
apiBaseUrl: 'https://partner-api.example.com',
mqttUrl: 'ssl://mqtt.staging.eixam.io:8883',
)
If your environment uses ws:// or wss:// instead, treat that as a transport-dependent alternative rather than the default staging recommendation.
The signed session is reused across both transports:
- HTTP uses
Authorization: Bearer <userHash> - MQTT uses
username = sdk:<appId>:<externalUserId>andpassword = <userHash>
Diagnostics
getOperationalDiagnostics
Returns SdkOperationalDiagnostics.
final diagnostics = await sdk.getOperationalDiagnostics();
debugPrint('mqtt=${diagnostics.connectionState.name}');
debugPrint('telTopic=${diagnostics.telemetryPublishTopic}');
debugPrint('lastDecision=${diagnostics.bridge.lastDecision}');
debugPrint('hasPendingSos=${diagnostics.bridge.pendingSos != null}');
watchOperationalDiagnostics
Returns Stream<SdkOperationalDiagnostics>.
final sub = sdk.watchOperationalDiagnostics().listen((diagnostics) {
debugPrint('mqtt=${diagnostics.connectionState.name}');
debugPrint('bleTel=${diagnostics.bridge.lastBleTelemetryEventSummary}');
debugPrint('bleSos=${diagnostics.bridge.lastBleSosEventSummary}');
});
Device Lifecycle
connectDevice
Returns DeviceStatus.
final status = await sdk.connectDevice(pairingCode: '123456');
debugPrint('device=${status.deviceId}');
debugPrint('lifecycle=${status.lifecycleState.name}');
debugPrint('ready=${status.isReadyForSafety}');
getDeviceStatus
Returns DeviceStatus.
final status = await sdk.getDeviceStatus();
debugPrint('connected=${status.connected}');
debugPrint('firmware=${status.firmwareVersion}');
debugPrint('battery=${status.approximateBatteryPercentage}');
deviceStatusStream
Returns Stream<DeviceStatus>.
final sub = sdk.deviceStatusStream.listen((status) {
debugPrint('lifecycle=${status.lifecycleState.name}');
debugPrint('connected=${status.connected}');
debugPrint('signal=${status.signalQuality}');
});
getDeviceSosStatus
Returns DeviceSosStatus.
final status = await sdk.getDeviceSosStatus();
debugPrint('state=${status.state.name}');
debugPrint('event=${status.lastEvent}');
debugPrint('countdown=${status.countdownRemainingSeconds}');
SOS
triggerSos
Returns SosIncident.
final incident = await sdk.triggerSos(
const SosTriggerPayload(
message: 'Need assistance',
triggerSource: 'button_ui',
),
);
debugPrint('incident=${incident.id}');
debugPrint('state=${incident.state.name}');
When the SDK has a paired device hardware id, the operational SOS payload may include:
{
"timestamp": "2026-03-30T12:00:00.000Z",
"latitude": 41.38,
"longitude": 2.17,
"altitude": 8.0,
"userId": "partner-user-123",
"deviceId": "hw-1"
}
For hardware-originated SOS, deviceId should be the paired device hardware_id. If no paired device is available, the field may be omitted.
getCurrentSosIncident
Returns Future<SosIncident?>.
final incident = await sdk.getCurrentSosIncident();
if (incident != null) {
debugPrint('incident=${incident.id}');
debugPrint('state=${incident.state.name}');
debugPrint('hasPosition=${incident.positionSnapshot != null}');
}
getSosState
Returns Future<SosState>.
final state = await sdk.getSosState();
debugPrint('sosState=${state.name}');
Contacts
listEmergencyContacts
Returns Future<List<EmergencyContact>>.
final contacts = await sdk.listEmergencyContacts();
for (final contact in contacts) {
debugPrint('${contact.priority}: ${contact.name} ${contact.phone}');
}
createEmergencyContact
Returns EmergencyContact.
final contact = await sdk.createEmergencyContact(
name: 'Mountain Rescue Desk',
phone: '+34600000000',
email: 'rescue@example.com',
priority: 1,
);
debugPrint('contact=${contact.id}');
debugPrint('phone=${contact.phone}');
debugPrint('priority=${contact.priority}');
updateEmergencyContact
Returns EmergencyContact.
final current = (await sdk.listEmergencyContacts()).first;
final updated = await sdk.updateEmergencyContact(
current.copyWith(name: 'Mountain Rescue 24/7'),
);
debugPrint('contact=${updated.id}');
debugPrint('name=${updated.name}');
debugPrint('updatedAt=${updated.updatedAt}');
Permissions
getPermissionState
Returns PermissionState.
final state = await sdk.getPermissionState();
debugPrint('location=${state.location.name}');
debugPrint('notifications=${state.notifications.name}');
debugPrint('bluetooth=${state.bluetooth.name}');
debugPrint('bluetoothReady=${state.canUseBluetooth}');
Protection Mode
Background continuity is far stronger on Android when Protection Mode/native foreground service owns the BLE transport. Plain Flutter-owned BLE provides no guaranteed full background runtime.
getProtectionStatus
Returns ProtectionStatus.
final status = await sdk.getProtectionStatus();
debugPrint('mode=${status.modeState.name}');
debugPrint('runtime=${status.runtimeState.name}');
debugPrint('owner=${status.bleOwner.name}');
debugPrint('protectedDevice=${status.protectedDeviceId}');
getProtectionDiagnostics
Returns ProtectionDiagnostics.
final diagnostics = await sdk.getProtectionDiagnostics();
debugPrint('wake=${diagnostics.lastWakeReason}');
debugPrint('reconnects=${diagnostics.reconnectAttemptCount}');
debugPrint('route=${diagnostics.lastCommandRoute}');
debugPrint('result=${diagnostics.lastCommandResult}');
Backend Device Registry
Paired-device sync logic
- after a known device is paired/connected and the signed-session identity is ready, the SDK/runtime may attempt backend paired-device sync.
- the validation app registry card is a status/retry/debug surface, not the intended primary manual flow.
- automatic sync uses
hardware_id,firmware_version,hardware_model, andpaired_at. - automatic sync is safe only when a canonical backend-compatible hardware id can be resolved.
listRegisteredDevices
Returns Future<List<BackendRegisteredDevice>>.
final devices = await sdk.listRegisteredDevices();
for (final device in devices) {
debugPrint('${device.hardwareId} ${device.firmwareVersion}');
}