Skip to main content

EthioConnect for Flutter (Dart)

The commbaas package is the native EthioConnect SDK for Flutter — iOS, Android, and Flutter web. It mirrors the JavaScript (@comm-baas/client-sdk), Swift (CommBaaS), and Kotlin (com.commbaas:sdk) SDKs layer by layer: typed models, resource facades, and a signaling connection with the disconnected -> connecting -> connected -> resuming lifecycle. See ADR 0022 — Native Dart SDK and ADR 0017 — Mobile SDK Architecture.

In-repo package (not yet on pub.dev)

The SDK lives in this repository at sdks/dart/commbaas and is not yet published to pub.dev (ADR 0022 §7). Until it is, consume it as a git dependency:

dependencies:
commbaas:
git:
url: https://github.com/comm-baas/communication_baas.git
path: sdks/dart/commbaas

or, from a checkout of this repository, as a path dependency:

dependencies:
commbaas:
path: ../communication_baas/sdks/dart/commbaas

Quick start

import 'package:commbaas/commbaas.dart';

final client = CommBaasClient(
baseUrl: 'https://api.example.com/v1',
// Called whenever the SDK needs a fresh JWT. Your app owns token
// storage and refresh; the tenant API key never ships in the app.
tokenProvider: () async => myBackend.fetchEthioConnectToken(),
);

final room = await client.joinRoom('room-uuid');

room.events.listen((event) {
switch (event) {
case ParticipantJoined(:final participant):
print('${participant.displayName} joined');
case ActiveSpeakersChanged(:final speakers):
print('${speakers.length} people speaking');
case Disconnected(:final reason):
print('disconnected: $reason');
default:
break;
}
});

await room.setMicEnabled(true);
// ...
await room.leave();

joinRoom() orchestrates the entire flow for you: the REST join call, the signaling WebSocket handshake, the LiveKit media connection (with server-provisioned ICE/TURN), and QoS telemetry — and returns a single RoomHandle.

What the SDK provides

LayerWhat you get
Typed modelsHand-written Dart classes for every REST resource and signaling message, taken verbatim from the platform contracts. No code generation.
Resource facadesclient.auth, client.rooms, client.presence, client.analytics, client.billing, client.turn — same naming as the JS SDK.
joinRoom() / RoomHandleOne call joins the room; the handle exposes events (a broadcast Stream of sealed RoomEvent subclasses), setMicEnabled / setCameraEnabled, moderation methods, and the roster.
SignalingConnectionHeartbeat, session_id/last_seq tracking, and automatic session resume with 1 s / 2 s / 4 s backoff (3 attempts). Managed for you by joinRoom().
Typed exceptionsAuthenticationException, AuthorizationException, NotFoundException, ValidationException, RateLimitException, NetworkException, SignalingException — mirroring the JS error hierarchy.

Dependencies are exactly http, web_socket_channel, and livekit_client. The SDK never stores tokens and has no storage dependency — token supply is the async tokenProvider closure, and secure storage stays in your app.

Architecture

EthioConnect uses the same trust-boundary split on Flutter as on every other platform:

Your Backend Flutter App (iOS / Android / web)
============ ==================================
Tenant API key commbaas SDK, built on:
| http (REST)
| POST /v1/auth/token web_socket_channel (signaling)
v livekit_client (media)
EthioConnect API -- short-lived JWT --> | tokenProvider closure
v
EthioConnect API
|
| WebSocket signaling
v
LiveKit SFU (media)
  1. Your backend holds the tenant API key and mints short-lived JWTs for end users via POST /v1/auth/token (see Authentication). The API key never ships inside the Flutter app — and by design the client SDK has no mintToken method.
  2. The Flutter app hands the SDK a tokenProvider closure; the SDK attaches Authorization: Bearer <JWT> to every REST call and never caches the token beyond immediate use.
  3. client.joinRoom() obtains a signaling ticket for the WebSocket and a LiveKit token/URL for media, and connects both.
  4. TURN relay is provisioned server-side (Coturn); the join grant already includes the ice_servers the media connection needs.

Under the hood

The SDK is a thin, typed layer over the platform's public REST and WebSocket contracts (contracts/openapi/*, contracts/ws-protocol/signaling.json). Each guide page in this section documents the SDK API first, then keeps the raw wire protocol in an "Under the hood" section — per ADR 0019 §4, the former integration-guide material now documents what the SDK does on the wire. In raw terms, joinRoom() performs:

// 1. POST /v1/rooms/{id}/join with Bearer auth -> join grant:
// { session_id, livekit_token, livekit_url,
// signal_url, signal_ticket, ice_servers }
// 2. WebSocketChannel.connect('<signal_url>?ticket=<signal_ticket>')
// and wait for the `hello` frame.
// 3. livekit Room().connect(livekit_url, livekit_token) with ice_servers.
// 4. Periodic QoS batches to POST /v1/analytics/qos.

For endpoints that do not yet have a facade method, client.httpClient exposes authenticated get/post/put/delete against the same base URL.

Guide contents

  • Authentication — the tokenProvider closure, end-user auth via client.auth, secure storage.
  • Roomsclient.rooms, joinRoom(), RoomHandle, moderation, recordings.
  • SignalingSignalingConnection, heartbeat, session resume, and the wire protocol.
  • Media — mic/camera control, the LiveKit escape hatch, TURN.
  • Presence & Notificationsclient.presence queries and event delivery.