flutter_embedding 0.0.1-beta.1 copy "flutter_embedding: ^0.0.1-beta.1" to clipboard
flutter_embedding: ^0.0.1-beta.1 copied to clipboard

This project helps embedding into a native ios or android app.

Flutter Embedding Plugin #

A Flutter plugin that enables seamless embedding of Flutter modules into native iOS and Android applications with bidirectional communication capabilities. This can also be used to embed Flutter modules into React Native applications.

Features #

  • Cross-platform Support: Works with both iOS and Android native applications
  • Bidirectional Communication: Send data between Flutter and native code in both directions
  • Theme Management: Runtime dynamic theme switching (light/dark/system)
  • Language Support: Runtime language switching capabilities
  • Environment Configuration: Support for multiple environments
  • React Native Compatibility: Includes workarounds for React Native layout issues
  • Fragment/ViewController Management: Easy integration with native UI components

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_embedding: ^0.0.1-beta.1

Then run:

fvm flutter pub get

Platform Setup #

Android #

The plugin automatically registers itself with the Flutter engine. No additional setup is required.

iOS #

The plugin automatically registers itself with the Flutter engine. No additional setup is required.

Usage #

Flutter Side #

1. Initialize the Embedding Controller

import 'package:flutter_embedding/flutter_embedding.dart';

void main(List<String> args) {
  // Initialize the embedding controller with configuration
  final embeddingController = EmbeddingController.fromArgs(args);
  
  runApp(MyApp(embeddingController: embeddingController));
}

2. Listen to Native Events

class MyApp extends StatelessWidget {
  final EmbeddingController embeddingController;
  
  const MyApp({Key? key, required this.embeddingController}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<ThemeMode>(
      valueListenable: embeddingController.themeMode,
      builder: (context, themeMode, child) {
        return MaterialApp(
          themeMode: themeMode,
          home: MyHomePage(embeddingController: embeddingController),
        );
      },
    );
  }
}

3. Handle Custom Handover Events

// Add handlers for custom events from native side
embeddingController.addHandoverHandler('resetCounter', (args, _) async {
  // Handle the reset counter event
  print('Counter reset with value: ${args['counter']}');
  return true;
});

embeddingController.addHandoverHandler('updateUserData', (args, _) async {
  // Handle user data update
  final userData = args['userData'] as Map<String, dynamic>;
  // Update your app state
  return true;
});

4. Send Events to Native Side

// Send data to native side
await embeddingController.invokeHandover('userAction', arguments: {
  'action': 'buttonPressed',
  'timestamp': DateTime.now().millisecondsSinceEpoch,
});

// Exit back to native app
embeddingController.exit();

5. React Native Compatibility

If you have issues with platform widgets (like WebView, MapView, etc.) in React Native which show without width and height, wrap them with the provided wrapper to ensure the React Native LayoutManager can properly layout them. The widget itself will only do something on Android.

import 'package:flutter_embedding/rn_native_component_wrapper.dart';

Widget build(BuildContext context) {
  return RnNativeComponentWrapper(
    child: YourFlutterWidget(),
  );
}

Native Side #

Android

import be.krispypen.plugins.flutter_embedding.FlutterEmbedding;
import be.krispypen.plugins.flutter_embedding.HandoverResponderInterface;

public class MainActivity extends FragmentActivity implements HandoverResponderInterface {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // Start the Flutter engine
        FlutterEmbedding.instance().startEngine(
            this,
            "PROD",           // environment
            "en",             // language
            "system",         // theme mode
            this,             // handover responder
            (success, error) -> {
                if (success) {
                    // Engine started successfully
                    showFlutterFragment();
                } else {
                    // Handle error
                    Log.e("FlutterEmbedding", "Failed to start engine", error);
                }
            }
        );
    }
    
    private void showFlutterFragment() {
        // Get or create the Flutter fragment
        FlutterEmbeddingFlutterFragment fragment = FlutterEmbedding.instance()
            .getOrCreateFragment(this, R.id.flutter_container);
    }
    
    // Implement HandoverResponderInterface
    @Override
    public void exit() {
        // Handle exit from Flutter
        finish();
    }
    
    @Override
    public void invokeHandover(String method, Map<String, Object> data, 
                              CompletionHandler<Object> completion) {
        // Handle custom events from Flutter
        switch (method) {
            case "userAction":
                // Handle user action
                completion.onSuccess("Action processed");
                break;
            default:
                completion.onFailure(new Exception("Unknown method: " + method));
        }
    }
}

