DobroDesk Flutter SDK

The DobroDesk Flutter SDK delegates transport, retries, identity and polling to the native DobroDesk engines. It exposes the same canonical event envelope on Android and iOS.

Requires Flutter 3.22 or newer, Android API 26 or newer and iOS 15.1 or newer. Install the package with flutter pub add dobrodesk_sdk. The Android engine uses java.time directly and the iOS bridge uses the native Swift concurrency and Foundation APIs.

import 'package:dobrodesk_sdk/dobrodesk_sdk.dart';

final client = DobroDeskFlutterClient(
  integrationId: 'int_example',
  apiOrigin: 'https://widget.example.com',
  accountScope: 'customer_42',
  locale: 'uk',
  pollInterval: const Duration(seconds: 1),
  context: {'screen': 'checkout'},
  credentialProvider: () async => getShortLivedAuthorizationToken(),
);

await client.presentWidget();
await client.presentWidget(context: {'screen': 'order-details', 'orderId': 'ord_42'});

To render support inside an existing Flutter route, use the native inline surface. It uses Compose on Android and SwiftUI on iOS through a PlatformView and shares the same client, session, draft and offline outbox:

SizedBox(
  height: 560,
  child: DobroDeskWidgetView(
    client: client,
    options: const NativeWidgetOptions(
      locale: 'uk',
      view: 'home',
      reduceMotion: true,
    ),
  ),
)

The client refreshes the short-lived identity before reserving the native surface. Removing the Flutter widget detaches it and preserves an unfinished draft. A modal and inline surface cannot be active at the same time. Use errorBuilder to provide localized host copy for preparation or mounting errors.

The widget presents the shared native DobroDesk UI. Its appearance comes from the widget integration configuration. System reduced-motion settings always take precedence. Your backend must issue the short-lived customer token; never embed a signing secret or support API token in the application. context is an optional bounded local map sent only with widget options. A per-presentation context replaces the constructor context and is never added to authorization, server operation or prefill payloads.

Headless conversation operations use the same client:

final session = await client.startSession(
  'I need help with an order',
  prefill: {
    'name': 'Olena',
    'fields': {'orderNumber': 'ORD-42'},
  },
);
final snapshot = await client.refresh();
final accepted = await client.sendMessage('Thanks', idempotencyKey: 'msg-2');

refresh, waitForAssistant, sendMessage and flushOutbox return typed canonical values. Rich JSON fields such as forms, commerce results, procedure actions and handoff availability are preserved in the raw fields and typed JSON properties.

Host actions are optional application callbacks for allowlisted widget choices. They remain local to the app and do not perform network authentication through the SDK:

final client = DobroDeskFlutterClient(
  integrationId: 'int_example',
  apiOrigin: 'https://widget.example.com',
  accountScope: 'customer_42',
  hostActions: {
    'checkout': (request, cancellation) async {
      final result = await openCheckout(request.input);
      if (cancellation.isCancelled) {
        return DobroDeskHostActionResult.failed(
          code: 'cancelled',
          retryable: true,
        );
      }
      return DobroDeskHostActionResult.completed(data: result);
    },
  },
);
await client.presentWidget();

Each callback receives a bounded JSON request. Each context, input and result data object is limited to 16 KiB, 32 fields or array items, strings up to 2048 UTF-16 code units and containers nested through depth 3; primitive values at depth 4 are valid. Object keys must match [A-Za-z0-9_.:-]{1,64} and reserved keys are rejected. At most 32 host actions may be registered. Return acknowledged, completed or a typed failed result. Requests are executed at most once per request ID and late results after cancellation, reset or close are ignored. A session reset keeps the listener installed but preserves the request-ID replay fence; closing, logging out or disposing the client removes the listener and clears that fence.

Subscribe to client.events for loading, session, snapshot, accepted-message, error and session-cleared events. Events use named fields (session, snapshot, message and error) and invalid envelopes are reported as a typed unsupported exception.

The credential provider runs in Dart before each operation that can access the network. Native code only holds the latest token supplied by the SDK. Native outbox files are isolated by accountScope. Call logout() before switching accounts; it resets the native session, clears pending mutations, removes the native client and releases the account scope so the next account can start without restarting the Flutter engine.

Voice is a separate opt-in native artifact. After the host installs and wires that artifact on both platforms, inject its DobroDeskVoicePort:

final voice = await client.attachVoice(nativeVoicePort);
await voice.start();
voice.events.listen((event) => debugPrint('$event'));

The base Flutter package has no microphone permission, audio dependency or background task and does not register a voice channel. The host owns the small platform adapter that turns its installed native capability into a DobroDeskVoicePort. logout() disposes the attached voice port before clearing the native session.

Android binary dependencies

The published wrapper module resolves its DobroDesk binaries from a local Maven repository bundled at native/maven. Register that repository in the host project's settings.gradle or settings.gradle.kts under dependencyResolutionManagement:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url = uri("<installed-dobrodesk-package>/native/maven") }
    }
}

The wrapper's Android module does not register a project-level repository. NativeScript's platforms/android/include.gradle validates the same package repository and adds only its bridge dependency. NativeScript's generated root build already owns its project repositories, so add the package repository to the host app module in App_Resources/Android/app.gradle:

repositories {
    maven { url = uri("$rootDir/../../node_modules/@dobrodesk/nativescript-sdk/native/maven") }
}

React Native and Flutter hosts can keep FAIL_ON_PROJECT_REPOS. Capacitor's official @capacitor/android source module currently declares its own Google project repository, so Capacitor hosts use PREFER_SETTINGS while still registering this local Maven repository from settings. NativeScript uses its generated root project repository policy and the app-module repository above. These provider-specific details are required by the upstream modules; the DobroDesk wrappers do not mutate or replace them.

Add com.dobrodesk:dobrodesk-voice:<version> or com.dobrodesk:dobrodesk-push:<version> to the host only when that optional capability is enabled.