flutter-native-interop

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Flutter Platform Integration

Flutter平台集成

Goal

目标

Integrates Flutter applications with platform-specific code and native features across Android, iOS, and Web environments. Determines the optimal interoperability strategy (FFI, Platform Channels, Platform Views, or JS Interop) and implements the necessary Dart and native code bindings while adhering to thread safety, WebAssembly (Wasm) compatibility, and modern build hook standards.
在Android、iOS和Web环境下将Flutter应用与平台特定代码和原生功能集成。确定最优互操作策略(FFI、Platform Channels、Platform Views或JS Interop),并实现必要的Dart和原生代码绑定,同时遵循线程安全、WebAssembly(Wasm)兼容性和现代构建钩子标准。

Instructions

使用说明

1. Determine Integration Strategy (Decision Logic)

1. 确定集成策略(决策逻辑)

Evaluate the user's requirements using the following decision tree to select the correct integration path:
  • Scenario A: Calling native C/C++ code.
    • Action: Use
      dart:ffi
      with the
      package_ffi
      template and build hooks.
    • Exception: If accessing the Flutter Plugin API or requiring static linking on iOS, use the legacy
      plugin_ffi
      template.
  • Scenario B: Calling OS-specific APIs (Java/Kotlin for Android, Swift/Obj-C for iOS).
    • Action: Use Platform Channels (
      MethodChannel
      ) or the
      pigeon
      package for type-safe code generation.
  • Scenario C: Embedding native UI components into the Flutter widget tree.
    • Action: Use Platform Views (
      AndroidView
      /
      AndroidViewSurface
      for Android,
      UiKitView
      for iOS).
  • Scenario D: Web integration and JavaScript APIs.
    • Action: Use
      package:web
      and
      dart:js_interop
      (Wasm-compatible). Use
      HtmlElementView
      for embedding web content.
STOP AND ASK THE USER: "Which platform(s) are you targeting, and what specific native functionality or UI component do you need to integrate?"
使用以下决策树评估用户需求,选择正确的集成路径:
  • 场景A:调用原生C/C++代码
    • 操作: 搭配
      package_ffi
      模板和构建钩子使用
      dart:ffi
    • 例外情况: 如果需要访问Flutter插件API或要求在iOS上静态链接,请使用旧版
      plugin_ffi
      模板
  • 场景B:调用操作系统特定API(Android端为Java/Kotlin,iOS端为Swift/Obj-C)
    • 操作: 使用Platform Channels(
      MethodChannel
      )或
      pigeon
      包实现类型安全的代码生成
  • 场景C:将原生UI组件嵌入到Flutter widget树中
    • 操作: 使用Platform Views(Android端为
      AndroidView
      /
      AndroidViewSurface
      ,iOS端为
      UiKitView
  • 场景D:Web集成和JavaScript API
    • 操作: 使用
      package:web
      dart:js_interop
      (兼容Wasm)。使用
      HtmlElementView
      嵌入Web内容
**停止并询问用户:"你目标的平台是哪些,需要集成什么具体的原生功能或UI组件?"

2. Implement C/C++ Interop (
dart:ffi
)

2. 实现C/C++互操作(
dart:ffi

If Scenario A is selected, implement the modern FFI architecture using build hooks (Flutter 3.38+).
  1. Generate the package:
    bash
    flutter create --template=package_ffi native_add
  2. Configure the build hook (
    hook/build.dart
    ) to compile the native code:
    dart
    import 'package:hooks/hooks.dart';
    import 'package:native_toolchain_c/native_toolchain_c.dart';
    
    void main(List<String> args) async {
      await build(args, (config, output) async {
        final builder = CBuilder.library(
          name: 'native_add',
          assetId: 'native_add/src/native_add.dart',
          sources: ['src/native_add.c'],
        );
        await builder.run(config: config, output: output);
      });
    }
  3. Bind the native function in Dart (
    lib/src/native_add.dart
    ):
    dart
    import 'dart:ffi';
    
    <Int32 Function(Int32, Int32)>()
    external int sum(int a, int b);
如果选择场景A,请使用构建钩子实现现代化FFI架构(Flutter 3.38+版本支持)
  1. 生成包:
    bash
    flutter create --template=package_ffi native_add
  2. 配置构建钩子(
    hook/build.dart
    )编译原生代码:
    dart
    import 'package:hooks/hooks.dart';
    import 'package:native_toolchain_c/native_toolchain_c.dart';
    
    void main(List<String> args) async {
      await build(args, (config, output) async {
        final builder = CBuilder.library(
          name: 'native_add',
          assetId: 'native_add/src/native_add.dart',
          sources: ['src/native_add.c'],
        );
        await builder.run(config: config, output: output);
      });
    }
  3. 在Dart中绑定原生函数(
    lib/src/native_add.dart
    ):
    dart
    import 'dart:ffi';
    
    <Int32 Function(Int32, Int32)>()
    external int sum(int a, int b);

3. Implement Platform Channels (MethodChannel)

3. 实现Platform Channels(MethodChannel)

If Scenario B is selected, implement asynchronous message passing.
  1. Dart Client Implementation:
    dart
    import 'package:flutter/services.dart';
    
    class NativeApi {
      static const platform = MethodChannel('com.example.app/channel');
    
      Future<String> getNativeData() async {
        try {
          final String result = await platform.invokeMethod('getData');
          return result;
        } on PlatformException catch (e) {
          return "Error: '${e.message}'.";
        }
      }
    }
  2. Android Host Implementation (Kotlin):
    kotlin
    import androidx.annotation.NonNull
    import io.flutter.embedding.android.FlutterActivity
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodChannel
    
    class MainActivity: FlutterActivity() {
      private val CHANNEL = "com.example.app/channel"
    
      override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
          if (call.method == "getData") {
            result.success("Data from Android")
          } else {
            result.notImplemented()
          }
        }
      }
    }
  3. iOS Host Implementation (Swift):
    swift
    import Flutter
    import UIKit
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel(name: "com.example.app/channel", binaryMessenger: controller.binaryMessenger)
        
        channel.setMethodCallHandler({
          (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
          if call.method == "getData" {
            result("Data from iOS")
          } else {
            result(FlutterMethodNotImplemented)
          }
        })
    
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
如果选择场景B,请实现异步消息传递
  1. Dart客户端实现:
    dart
    import 'package:flutter/services.dart';
    
    class NativeApi {
      static const platform = MethodChannel('com.example.app/channel');
    
      Future<String> getNativeData() async {
        try {
          final String result = await platform.invokeMethod('getData');
          return result;
        } on PlatformException catch (e) {
            return "Error: '${e.message}'.";
          }
        }
      }
  2. **Android端实现(Kotlin):
    kotlin
    import androidx.annotation.NonNull
    import io.flutter.embedding.android.FlutterActivity
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodChannel
    
    class MainActivity: FlutterActivity() {
      private val CHANNEL = "com.example.app/channel"
    
      override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
          if (call.method == "getData") {
            result.success("Data from Android")
          } else {
            result.notImplemented()
          }
        }
      }
    }
  3. **iOS端实现(Swift):
    swift
    import Flutter
    import UIKit
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel(name: "com.example.app/channel", binaryMessenger: controller.binaryMessenger)
        
        channel.setMethodCallHandler({
          (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
          if call.method == "getData" {
            result("Data from iOS")
          } else {
            result(FlutterMethodNotImplemented)
          }
        })
    
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }

