embed_flutter 0.0.4 copy "embed_flutter: ^0.0.4" to clipboard
embed_flutter: ^0.0.4 copied to clipboard

unlisted

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_DATA event 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 active
  • showOnAllRoutes: Show EmbedWidget on all routes (default: false)
  • disabledRoutes: List of route names where EmbedWidget should be disabled
  • routeMatchMode: How to match routes (RouteMatchMode.exact or RouteMatchMode.startsWith or RouteMatchMode.contains)

Optional Parameters #

  • apiKey (optional): Your Revrag AI API key for authentication (can be set globally via embedInitialize())
  • embedUrl (optional): Custom base URL for API endpoints (can be set globally via embedInitialize())
  • showEmbedWidget (default: true): Controls whether the embedded widget is visible
  • enabledRoutes (optional): List of route names where EmbedWidget should be active
  • showOnAllRoutes (default: false): Show EmbedWidget on all routes
  • disabledRoutes (optional): List of route names where EmbedWidget should be disabled
  • routeMatchMode (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 #

  1. Widget Not Visible

    • Check showEmbedWidget parameter
    • Verify API key is valid
    • Check network connectivity
  2. Voice Call Issues

    • Ensure microphone permission is granted
    • Check device audio settings
  3. Widget Tree Not Updating

    • Check widget tree handler initialization
    • Verify context is available
    • Check for widget disposal issues
  4. Route-Based Activation Not Working

    • Verify route names match exactly (case-sensitive)
    • Check EmbedNavigatorObserver is added to router observers
    • Ensure GoRouter is properly configured with named routes
    • Verify enabledRoutes list contains correct route names
  5. 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.)
  6. EmbedWidget Not Appearing on Expected Screens

    • Check enabledRoutes configuration
    • Check disabledRoutes configuration
    • Verify route matching mode (exact vs startsWith)
    • Check if showEmbedWidget is set to true

License #

This project is licensed under the Non-Commercial License License - see the LICENSE file for details.

Support #

Changelog #

See CHANGELOG.md for a complete list of changes and version history.


0
likes
0
points
139
downloads

Documentation

Documentation

Publisher

verified publisherrevrag.ai

Weekly Downloads

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.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_webrtc, livekit_client, lottie, permission_handler, wave

More

Packages that depend on embed_flutter