Onlo Flutter SDK

Add Onlo’s ready-made native support Messenger to a Flutter app. Get the basic flow working first: install → initialize → open Messenger → send a test message. Add signed-in identity and push afterward.

Want working code first? Start with the runnable Flutter example. It uses the local plugin and native SDKs from this repository and demonstrates initialization, customer login, Messenger presentation, logout, and push-forwarding hooks.

Package availability: version 0.3.2 is prepared in this repository, but the public package is not published yet. Install only a version marked as available in Onlo Dashboard → WebChat → Install → Mobile app; otherwise, run the repository example.

Flutter is a typed plugin. The iOS and Android Onlo cores own credentials, sessions, offline messages, push registration, and UI.

Prerequisites

  • Flutter 3.27 or newer and Dart 3.6 or newer.
  • An iOS 15+ and/or Android API 24+ host. Android builds require compile SDK 35 and Java 17.
  • An Onlo account with Owner or Admin access to WebChat → Install → Mobile app.
  • A host-owned Support button or route.
  • For identified customers, a backend endpoint authenticated by your app.
  • For push, APNs credentials for iOS and/or a Firebase project for Android.

Concepts

Item Purpose Where it belongs
Public SDK key Connects the app to one Onlo Mobile SDK integration App configuration; it is not a secret or customer identity
Identity secret Signs short-lived customer JWTs Backend secret manager only; never Dart, app config, or source
User JWT Proves the identity of the customer already signed in to your app Created by your backend, held briefly in memory, then passed to native Onlo
Native core Owns protected state, retries, transcript, push, permissions, and Messenger UI Resolved automatically by onlo_flutter
Push token APNs token on iOS or FCM registration token on Android Forward from your push plugin to native Onlo; never store or log it in Dart

Never store Onlo JWTs, session state, push tokens, customer data, or messages in shared preferences, providers, blocs, Dart databases, app files, or logs.

1. Quickstart: connect and test Onlo

Create the Flutter integration

  1. In Onlo Dashboard, open WebChat.

    Expected result: the WebChat channel settings are visible.

  2. Select Install → Mobile app.

    Expected result: the Mobile SDK setup page opens.

  3. Choose Flutter.

    Expected result: Onlo shows the pub and initialization snippets for the plugin.

  4. Select Generate key, then copy the public SDK key.

    Expected result: the integration has a public key that is safe to include in app configuration.

Install the plugin

Add the package to pubspec.yaml:

dependencies:
  onlo_flutter: 0.3.2

Run:

flutter pub get

The plugin resolves OnloSDK 0.3.2 on iOS and ai.onlo:onlo-android-sdk:0.3.2 on Android. Do not add either native core manually.

Expected result: the import resolves and both native hosts build:

import 'package:onlo_flutter/onlo_flutter.dart';

Initialize and connect anonymously

Initialize when the root widget starts, then select the anonymous login path:

class _AppState extends State<App> {
  @override
  void initState() {
    super.initState();
    _connectOnlo();
  }

  Future<void> _connectOnlo() async {
    // Paste the public key generated by the Mobile app setup page.
    await Onlo.initialize(
      sdkKey: '<YOUR_PUBLIC_MOBILE_SDK_KEY>',
    );

    // Create or resume this installation's anonymous support session.
    await Onlo.loginUnidentifiedUser();
  }
}
Added line What it does
Onlo.initialize(sdkKey:) Selects the Onlo integration and starts protected native state restoration; it does not show UI or ask for permissions
loginUnidentifiedUser() Creates or resumes an installation-scoped anonymous session without email, phone, or customer ID
initState() Starts the one-time connection when the root state is created
Future<void> Keeps native/network work asynchronous; production code should show a safe Support-unavailable state when it throws

Open Messenger

Call present from your app’s Support button after anonymous login completes:

FilledButton(
  onPressed: () => Onlo.present(),
  child: const Text('Support'),
)

Expected result: tapping Support opens the native Onlo Messenger. Onlo does not add a launcher automatically.

Verify the connection

  1. Tap your app’s Support button.

    Expected result: the native Onlo Messenger opens; Flutter does not render a parallel chat screen.

  2. Send an anonymous test message to your workspace.

    Expected result: the message reaches the same WebChat AI and support pipeline as the website widget.

  3. Return to WebChat → Install → Mobile app → Flutter in Onlo Dashboard.

    Expected result: Onlo automatically updates the integration status after receiving the SDK connection. Use the displayed status or SDK error code to confirm whether setup succeeded.

2. Verify signed-in customer identity

Identified login starts with your app’s existing authentication. Customers do not enter an Onlo OTP or sign in a second time.