4. Implement Platform Views

4. 实现Platform Views

If Scenario C is selected, embed native views.
  1. Dart Implementation (iOS Example):
    dart
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    Widget buildNativeView() {
      const String viewType = '<platform-view-type>';
      final Map<String, dynamic> creationParams = <String, dynamic>{};
    
      return UiKitView(
        viewType: viewType,
        layoutDirection: TextDirection.ltr,
        creationParams: creationParams,
        creationParamsCodec: const StandardMessageCodec(),
      );
    }
  2. iOS Factory Implementation (Swift):
    swift
    import Flutter
    import UIKit
    
    class FLNativeViewFactory: NSObject, FlutterPlatformViewFactory {
        private var messenger: FlutterBinaryMessenger
    
        init(messenger: FlutterBinaryMessenger) {
            self.messenger = messenger
            super.init()
        }
    
        func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
            return FLNativeView(frame: frame, viewIdentifier: viewId, arguments: args, binaryMessenger: messenger)
        }
    
        public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
              return FlutterStandardMessageCodec.sharedInstance()
        }
    }
    
    class FLNativeView: NSObject, FlutterPlatformView {
        private var _view: UIView
    
        init(frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger messenger: FlutterBinaryMessenger?) {
            _view = UIView()
            super.init()
            _view.backgroundColor = UIColor.blue
        }
    
        func view() -> UIView { return _view }
    }
    Validate-and-Fix: Ensure the factory is registered in
    AppDelegate.swift
    using
    registrar.register(factory, withId: "<platform-view-type>")
    .
如果选择场景C,请嵌入原生视图
  1. Dart实现(iOS示例):
    dart
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    Widget buildNativeView() {
      const String viewType = '<platform-view-type>';
      final Map<String, dynamic> creationParams = <String, dynamic>{};
    
      return UiKitView(
        viewType: viewType,
        layoutDirection: TextDirection.ltr,
        creationParams: creationParams,
        creationParamsCodec: const StandardMessageCodec(),
      );
    }
  2. iOS工厂实现(Swift):
    swift
    import Flutter
    import UIKit
    
    class FLNativeViewFactory: NSObject, FlutterPlatformViewFactory {
        private var messenger: FlutterBinaryMessenger
    
        init(messenger: FlutterBinaryMessenger) {
            self.messenger = messenger
            super.init()
        }
    
        func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
            return FLNativeView(frame: frame, viewIdentifier: viewId, arguments: args, binaryMessenger: messenger)
        }
    
        public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
              return FlutterStandardMessageCodec.sharedInstance()
        }
    }
    
    class FLNativeView: NSObject, FlutterPlatformView {
        private var _view: UIView
    
        init(frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger messenger: FlutterBinaryMessenger?) {
            _view = UIView()
            super.init()
            _view.backgroundColor = UIColor.blue
        }
    
        func view() -> UIView { return _view }
    }
    验证修复: 确保工厂已在
    AppDelegate.swift
    中通过
    registrar.register(factory, withId: "<platform-view-type>")
    完成注册

