Robylon Flutter SDK

Flutter plugin for Robylon Chatbot.

Installation

Add to your pubspec.yaml:

dependencies:
  robylon_flutter_sdk: ^0.0.1

Then run:

flutter pub get

Configuration (optional)

Set base URLs and debug before using the SDK:

import 'package:robylon_flutter_sdk/robylon_flutter_sdk.dart';

void main() {
  setRobylonFlutterSdkConfig(RobylonFlutterSdkConfig(
    apiUrl: 'https://api.robylon.com',
    baseChatbotDomain: 'https://your-chatbot-domain.com',
    chatbotPath: 'path',
    debug: false,
  ));
  runApp(MyApp());
}

Usage

Basic

import 'package:robylon_flutter_sdk/robylon_flutter_sdk.dart';

class MyScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Chatbot(
        apiKey: 'YOUR_API_KEY',
        userId: 'optional_user_id',
        userToken: 'optional_token',
        userProfile: {
          'email': 'user@example.com',
          'name': 'John Doe',
          'mobile': '+1234567890',
        },
        onEvent: (event) => print('Event: ${event.type}'),
        onOpen: () => print('Opened'),
        onClose: () => print('Closed'),
        onReady: () => print('Ready'),
      ),
    );
  }
}

Imperative control (ref API)

final controller = RobylonChatbotController();

// In build:
Chatbot(
  apiKey: 'YOUR_API_KEY',
  controller: controller,
  showFloatingButton: false,
)

// Later:
if (controller.isReady()) {
  controller.open();
  // or controller.close(); controller.toggle();
}

Open chatbot in external browser

import 'package:robylon_flutter_sdk/robylon_flutter_sdk.dart';

openChatbot('CHATBOT_ID', {'param': 'value'});

Exports

  • Chatbot – Main widget
  • RobylonChatbotController – Ref-style open/close/toggle/isReady
  • openChatbot – Open chatbot URL externally
  • errorTracker / ErrorTrackingService – Error reporting
  • ChatbotEventType, ChatbotEvent, ChatbotEventHandler – Events
  • ChatbotConfig, LauncherType, WidgetPositionEnums, etc. – Types
  • setRobylonFlutterSdkConfig / RobylonFlutterSdkConfig – Config

Events

Same as the React Native SDK:

  • CHATBOT_BUTTON_LOADED, CHATBOT_BUTTON_CLICKED
  • CHATBOT_OPENED, CHATBOT_CLOSED
  • CHATBOT_APP_READY, CHATBOT_LOADED
  • CHAT_INITIALIZED, CHAT_INITIALIZATION_FAILED
  • SESSION_REFRESHED
  • REQUEST_MIC_PERMISSION, MIC_PERMISSION_GRANTED, MIC_PERMISSION_DENIED

Requirements

  • Flutter SDK
  • Android / iOS (platform WebView)
  • Valid Robylon API key

License

ISC


Integration Recipes

Copy‑pasteable integration patterns for using robylon_flutter_sdk in real apps. Each recipe lists: what it does, code sketch, and required platform config. Assume robylon_flutter_sdk is in pubspec.yaml and you have a valid Robylon API key. Replace placeholders (YOUR_API_KEY, YOUR_USER_ID, etc.) with real data.

Index


Recipe 1 – Full‑screen overlay with external trigger (no launcher) and keyboard‑aware layout

Goal: Show the chatbot as a full‑screen overlay when the user taps a menu item (or any button), with: no built‑in launcher (showFloatingButton: false), external trigger via RobylonChatbotController, and keyboard‑aware layout so the WebView input is not covered on Android. Works on both Android and iOS.

1. Basic structure

Create a RobylonChatbotController and a stateful screen that: renders your normal content, uses a top‑level Stack so the overlay sits above the entire UI (including AppBar), and shows a Positioned.fill overlay with the chatbot when a flag is true.

import 'package:flutter/material.dart';
import 'package:robylon_flutter_sdk/robylon_flutter_sdk.dart';

final RobylonChatbotController _chatbotController = RobylonChatbotController();

class ChatbotHomeScreen extends StatefulWidget {
  const ChatbotHomeScreen({super.key});

  @override
  State<ChatbotHomeScreen> createState() => _ChatbotHomeScreenState();
}

class _ChatbotHomeScreenState extends State<ChatbotHomeScreen> {
  bool _showOverlay = false;

  void _openChatbotOverlay(BuildContext context) {
    Navigator.of(context).pop(); // close drawer if opened
    setState(() => _showOverlay = true);
  }

