embed_flutter 0.0.3
embed_flutter: ^0.0.3 copied to clipboard
A powerful Flutter SDK that provides a powerful voice-enabled AI-agent functionality with real-time widget tree monitoring for screen context fetching and realtime voice communication.
Embed Flutter SDK #
A powerful Flutter SDK that provides a powerful voice-enabled AI-agent functionality with real-time widget tree monitoring for screen context fetching and realtime voice communication.
Table of Contents #
Installation #
Add the following dependency to your pubspec.yaml:
dependencies:
embed_flutter: ^0.0.3
Then run:
flutter pub get
Android Configuration
Add the following permissions to your android/app/src/main/AndroidManifest.xml:
<!-- Required permissions for Embed SDK -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MICROPHONE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Add the following permissions for embed -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MICROPHONE" />
iOS Configuration
Add the following permissions to your ios/Runner/Info.plist:
<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to microphone for voice calls.</string>
Getting Started #
Initialization #
Before using any EmbedWidget, you must initialize the configuration once in your main.dart:
void main() {
embedInitialize(
'your-api-key-here',
embedUrl: 'https://embed.revrag.ai', // Optional
);
runApp(const MyApp());
}
Required: Navigator Observer
For route-based activation to work properly, you must add EmbedNavigatorObserver to your app's navigator observers. This enables the SDK to track route changes and activate/deactivate the EmbedWidget accordingly.
For GoRouter:
import 'package:go_router/go_router.dart';
import 'package:embed_flutter/embed_flutter.dart';
final GoRouter router = GoRouter(
observers: [EmbedNavigatorObserver()], // Required for route tracking
routes: [
// Your routes here
],
);
For MaterialApp:
import 'package:embed_flutter/embed_flutter.dart';
MaterialApp(
navigatorObservers: [EmbedNavigatorObserver()], // Required for route tracking
// Other MaterialApp properties
)
Required: USER_DATA Event
To activate the EmbedWidget on the screen, you must call the USER_DATA embedEvent with a user ID. This is typically done after user authentication or when you have a user identifier:
import 'package:embed_flutter/embed_flutter.dart';
// Call this after user authentication or when you have a user ID
embedEvent(
EventKeys.USER_DATA,
UserEventPayload(
app_user_id: 'user_12345', // Required: Unique user identifier
data: {
'name': 'John Doe', // Optional: Additional user data
'email': 'john@example.com',
'phone': '+1234567890',
},
),
);
Important: The EmbedWidget will not be fully functional until the
USER_DATAevent is sent. This event initializes the voice communication features.
Optional: SCREEN_STATE Event
You can optionally send SCREEN_STATE events to provide additional context about screen changes or user navigation:
// Send screen state when navigating to a new screen
embedEvent(
EventKeys.SCREEN_STATE,
ScreenEventPayload(
screen: 'product_selection_screen', // Required: Screen identifier
data: {
'category': 'banking', // Optional: Additional screen context
'user_type': 'premium',
'flow_step': 'selection',
},
),
);
Available Events
| Event | Purpose | Required | When to Use |
|---|---|---|---|
USER_DATA |
Initialize user context and activate EmbedWidget | Required | After user authentication or when user ID is available |
SCREEN_STATE |
Provide screen context and navigation info | Optional | When navigating between screens or when screen context changes |
Basic Usage #
Here's a complete example showing how to use the SDK with all essential components:
import 'package:flutter/material.dart';
import 'package:embed_flutter/embed_flutter.dart';
void main() {
// 1. Initialize the SDK
embedInitialize(
'your-api-key-here',
embedUrl: 'https://embed.revrag.ai', // Optional
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return EmbedWidget(
// 4. Configure route-based activation
enabledRoutes: ['home', 'product_selection_screen'],
child: MaterialApp(
navigatorObservers: [EmbedNavigatorObserver()], // Required for route tracking
home: MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
// 2. Send USER_DATA event to activate EmbedWidget
// This should typically be called after user authentication
embedEvent(
EventKeys.USER_DATA,
UserEventPayload(
app_user_id: 'user_12345', // Replace with actual user ID
data: {
'name': 'John Doe',
'email': 'john@example.com',
'plan': 'premium',
},
),
);
}
void _navigateToProductScreen() {
// 3. Send SCREEN_STATE event for additional context (Optional)
embedEvent(
EventKeys.SCREEN_STATE,
ScreenEventPayload(
screen: 'product_selection_screen',
data: {
'category': 'banking_products',
'user_segment': 'new_customer',
},
),
);
// Navigate to product screen
Navigator.pushNamed(context, '/product_selection');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('My App')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Welcome to My App!'),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _navigateToProductScreen,
child: const Text('Go to Product Selection'),
),
],
),
),
);
}
}
Required Parameters #
child(required): The main content of your app
Route-Based Activation #
The SDK supports intelligent route-based activation, allowing you to control exactly which screens should display the EmbedWidget:
void main() {
embedInitialize('your-api-key-here');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return EmbedWidget(
// Activate only on specific routes
enabledRoutes: ['welcome_screen', 'personal_info', 'product_selection'],
// Optional: Show on all routes except disabled ones
// showOnAllRoutes: true,
// disabledRoutes: ['splash_screen', 'success_screen'],
// Optional: Route matching mode (exact or startsWith)
// routeMatchMode: RouteMatchMode.exact,
child: MaterialApp.router(
routerConfig: appRouter,
),
);
}
}
Route Configuration Options
enabledRoutes: List of route names where EmbedWidget should be activeshowOnAllRoutes: Show EmbedWidget on all routes (default:false)disabledRoutes: List of route names where EmbedWidget should be disabledrouteMatchMode: How to match routes (RouteMatchMode.exactorRouteMatchMode.startsWithorRouteMatchMode.contains)
Optional Parameters #
apiKey(optional): Your Revrag AI API key for authentication (can be set globally viaembedInitialize())embedUrl(optional): Custom base URL for API endpoints (can be set globally viaembedInitialize())showEmbedWidget(default:true): Controls whether the embedded widget is visibleenabledRoutes(optional): List of route names where EmbedWidget should be activeshowOnAllRoutes(default:false): Show EmbedWidget on all routesdisabledRoutes(optional): List of route names where EmbedWidget should be disabledrouteMatchMode(default:RouteMatchMode.exact): How to match routes
Examples #
Basic Integration #
import 'package:flutter/material.dart';
import 'package:embed_flutter/embed_flutter.dart';
void main() {
// Initialize the SDK
embedInitialize('your-api-key-here');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return EmbedWidget(
child: MaterialApp(
navigatorObservers: [EmbedNavigatorObserver()], // Required for route tracking
home: MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
// Send USER_DATA event to activate EmbedWidget
// This should typically be called after user authentication
embedEvent(
EventKeys.USER_DATA,
UserEventPayload(
app_user_id: 'user_12345', // Replace with actual user ID
data: {
'name': 'John Doe',
'email': 'john@example.com',
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('My App')),
body: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Welcome to My App!'),
SizedBox(height: 20),
Text('The embedded agent is monitoring this screen.'),
],
),
),
);
}
}
Form with Monitoring #
import 'package:flutter/material.dart';
import 'package:embed_flutter/embed_flutter.dart';
void main() {
// Initialize the SDK
embedInitialize('your-api-key-here');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return EmbedWidget(
child: MaterialApp(
navigatorObservers: [EmbedNavigatorObserver()], // Required for route tracking
home: const MyFormPage(),
),
);
}
}
class MyFormPage extends StatefulWidget {
const MyFormPage({super.key});
@override
State<MyFormPage> createState() => _MyFormPageState();
}
class _MyFormPageState extends State<MyFormPage> {
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _emailController = TextEditingController();
@override
void initState() {
super.initState();
// Send USER_DATA event to activate EmbedWidget
// This should typically be called after user authentication
embedEvent(
EventKeys.USER_DATA,
UserEventPayload(
app_user_id: 'user_12345', // Replace with actual user ID
data: {
'name': 'John Doe',
'email': 'john@example.com',
},
),
);
// Send SCREEN_STATE event for additional context
embedEvent(
EventKeys.SCREEN_STATE,
ScreenEventPayload(
screen: 'form_page',
data: {
'form_type': 'user_registration',
'step': 'personal_info',
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('My Form')),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextFormField(
controller: _nameController,
decoration: const InputDecoration(labelText: 'Name'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your name';
}
return null;
},
),
const SizedBox(height: 16),
TextFormField(
controller: _emailController,
decoration: const InputDecoration(labelText: 'Email'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
return null;
},
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// Form is valid - EmbedWidget will track the submission
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Form submitted successfully!')),
);
}
},
child: const Text('Submit'),
),
],
),
),
),
);
}
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
super.dispose();
}
}
Route-Based Configuration #
Configure the EmbedWidget to activate only on specific screens:
import 'package:flutter/material.dart';
import 'package:embed_flutter/embed_flutter.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return EmbedWidget(
// Only show on user-facing screens, not on splash or success
enabledRoutes: [
'welcome',
'personal-info',
'personal-details',
'product-selection',
'additional-info'
],
child: MaterialApp(
navigatorObservers: [EmbedNavigatorObserver()], // Required for route tracking
initialRoute: '/',
routes: {
'/': (context) => const SplashScreen(),
'/welcome': (context) => const WelcomeScreen(),
'/personal-info': (context) => const PersonalInfoScreen(),
'/personal-details': (context) => const PersonalDetailsScreen(),
'/product-selection': (context) => const ProductSelectionScreen(),
'/additional-info': (context) => const AdditionalInfoScreen(),
},
),
);
}
}
Custom Router Integration #
An Example to show Full integration with Custom Routers we can take example of GoRouter for declarative navigation:
import 'package:go_router/go_router.dart';
import 'package:embed_flutter/embed_flutter.dart';
final appRouter = GoRouter(
initialLocation: '/splash',
routes: [
GoRoute(
path: '/splash',
name: 'splash_screen',
builder: (context, state) => const SplashScreen(),
),
GoRoute(
path: '/welcome',
name: 'welcome_screen',
builder: (context, state) => const WelcomeScreen(),
),
GoRoute(
path: '/personal-info',
name: 'personal_info',
builder: (context, state) => const PersonalInfoScreen(),
),
// ... more routes
],
// Add EmbedNavigatorObserver to the list of observers
observers: [
EmbedNavigatorObserver(),
// ... other observers
],
);
void main() {
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
widgetsBinding = EmbedWidgetsBinding();
embedInitialize('your-api-key-here');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return EmbedWidget(
enabledRoutes: ['welcome_screen', 'personal_info', 'product_selection_screen'],
child: MaterialApp.router(
routerConfig: appRouter,
),
);
}
}
Configuration #
Custom Base URL #
You can set a custom base URL globally during initialization:
void main() {
embedInitialize(
'your-api-key',
embedUrl: 'https://your-custom-domain.com',
);
runApp(const MyApp());
}
Troubleshooting #
Common Issues #
-
Widget Not Visible
- Check
showEmbedWidgetparameter - Verify API key is valid
- Check network connectivity
- Check
-
Voice Call Issues
- Ensure microphone permission is granted
- Check device audio settings
-
Widget Tree Not Updating
- Check widget tree handler initialization
- Verify context is available
- Check for widget disposal issues
-
Route-Based Activation Not Working
- Verify route names match exactly (case-sensitive)
- Check
EmbedNavigatorObserveris added to router observers - Ensure GoRouter is properly configured with named routes
- Verify
enabledRouteslist contains correct route names
-
Button Click Detection Issues
- Ensure buttons have proper keys for identification
- Check if buttons are properly tracked in widget tree
- Verify hit testing permissions and context
- Test with different button types (ElevatedButton, TextButton, etc.)
-
EmbedWidget Not Appearing on Expected Screens
- Check
enabledRoutesconfiguration - Check
disabledRoutesconfiguration - Verify route matching mode (
exactvsstartsWith) - Check if
showEmbedWidgetis set totrue
- Check
License #
This project is licensed under the Non-Commercial License License - see the LICENSE file for details.
Support #
- Documentation: https://docs.revrag.ai/embed/integration/flutter
- Email Support: contact@revrag.ai
- GitHub Issues: https://github.com/RevRag-ai/embed-react-native/issues
Changelog #
See CHANGELOG.md for a complete list of changes and version history.