Quick Start: Flutter
Embed the Lovina chat widget in your Flutter app using a WebView widget with native event bridging, session persistence, and theme support.
Step 1: Add the Dependency
Add the SDK to your pubspec.yaml:
dependencies:
lovina_chat_sdk:
path: packages/flutter # or from pub.dev when published
Then run:
flutter pub get
Platform-Specific Setup
Android -- add Internet permission in android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
iOS -- if using HTTPS (recommended), no changes are needed. For local development with HTTP, add to ios/Runner/Info.plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Step 2: Add the Chat Widget
import 'package:flutter/material.dart';
import 'package:lovina_chat_sdk/lovina_chat_sdk.dart';
class ChatPage extends StatelessWidget {
const ChatPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Support Chat')),
body: LovinaChatWidget(
config: LovinaChatConfig(
websiteToken: 'your-website-token',
baseUrl: 'https://chat.lovina.app',
),
onLoaded: (event) {
debugPrint('Chat loaded, token: ${event.authToken}');
},
onMessageReceived: (event) {
debugPrint('Message: ${event.message}');
},
),
);
}
}
Display Options
Inline Widget
Embed the chat directly in your widget tree:
LovinaChatWidget(
config: LovinaChatConfig(
websiteToken: 'your-token',
baseUrl: 'https://chat.lovina.app',
locale: 'en',
colorScheme: 'auto',
),
onLoaded: (event) => print('Loaded'),
onMessageReceived: (event) => print('Message received'),
onUnreadCountChanged: (event) => print('Unread: ${event.count}'),
onClosed: (event) => print('Closed: ${event.reason}'),
onError: (event) => print('Error: ${event.code} - ${event.message}'),
)
Modal Bottom Sheet
ElevatedButton(
onPressed: () {
LovinaChatModal.showBottomSheet(
context: context,
config: LovinaChatConfig(
websiteToken: 'your-token',
baseUrl: 'https://chat.lovina.app',
),
onMessageReceived: (event) => print('New message'),
);
},
child: const Text('Open Chat'),
)
Full-Screen Modal
LovinaChatModal.showFullScreen(
context: context,
config: LovinaChatConfig(
websiteToken: 'your-token',
baseUrl: 'https://chat.lovina.app',
),
);
Configuration Options
| Parameter | Type | Default | Description |
|---|---|---|---|
websiteToken | String | required | Website channel token from your Lovina dashboard |
baseUrl | String | required | Base URL of your Lovina instance |
locale | String | 'id' | Widget locale code (3 languages supported) |
colorScheme | String | 'auto' | 'light', 'dark', or 'auto' |
user | LovinaChatUser? | null | Pre-identified user |
customColor | String? | null | Hex color for theming (e.g., '#FF6B35') |
displayMode | String | 'fullscreen' | 'popup', 'sidebar', or 'fullscreen' |
User Identification
Pre-identify users to associate messages with their account:
final config = LovinaChatConfig(
websiteToken: 'your-token',
baseUrl: 'https://chat.lovina.app',
user: LovinaChatUser(
identifier: 'user-123',
name: 'John Doe',
email: 'john@example.com',
avatarUrl: 'https://example.com/avatar.png',
identifierHash: 'hmac-hash-for-verification',
phoneNumber: '+62812345678',
customAttributes: {
'plan': 'premium',
'company': 'Acme Corp',
},
),
);
Event Handling
Use typed callbacks or the generic onEvent handler:
LovinaChatWidget(
config: config,
onEvent: (event) {
if (event is ChatLoadedEvent) {
print('Loaded with token: ${event.authToken}');
} else if (event is MessageReceivedEvent) {
print('Message: ${event.message}');
} else if (event is UnreadCountChangedEvent) {
print('Unread count: ${event.count}');
} else if (event is ChatClosedEvent) {
print('Closed: ${event.reason}');
} else if (event is ChatErrorEvent) {
print('Error [${event.code}]: ${event.message}');
}
},
)
| Event | Description |
|---|---|
ChatLoadedEvent | Widget finished loading. Contains optional authToken. |
MessageReceivedEvent | New message received. Contains message map. |
UnreadCountChangedEvent | Unread count changed. Contains count. |
ChatClosedEvent | Chat closed. Contains optional reason. |
ChatErrorEvent | Error occurred. Contains code and message. |
Theming
// Follow system theme
LovinaChatConfig(colorScheme: 'auto', ...)
// Force light or dark
LovinaChatConfig(colorScheme: 'dark', ...)
// Custom brand color
LovinaChatConfig(customColor: '#FF6B35', ...)
Session Management
Sessions are persisted automatically via flutter_secure_storage. To clear a session:
await CookieStore.clear('your-website-token');
Requirements
- Flutter 3.0+
- Dart 2.19+
- Android: API 24+ with Internet permission
- iOS: 15.0+