Generate and store the identity secret

  1. On the Flutter Mobile SDK setup page, open Identity verification and select Generate secret.

    Expected result: Onlo creates the secret used to sign mobile identity proofs.

  2. Copy the secret directly into your backend secret manager.

    Expected result: the secret is available only to trusted server code. Never return it to Dart or place it in app configuration, source control, CI logs, or analytics.

  3. Add an authenticated backend endpoint that derives the current customer from your app session and signs a short-lived JWT with HS256.

    Expected result: the app receives a fresh userJwt, not the identity secret.

Replace these placeholders before your backend signs the JWT:

{
  "aud": "onlo-messenger",
  "sub": "<stable-customer-id>",
  "iat": "<current-unix-seconds>",
  "exp": "<iat-plus-no-more-than-300-seconds>",
  "name": "<optional-customer-name>",
  "customAttributes": {
    "plan": "<optional-plan>"
  }
}

Use an immutable, opaque customer ID for sub. iat and exp are numeric Unix seconds, and the lifetime must not exceed five minutes; see the complete JWT claim contract.

Log in the identified customer

// Your backend authenticates the current app session and signs the JWT.
final userJwt = await merchantBackend.fetchOnloUserJwt();

// Pass it directly to native Onlo. Do not decode, persist, or log it.
await Onlo.loginIdentifiedUser(userJwt: userJwt);

Expected result: Onlo verifies the backend signature and associates the native installation with the identified contact for sub.

Test identity continuity

  1. Sign in to your app with a test account, fetch a fresh JWT, and call loginIdentifiedUser.
  2. Open Messenger and send a test message.
  3. Disable Support and await Onlo.logout() before completing app logout.
  4. Sign in again with the same app credentials, mint a new JWT with the same stable sub, and call loginIdentifiedUser again.
  5. Check Onlo Dashboard.

Expected result: Onlo resolves the same identified contact after the second login. A different app customer must use a different stable sub.

3. Enable push notifications

Flutter uses the provider for the current native runtime:

Runtime Provider sent to Onlo Dashboard credential
iOS OnloPushProvider.apns with the hexadecimal APNs device token APNs .p8, Key ID, Team ID, Bundle ID, and environment
Android OnloPushProvider.fcm with the FCM registration token Firebase service-account JSON and Android application ID

Onlo does not install a push-provider plugin or ask for notification permission. Use your existing plugin, ask from a clear customer action, and forward the current token only after anonymousReady or identifiedReady.

Configure the Android runtime with FCM

  1. Add a matching Android app to your Firebase project and follow Firebase’s Android project setup.
  2. Place google-services.json in android/app/, apply the Google Services plugin, and install your Firebase messaging plugin.
  3. In Onlo Dashboard, expand Mobile Features & App Controls, enable Push notifications → FCM, and enter the Android application ID.
  4. In Firebase Console, open Project settings → Service accounts → Generate new private key. Follow Firebase’s service-account instructions.
  5. Paste the complete service-account JSON into Onlo Dashboard and select Save FCM.

Expected result: the dashboard status becomes FCM ready. The service-account JSON remains in Onlo Dashboard and is never bundled into the app.

Configure the iOS runtime with APNs

  1. Add the Push Notifications capability to the iOS app target and enable APNs for its App ID. Follow Apple’s APNs registration guide.
  2. In Onlo Dashboard, enable Push notifications → APNs and enter the Bundle ID and Team ID.
  3. Create and download an APNs .p8 key by following Apple’s private-key guide.
  4. Enter the Key ID, Team ID, .p8 contents, and matching Sandbox/Production environment, then select Validate and save APNs.

Expected result: the dashboard shows the APNs ready state. The .p8 credential remains in Onlo Dashboard and is never bundled into the app.

Forward the device push token

The following example uses the token APIs exposed by firebase_messaging. Another push plugin is also valid if it returns the raw APNs token on iOS and the FCM registration token on Android:

import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:onlo_flutter/onlo_flutter.dart';

final token = Platform.isIOS
    ? await FirebaseMessaging.instance.getAPNSToken()
    : await FirebaseMessaging.instance.getToken();

if (token != null) {
  await Onlo.setPushToken(
    provider: Platform.isIOS
        ? OnloPushProvider.apns
        : OnloPushProvider.fcm,
    token: token,
  );
}

Forward every later token rotation. On iOS, fetch the current APNs token again after native registration/foreground recovery; do not pass an iOS FCM token to Onlo as apns.

Expected result: the current anonymous or identified native installation is registered with the matching provider.

When the customer taps an Onlo notification, wait for a ready state and forward the three routing values:

final result = await Onlo.handlePushNotification(
  OnloPushNotificationPayload(
    conversationId: data['conversationId']!,
    messageId: data['messageId']!,
    notificationType: 'message_available',
  ),
);