  void _closeChatbotOverlay() {
    setState(() => _showOverlay = false);
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Scaffold(
          appBar: AppBar(title: const Text('Your App')),
          drawer: Drawer(
            child: ListView(
              padding: EdgeInsets.zero,
              children: [
                const DrawerHeader(
                  decoration: BoxDecoration(color: Colors.deepPurple),
                  child: Align(
                    alignment: Alignment.bottomLeft,
                    child: Text('Menu', style: TextStyle(color: Colors.white, fontSize: 20)),
                  ),
                ),
                ListTile(
                  leading: const Icon(Icons.support_agent),
                  title: const Text('Customer Service'),
                  onTap: () => _openChatbotOverlay(context),
                ),
              ],
            ),
          ),
          body: const Center(child: Text('Your regular content goes here')),
        ),
        if (_showOverlay) _buildChatbotOverlay(context),
      ],
    );
  }

  Widget _buildChatbotOverlay(BuildContext context) {
    return Positioned.fill(
      child: Material(
        color: Colors.black54,
        child: SafeArea(
          child: AnimatedPadding(
            duration: const Duration(milliseconds: 200),
            padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
            child: _ChatbotOverlayContent(
              controller: _chatbotController,
              onClose: _closeChatbotOverlay,
            ),
          ),
        ),
      ),
    );
  }
}

2. Overlay chatbot widget (no launcher, external trigger)

class _ChatbotOverlayContent extends StatelessWidget {
  const _ChatbotOverlayContent({required this.controller, required this.onClose});

  final RobylonChatbotController controller;
  final VoidCallback onClose;

  @override
  Widget build(BuildContext context) {
    return Chatbot(
      apiKey: 'YOUR_API_KEY',
      controller: controller,
      showFloatingButton: false,
      userId: 'OPTIONAL_YOUR_USER_ID',
      userToken: 'OPTIONAL_USER_TOKEN',
      userProfile: {'email': 'user@example.com', 'is_test_user': true},
      onEvent: (event) => debugPrint('Chatbot event: ${event.type}'),
      onOpen: () => debugPrint('Chatbot opened'),
      onClose: () {
        debugPrint('Chatbot closed');
        onClose();
      },
      onReady: () {
        debugPrint('Chatbot ready (overlay)');
        if (controller.isReady()) controller.open();
      },
    );
  }
}
  • showFloatingButton: false ensures only your external trigger is used. In onReady, call controller.open() after readiness. In onClose, call onClose() to hide the overlay.

3. Platform / SDK configuration

  • pubspec.yaml: robylon_flutter_sdk: ^2.x.x

  • Android: android:windowSoftInputMode="adjustResize" on MainActivity. For local HTTP dev, add network_security_config and reference it in <application>. If you use voice notes or any audio recording features, also add these permissions to your AndroidManifest.xml:

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    
  • iOS: NSCameraUsageDescription, NSPhotoLibraryUsageDescription, NSMicrophoneUsageDescription in Info.plist if the chatbot uses camera/mic/photo.


Recipe 2 – Inline (non‑full‑screen) chatbot panel with external trigger and keyboard‑aware layout

Goal: Embed the chatbot as a panel inside your screen (not full‑screen); hide the launcher; use a button or menu item to toggle the panel; keep the WebView input visible when the keyboard opens.

1. Basic structure – inline panel in a Column

import 'package:flutter/material.dart';
import 'package:robylon_flutter_sdk/robylon_flutter_sdk.dart';

final RobylonChatbotController _inlineChatController = RobylonChatbotController();

class InlineChatScreen extends StatefulWidget {
  const InlineChatScreen({super.key});

  @override
  State<InlineChatScreen> createState() => _InlineChatScreenState();
}

class _InlineChatScreenState extends State<InlineChatScreen> {
  bool _showChat = false;

  void _toggleChat() {
    setState(() => _showChat = !_showChat);
    if (_showChat && _inlineChatController.isReady()) {
      _inlineChatController.open();
    }
  }

  @override
  Widget build(BuildContext context) {
    final viewInsets = MediaQuery.of(context).viewInsets;
    return Scaffold(
      appBar: AppBar(
        title: const Text('Inline Chat Example'),
        actions: [IconButton(icon: const Icon(Icons.support_agent), onPressed: _toggleChat)],
      ),
      body: Column(
        children: [
          const Expanded(child: Center(child: Text('Main content here'))),
          _showChat
              ? Expanded(
                  child: Padding(
                    padding: EdgeInsets.only(bottom: viewInsets.bottom),
                    child: _InlineChatPanel(
                      controller: _inlineChatController,
                      onClose: () => setState(() => _showChat = false),
                    ),
                  ),
                )
              : const SizedBox.shrink(),
        ],
      ),
    );
  }
}

2. Inline chat panel widget

class _InlineChatPanel extends StatelessWidget {
  const _InlineChatPanel({required this.controller, required this.onClose});