iOS

import flutter_embedding

class ViewController: UIViewController, HandoverResponderProtocol {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Start the Flutter engine
        FlutterEmbedding.shared.startEngine(
            forEnv: "PROD",
            forLanguage: "en", 
            forThemeMode: "system",
            with: self
        ) { success, error in
            if success == true {
                // Engine started successfully
                self.showFlutterView()
            } else {
                // Handle error
                print("Failed to start Flutter engine: \(error?.localizedDescription ?? "Unknown error")")
            }
        }
    }
    
    private func showFlutterView() {
        do {
            let flutterViewController = try FlutterEmbedding.shared.getViewController()
            addChild(flutterViewController)
            view.addSubview(flutterViewController.view)
            flutterViewController.view.frame = view.bounds
            flutterViewController.didMove(toParent: self)
        } catch {
            print("Failed to get Flutter view controller: \(error)")
        }
    }
    
    // Implement HandoverResponderProtocol
    func exit() {
        // Handle exit from Flutter
        dismiss(animated: true)
    }
    
    func invokeHandover(withName name: String, data: [String : Any?], 
                       completion: @escaping (Any?, FlutterEmbeddingError?) -> Void) {
        // Handle custom events from Flutter
        switch name {
        case "userAction":
            // Handle user action
            completion("Action processed", nil)
        default:
            completion(nil, FlutterEmbeddingError.genericError(
                code: "UNKNOWN_METHOD", 
                message: "Unknown method: \(name)"
            ))
        }
    }
}

Configuration #

Environment Support #

You can pass the environment name when initializing the engine.

Theme Modes #

You can pass the theme mode when initializing the engine but it will also be dynamic and can be changed from the native side. Supported theme modes:

  • light - Light theme
  • dark - Dark theme
  • system - Follow system theme

Language Support #

The plugin supports dynamic language switching. Pass the language code (e.g., "en", "nl", "fr") when initializing the engine.

Flutter API Reference #

EmbeddingController #

The main controller class for managing Flutter embedding functionality.

Methods

  • EmbeddingController.fromArgs(List<String> args) - Create controller from command line arguments
  • addHandoverHandler(String method, Handler handler) - Add handler for native events
  • invokeHandover(String method, {Map<String, dynamic> arguments}) - Send event to native side
  • exit() - Exit back to native application

Properties

  • environment - Current environment (String)
  • themeMode - Current theme mode (ValueNotifier
  • language - Current language (ValueNotifier

RnNativeComponentWrapper #

A widget wrapper for React Native compatibility that handles layout issues.

Troubleshooting #

React Native Layout Issues #

If you're experiencing layout issues in React Native, ensure you wrap your Flutter widgets with RnNativeComponentWrapper. This addresses a known React Native bug with Flutter embedding.

Engine Not Starting #

Make sure you're calling the start engine methods on the main thread and that all required parameters are provided.

Communication Issues #

Verify that both Flutter and native sides are implementing the handover interfaces correctly and that method names match between both sides.

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

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

1
likes
0
points
264
downloads

Publisher

verified publisherkrispypen.be

Weekly Downloads

This project helps embedding into a native ios or android app.

Homepage

License

unknown (license)

Dependencies

flutter

More

Packages that depend on flutter_embedding

Packages that implement flutter_embedding