Expected result: native code re-authorizes and refreshes the conversation before navigation. Route notOnlo through the app’s normal notification handler; retry deferred after foreground/network recovery without persisting the payload in Dart.

Build and test each installation

  1. Build the native host. Use a signed physical iPhone for APNs and a physical or Google Play-enabled Android device for FCM.

    flutter build apk --release
    flutter build ios --release
    

    Expected result: the provider returns a current token and the app forwards it after Onlo readiness.

  2. In the Mobile SDK dashboard, open Installations.

    Expected result: each test device appears and the installation count increases.

  3. Select one device, choose Send to selected installation, and keep the default five-second safety delay or select another available delay.

    Expected result: Onlo schedules the test only for the selected iOS or Android installation.

  4. Wait for the selected delay and tap the delivered notification.

    Expected result: the notification reaches the selected device and the authorized native Messenger route opens.

Push-token or provider errors are push-only failures. They must not interrupt Messenger, transcript synchronization, login, or logout.

4. Control Messenger presentation

The quickstart opens Messenger directly. In production, observe native readiness before enabling the Support button. Onlo provides the complete native Messenger UI on both platforms and reuses the supported WebChat greeting, colors, bot identity, FAQs, Help Center content, voice controls, and image-upload settings.

Observe native state and enable your host-owned Support button:

StreamBuilder<OnloStateSnapshot>(
  stream: Onlo.observeState(),
  builder: (context, snapshot) {
    final state = snapshot.data?.session;
    final ready = state == OnloSessionState.anonymousReady ||
        state == OnloSessionState.identifiedReady;

    return FilledButton(
      onPressed: ready ? () => Onlo.present() : null,
      child: const Text('Support'),
    );
  },
)
Added line What it does
Onlo.observeState() Streams token-free state emitted by the native core
anonymousReady / identifiedReady Ensures Messenger opens only after the selected session is ready
Onlo.present() Opens the contained native Messenger; it does not render chat in Dart
onPressed: ready ? ... : null Keeps the Support action disabled during initialization, logout, or recovery

Expected result: iOS and Android customers get the same configured support experience without a custom Flutter chat screen. Onlo does not insert a launcher; your app controls where and when Support opens.

Logout and account switching

Disable Support before app logout, then wait for Onlo logout to finish:

Future<void> logoutCustomer() async {
  setState(() => supportEnabled = false);
  await Onlo.logout();
  await merchantAuth.logout();
}

If native state becomes logoutPending, keep Support disabled until recovery completes. User A’s messages, queued sends, unread state, and push association must remain inaccessible before User B can use Onlo.

API summary

Task Flutter API
Initialize Onlo.initialize(sdkKey:)
Anonymous login Onlo.loginUnidentifiedUser()
Identified login Onlo.loginIdentifiedUser(userJwt:)
Present Messenger Onlo.present(...)
Logout Onlo.logout()
Register push Onlo.setPushToken(provider:, token:)
Route a push tap Onlo.handlePushNotification(payload)
Observe state/unread Onlo.observeState(), Onlo.observeUnreadCount()

Success criteria

  • The anonymous test message updates the Flutter integration status in Onlo Dashboard.
  • A server-signed JWT resolves the same contact after logout and login with the same stable sub.
  • Each enabled provider shows ready, its test installation appears, and a selected-device test reaches that runtime.
  • The native Messenger opens from a host-owned action and reflects shared WebChat settings on iOS and Android.
  • Dart never signs, decodes, stores, or logs identity proofs, native state, push tokens, customer data, or message content.

Troubleshooting

Symptom Likely cause Fix
OnloBridgeUnavailableException The plugin was not registered in the rebuilt native host Run flutter clean, flutter pub get, and rebuild the selected platform
Duplicate iOS symbols or Android classes A native Onlo core was added manually beside the plugin Remove the manual core; the Flutter plugin already resolves it
Dashboard does not confirm the connection The package, public key, rebuild, or anonymous login is incomplete Verify the generated public key, reach a ready state, open Messenger, and send one test message
Identified login fails The backend JWT is expired, signed by the wrong secret, or has invalid claims Mint a fresh HS256 JWT with the exact audience, stable sub, and maximum five-minute lifetime
Push setup is ready but no installation appears The app forwarded the wrong device push token or did so before login finished Use the APNs token on iOS or the FCM token on Android, then call setPushToken after login completes
Notification tap does not open Messenger The payload was forwarded before native restoration or failed ownership validation Wait for a ready state and handle deferred/notOnlo without forcing navigation
Old Support state appears during account switching The host did not await native logout Disable Support and complete Onlo.logout() before enabling another customer

Run the example

Use the Flutter host example to test both native runtimes against this repository.

Next: use the API contract when implementing the backend JWT endpoint.

Libraries

onlo_flutter