  final RobylonChatbotController controller;
  final VoidCallback onClose;

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: const BoxDecoration(
        color: Colors.white,
        border: Border(top: BorderSide(color: Colors.black12)),
      ),
      child: ClipRect(
        child: Chatbot(
          apiKey: 'YOUR_API_KEY',
          controller: controller,
          showFloatingButton: false,
          userId: 'YOUR_USER_ID',
          userToken: 'OPTIONAL_USER_TOKEN',
          userProfile: {'email': 'user@example.com', 'is_test_user': true},
          onEvent: (event) => debugPrint('Inline chatbot event: ${event.type}'),
          onOpen: () => debugPrint('Inline chatbot opened'),
          onClose: () {
            debugPrint('Inline chatbot closed');
            onClose();
          },
          onReady: () {
            debugPrint('Inline chatbot ready');
            if (controller.isReady()) controller.open();
          },
        ),
      ),
    );
  }
}

Platform: Same as Recipe 1.


Recipe 3 – Launcher on, full‑screen chatbot with keyboard‑aware layout

Goal: Use the SDK’s built‑in floating launcher (showFloatingButton: true) and let it open the chatbot full‑screen, with WebView input visible when the keyboard opens.

1. Full‑screen setup with launcher

import 'package:flutter/material.dart';
import 'package:robylon_flutter_sdk/robylon_flutter_sdk.dart';

class LauncherFullScreenChatScreen extends StatelessWidget {
  const LauncherFullScreenChatScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Launcher Full‑screen Chat')),
      body: const _LauncherChatbot(),
    );
  }
}

class _LauncherChatbot extends StatelessWidget {
  const _LauncherChatbot({super.key});

  @override
  Widget build(BuildContext context) {
    return Chatbot(
      apiKey: 'YOUR_API_KEY',
      showFloatingButton: true,
      userId: 'YOUR_USER_ID',
      userToken: 'OPTIONAL_USER_TOKEN',
      userProfile: {'email': 'user@example.com', 'is_test_user': true},
      onEvent: (event) => debugPrint('Launcher chatbot event: ${event.type}'),
      onOpen: () => debugPrint('Launcher chatbot opened'),
      onClose: () => debugPrint('Launcher chatbot closed'),
      onReady: () => debugPrint('Launcher chatbot ready'),
    );
  }
}

Platform: Same as Recipe 1.


Recipe 4 – Full‑screen route (non‑overlay) with external trigger, onClose, and keyboard‑aware layout

Goal: Open the chatbot on a dedicated full‑screen route when the user taps a button; no launcher; external trigger via Navigator.push and RobylonChatbotController; onClose pops the route; keyboard via system.

1. Entry screen – navigate to full‑screen chat

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  void _openChat(BuildContext context) {
    Navigator.of(context).push(
      MaterialPageRoute(builder: (_) => const FullScreenChatScreen()),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
        actions: [
          IconButton(
            icon: const Icon(Icons.support_agent),
            onPressed: () => _openChat(context),
          ),
        ],
      ),
      body: const Center(child: Text('Main content here')),
    );
  }
}

2. Full‑screen chat screen

import 'package:flutter/material.dart';
import 'package:robylon_flutter_sdk/robylon_flutter_sdk.dart';

final RobylonChatbotController _fullScreenChatController = RobylonChatbotController();

class FullScreenChatScreen extends StatelessWidget {
  const FullScreenChatScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: _FullScreenChatBody(
          controller: _fullScreenChatController,
          onClose: () => Navigator.of(context).pop(),
        ),
      ),
    );
  }
}

class _FullScreenChatBody extends StatelessWidget {
  const _FullScreenChatBody({required this.controller, required this.onClose});

  final RobylonChatbotController controller;
  final VoidCallback onClose;

  @override
  Widget build(BuildContext context) {
    return Chatbot(
      apiKey: 'YOUR_API_KEY',
      controller: controller,
      showFloatingButton: false,
      userId: 'YOUR_USER_ID',
      userToken: 'OPTIONAL_USER_TOKEN',
      userProfile: {'email': 'user@example.com', 'is_test_user': true},
      onEvent: (event) => debugPrint('Full‑screen route chatbot event: ${event.type}'),
      onOpen: () => debugPrint('Full‑screen route chatbot opened'),
      onClose: () {
        debugPrint('Full‑screen route chatbot closed');
        onClose();
      },
      onReady: () {
        debugPrint('Full‑screen route chatbot ready');
        if (controller.isReady()) controller.open();
      },
    );
  }
}
```**Platform:** Same as Recipe 1. More recipes (bottom‑sheet launcher, deep‑link triggered chatbot, etc.) can follow the same structure: what it does, Flutter layout, and platform config.