kindly 2.0.25 copy "kindly: ^2.0.25" to clipboard
kindly: ^2.0.25 copied to clipboard

Kindly Chat SDK for Flutter - customer support chat widget for iOS and Android. Successor to the kindly_sdk package.

Kindly Chat SDK for Flutter #

pub package License: MIT

Kindly Chat SDK for Flutter — customer support chat widget for iOS and Android applications. Thin Flutter facade over the public Kindly iOS and Android SDKs.

The published package ships the native iOS xcframework and Android AAR inline, so consumer apps don't need to wire up Swift Package Manager or JitPack themselves.

Features #

  • Customisable themes and colours
  • Authentication via JWT (callback-based)
  • Multi-language support
  • Real-time chat
  • Push notifications (APNS + FCM)
  • Trigger specific dialogues / deep-link URLs
  • Programmatic message send
  • Context attached to next message or button click
  • Native iOS and Android implementations bundled — no extra setup

Requirements #

  • Flutter >= 3.0 (Dart >= 2.17)
  • iOS >= 17.2 (matches the bundled xcframework — older targets fail at launch with missing dyld symbols)
  • Android minSdk >= 21, plugin builds with compileSdk 35 (matches android-source)

Installation #

Add kindly to your pubspec.yaml:

dependencies:
  kindly: ^2.0.0

Then flutter pub get.

Migrating from kindly_sdk? This package is the renamed successor to kindly_sdk. The public API is identical — only the package name changed. To migrate: bump the dep from kindly_sdk to kindly: ^2.0.0, and replace import 'package:kindly_sdk/kindly_sdk.dart' with import 'package:kindly/kindly.dart'. Nothing else needs to change.

iOS Setup #

No additional setup required. The package vendors a signed KindlySDK.xcframework and CocoaPods links it automatically when Flutter runs pod install. (The framework is named KindlySDK rather than Kindly so it doesn't case-collide with the kindly pod on macOS's case-insensitive filesystem.)

Android Setup #

No additional setup required. The package ships a kindlysdk.aar that Gradle picks up directly via implementation files("libs/kindlysdk.aar").

Note on manifest merger. The bundled AAR declares android:label="@string/app_name" on its <application> element. If your app's AndroidManifest.xml also sets android:label, Android's manifest merger fails with "Attribute application@label is also present at [kindlysdk.aar]". To resolve, add tools:replace="android:label" to your <application> tag (and declare xmlns:tools="http://schemas.android.com/tools" on the root <manifest> if not already):

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <application
        android:label="My App"
        …
        tools:replace="android:label">
        …
    </application>
</manifest>

Usage #

Basic Setup #

import 'package:kindly/kindly.dart';

await KindlySDK.start(
  botKey: 'YOUR_BOT_KEY',
);

await KindlySDK.displayChat();

Authentication #

await KindlySDK.start(
  botKey: 'YOUR_BOT_KEY',
  authTokenCallback: () async {
    final token = await yourAuthService.getToken();
    return token;
  },
);

Custom Theme #

await KindlySDK.setCustomTheme(
  background: Colors.white,
  botMessageBackground: Colors.grey[200],
  botMessageText: Colors.black,
  userMessageBackground: Colors.blue,
  userMessageText: Colors.white,
  buttonBackground: Colors.blue,
  buttonText: Colors.white,
  navBarBackground: Colors.blue,
  navBarText: Colors.white,
  inputBackground: Colors.grey[100],
  inputText: Colors.black,
);

// Revert to default
await KindlySDK.clearCustomTheme();

Context Data #

await KindlySDK.setNewContext({
  'userId': '12345',
  'userName': 'John Doe',
  'email': 'john@example.com',
  'plan': 'premium',
});

await KindlySDK.clearNewContext();

Trigger Specific Dialogues #

// Launch chat with a specific dialogue
await KindlySDK.launchChat(triggerDialogueId: 'welcome_dialogue');

// Or trigger a dialogue inside an active chat
await KindlySDK.triggerDialogue('help_dialogue');