5. Implement Web Integration (Wasm & JS Interop)

5. 实现Web集成(Wasm & JS Interop)

If Scenario D is selected, implement Wasm-compatible web integrations.
  1. JS Interop (Dart):
    dart
    import 'dart:js_interop';
    import 'package:web/web.dart' as web;
    
    ('console.log')
    external void log(JSAny? value);
    
    void manipulateDOM() {
      final div = web.document.createElement('div') as web.HTMLDivElement;
      div.text = "Hello from Wasm-compatible Dart!";
      web.document.body?.append(div);
      log("DOM updated".toJS);
    }
  2. Embedding HTML Elements:
    dart
    import 'package:flutter/widgets.dart';
    import 'package:web/web.dart' as web;
    
    Widget buildVideoElement() {
      return HtmlElementView.fromTag('video', onElementCreated: (Object video) {
        final videoElement = video as web.HTMLVideoElement;
        videoElement.src = 'https://example.com/video.mp4';
        videoElement.style.width = '100%';
        videoElement.style.height = '100%';
      });
    }
如果选择场景D,请实现兼容Wasm的Web集成
  1. **JS互操作(Dart):
    dart
    import 'dart:js_interop';
    import 'package:web/web.dart' as web;
    
    ('console.log')
    external void log(JSAny? value);
    
    void manipulateDOM() {
      final div = web.document.createElement('div') as web.HTMLDivElement;
      div.text = "Hello from Wasm-compatible Dart!";
      web.document.body?.append(div);
      log("DOM updated".toJS);
    }
  2. 嵌入HTML元素:
    dart
    import 'package:flutter/widgets.dart';
    import 'package:web/web.dart' as web;
    
    Widget buildVideoElement() {
      return HtmlElementView.fromTag('video', onElementCreated: (Object video) {
        final videoElement = video as web.HTMLVideoElement;
        videoElement.src = 'https://example.com/video.mp4';
        videoElement.style.width = '100%';
        videoElement.style.height = '100%';
      });
    }

Constraints

约束条件

  • Thread Safety: Whenever you invoke a channel method on the platform side destined for Flutter, you MUST invoke it on the platform's main/UI thread. Use
    Handler(Looper.getMainLooper()).post
    (Android) or
    DispatchQueue.main.async
    (iOS) if jumping from a background thread.
  • WebAssembly Compatibility: DO NOT use
    dart:html
    ,
    dart:js
    , or
    package:js
    . You MUST use
    package:web
    and
    dart:js_interop
    to ensure the app compiles to Wasm.
  • Wasm iOS Limitation: Flutter compiled to Wasm currently CANNOT run on the iOS version of any browser due to WebKit limitations. Ensure fallback to JS compilation is maintained.
  • FFI Naming: When implementing
    build.dart
    hooks for Apple platforms, dynamic libraries MUST have consistent filenames across all target architectures (e.g., do not use
    lib_arm64.dylib
    ).
  • Platform View Performance: Handling
    SurfaceView
    on Android via Platform Views is problematic and should be avoided when possible. Prefer
    TextureLayerHybridComposition
    for better Flutter rendering performance.
  • 线程安全: 当你在平台侧调用要发送到Flutter的通道方法时,必须在平台的主线程/UI线程调用。如果从后台线程跳转,请使用
    Handler(Looper.getMainLooper()).post
    (Android)或
    DispatchQueue.main.async
    (iOS)
  • WebAssembly兼容性: 不要使用
    dart:html
    dart:js
    package:js
    。必须使用
    package:web
    dart:js_interop
    来确保应用可以编译为Wasm
  • Wasm iOS限制: 由于WebKit的限制,编译为Wasm的Flutter目前无法在任何浏览器的iOS版本上运行。请确保保留回退到JS编译的功能可用
  • FFI命名规范: 当为Apple平台实现
    build.dart
    钩子时,动态库在所有目标架构上的文件名必须保持一致(例如不要使用
    lib_arm64.dylib
  • Platform View性能: 通过Platform Views在Android上处理
    SurfaceView
    存在问题,应尽可能避免。优先使用
    TextureLayerHybridComposition
    以获得更好的Flutter渲染性能