// Clear any pending trigger (Android only)
await KindlySDK.clearTriggerDialogue();

The SDK recognises kindly://chat/dialogue/{id} URLs.

final handled = await KindlySDK.handleUrl('kindly://chat/dialogue/welcome');

Programmatic Message Send #

Send a message on behalf of the user. The SDK renders the bubble locally and reconciles the server-assigned id when the POST returns — do not also display the message yourself.

final reconciled = await KindlySDK.sendMessage(
  'Hello there',
  newContext: {'priority': 'high'},
);
print(reconciled?['id']); // server id

Handover to a Human Agent #

Initiate a handover and receive a callback when the handover begins.

await KindlySDK.callHandover(() {
  print('Handover initiated');
});

Push Notifications #

iOS

await KindlySDK.setAPNSDeviceToken(deviceToken);
await KindlySDK.handleNotification(notificationData);
final isKindly = await KindlySDK.isKindlyNotification(notificationData);

Android

await KindlySDK.saveNotificationToken(fcmToken);
await KindlySDK.handleNotification(remoteMessage.data);
final isKindly = await KindlySDK.isKindlyNotification(remoteMessage.data);

Other Features #

// Check chat UI state (iOS only)
final isDisplayed = await KindlySDK.isChatDisplayed;

// Update language for the active session
await KindlySDK.setLanguage('no');

// Save a JWT to the platform keychain (iOS only)
await KindlySDK.saveAuthToken('jwt-here');

// Toggle SDK logging / Sentry crash reporting
await KindlySDK.setVerboseLogging(true);
await KindlySDK.setCrashReporting(true);

// Close UI without ending the session
await KindlySDK.closeChat();

// End the active session (clears messages + token, dismisses UI)
await KindlySDK.endChat();

// Tear the SDK down completely — must call start() again before reuse
await KindlySDK.kill();

API Reference #

Lifecycle #

  • start({botKey, languageCode?, authTokenCallback?}) — initialise the SDK. First call before anything else.
  • displayChat({languageCode?, triggerDialogueId?}) — show the chat UI.
  • launchChat({triggerDialogueId?}) — connect (if needed) and show the chat UI. Recommended on Android; routed to displayChat on iOS.
  • closeChat() — dismiss the UI without ending the session.
  • endChat() — end the active session, clear messages + token, dismiss UI.
  • kill() — fully tear down the SDK; start() must be called again before reuse.
  • setLanguage(languageCode) — change language for the current session.

Messaging #

  • sendMessage(text, {newContext?}) — send a message programmatically; resolves with {id, text, created, sender, ...}.
  • setNewContext(context) — stage Map<String, String> context for the next message or click.
  • clearNewContext() — clear staged context.
  • triggerDialogue(dialogueId) — trigger a dialogue by id (must be connected).
  • clearTriggerDialogue() — clear pending trigger (Android only).
  • handleUrl(url) — handle kindly://chat/dialogue/{id} deep links; returns bool.
  • callHandover(callback) — request handover to a human agent (Android only).

Theme #

  • setCustomTheme({...colors}) — override individual theme slots (background, botMessageBackground, botMessageText, userMessageBackground, userMessageText, buttonBackground, buttonText, buttonOutline, buttonSelectedBackground, navBarBackground, navBarText, inputBackground, inputText, inputCursor, chatLogElements, defaultShadow, maintenanceHeaderBackground).
  • clearCustomTheme() — revert to the default / API theme.

Push #

  • setAPNSDeviceToken(token) — register the APNS token (iOS only).
  • saveNotificationToken(token) — register the FCM token (Android only).
  • handleNotification(data) — forward a push to the SDK.
  • isKindlyNotification(data)true if the push originated from Kindly.

State & settings #

  • isChatDisplayedFuture<bool>; iOS only (Android always returns false — track via host UI state).
  • saveAuthToken(token) — persist a JWT to the platform keychain (iOS).
  • setVerboseLogging(bool) — toggle verbose logging.
  • setCrashReporting(bool) — toggle Sentry crash reporting.

License #

This project is licensed under the MIT License — see the LICENSE file for details.


Maintenance #

Internal note for future maintainers — not relevant if you're integrating the SDK into your app.

This package wraps two native artefacts that are built from sibling repos and bundled inline:

  • ios/Frameworks/KindlySDK.xcframework — built from ../ios-source/, signed with the team G2P4AFMWD6 Apple Distribution cert. (Renamed from upstream Kindly.framework during bundling — see AGENTS.md for the why.)
  • android/libs/kindlysdk.aar — built from ../android-source/ via ./gradlew :kindlysdk:assembleRelease -PsdkMode=true.

There are two release paths:

  1. Manual local (make publish from a developer laptop) — used when the bridge layer (lib/kindly.dart + the two KindlyPlugin files) needs hand-edits because EntryPoint.swift / EntryPoint.kt changed.
  2. Cross-repo CI (automatic on every iOS / Android source release) — ios-source/.github/workflows/deploy-sdk.yml and android-source/.github/workflows/deploy-sdk.yml clone this repo, rebundle the corresponding native binary, bump pubspec.yaml's patch, and dart pub publish — keeping kindly in sync with the latest native bug fixes without any manual step.

See docs/flutter-sdk-release-architecture.md for the full diagram of the auth model, secrets, and how to flip between architectures.

make setup        # one-time: install Ansible / coreutils / etc.
make bundle       # build-only: refresh the xcframework + AAR (no publish)
make publish-dry  # bundle + validate via `dart pub publish --dry-run`
make publish      # bundle + validate + confirmation prompt + upload + tag + bump

make publish is the canonical release command. It runs a single Ansible invocation that bundles, validates, prompts before the irreversible upload, then publishes + tags + bumps. make bundle is a stand-alone convenience for build-only work — make publish doesn't need it.

Version cycle (mirrors the iOS pipeline) #

pubspec.yaml's version: field is the canonical source of truth, equivalent to iOS's .bumpversion.cfg. The release flow is:

  1. Whatever version is in pubspec.yaml right now is what gets published. If pubspec.yaml says 1.1.0, make publish publishes 1.1.0.
  2. Right after a successful dart pub publish, the playbook tags the released commit v1.1.0 and pushes the tag.
  3. It then auto-increments the patch (1.1.01.1.1), commits the bump with message Bump version for next release, and pushes that commit on the current branch.
  4. So at any point in time, HEAD of your branch carries the next version waiting to be released, and the most recent release tag is one patch behind.

For a minor or major bump, edit pubspec.yaml and CHANGELOG.md by hand before running make publish — same model as bumping .bumpversion.cfg manually on iOS before make deploy-sdk. Patch bumps are automatic.

Cert prerequisite: the bundling step requires the Apple Distribution cert for team G2P4AFMWD6 to already be in your login keychain. If you regularly release the iOS SDK from ../ios-source/, you have it. Otherwise run once: cd ../ios-source && bundle exec fastlane match development --readonly.

The plugin's bridge layer (lib/kindly.dart + ios/Classes/KindlyPlugin.swift + android/src/main/kotlin/ai/kindly/flutter_sdk/KindlyPlugin.kt) is a thin facade over the public EntryPoint API of each native SDK. If a method isn't on EntryPoint, it isn't reachable from Flutter — that's by design.

When the iOS or Android SDK changes:

  • No public-API change (bug fix, internal refactor): just make publish (patch bumps automatically).
  • EntryPoint API change (new method, signature change): update the three bridge files first, optionally hand-bump minor/major in pubspec.yaml, then make publish.

Manual ansible-playbook invocations bundle by default too — you can pass -e skip_bundle=true to skip the bundle step (only useful when iterating on the publish playbook itself).

See scripts/README.md for what each playbook does.

0
likes
0
points
1.52k
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

Kindly Chat SDK for Flutter - customer support chat widget for iOS and Android. Successor to the kindly_sdk package.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on kindly

Packages that implement kindly