flutter-native-interop
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFlutter 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 with the
dart:ffitemplate and build hooks.package_ffi - Exception: If accessing the Flutter Plugin API or requiring static linking on iOS, use the legacy template.
plugin_ffi
- Action: Use
- Scenario B: Calling OS-specific APIs (Java/Kotlin for Android, Swift/Obj-C for iOS).
- Action: Use Platform Channels () or the
MethodChannelpackage for type-safe code generation.pigeon
- Action: Use Platform Channels (
- Scenario C: Embedding native UI components into the Flutter widget tree.
- Action: Use Platform Views (/
AndroidViewfor Android,AndroidViewSurfacefor iOS).UiKitView
- Action: Use Platform Views (
- Scenario D: Web integration and JavaScript APIs.
- Action: Use and
package:web(Wasm-compatible). Usedart:js_interopfor embedding web content.HtmlElementView
- Action: Use
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_ffidart:ffi - 例外情况: 如果需要访问Flutter插件API或要求在iOS上静态链接,请使用旧版模板
plugin_ffi
- 操作: 搭配
- 场景B:调用操作系统特定API(Android端为Java/Kotlin,iOS端为Swift/Obj-C)
- 操作: 使用Platform Channels()或
MethodChannel包实现类型安全的代码生成pigeon
- 操作: 使用Platform Channels(
- 场景C:将原生UI组件嵌入到Flutter widget树中
- 操作: 使用Platform Views(Android端为/
AndroidView,iOS端为AndroidViewSurface)UiKitView
- 操作: 使用Platform Views(Android端为
- 场景D:Web集成和JavaScript API
- 操作: 使用和
package:web(兼容Wasm)。使用dart:js_interop嵌入Web内容HtmlElementView
- 操作: 使用
**停止并询问用户:"你目标的平台是哪些,需要集成什么具体的原生功能或UI组件?"
2. Implement C/C++ Interop (dart:ffi
)
dart:ffi2. 实现C/C++互操作(dart:ffi
)
dart:ffiIf Scenario A is selected, implement the modern FFI architecture using build hooks (Flutter 3.38+).
- Generate the package:
bash
flutter create --template=package_ffi native_add - Configure the build hook () to compile the native code:
hook/build.dartdartimport '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); }); } - Bind the native function in Dart ():
lib/src/native_add.dartdartimport 'dart:ffi'; <Int32 Function(Int32, Int32)>() external int sum(int a, int b);
如果选择场景A,请使用构建钩子实现现代化FFI架构(Flutter 3.38+版本支持)
- 生成包:
bash
flutter create --template=package_ffi native_add - 配置构建钩子()编译原生代码:
hook/build.dartdartimport '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); }); } - 在Dart中绑定原生函数():
lib/src/native_add.dartdartimport '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.
- 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}'."; } } } - 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() } } } } - 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,请实现异步消息传递
- 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}'."; } } } - **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() } } } } - **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.
- 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(), ); } - iOS Factory Implementation (Swift):
Validate-and-Fix: Ensure the factory is registered inswift
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 } }usingAppDelegate.swift.registrar.register(factory, withId: "<platform-view-type>")
如果选择场景C,请嵌入原生视图
- 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(), ); } - 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.
- 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); } - 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集成
- **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); } - 嵌入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 (Android) or
Handler(Looper.getMainLooper()).post(iOS) if jumping from a background thread.DispatchQueue.main.async - WebAssembly Compatibility: DO NOT use ,
dart:html, ordart:js. You MUST usepackage:jsandpackage:webto ensure the app compiles to Wasm.dart:js_interop - 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 hooks for Apple platforms, dynamic libraries MUST have consistent filenames across all target architectures (e.g., do not use
build.dart).lib_arm64.dylib - Platform View Performance: Handling on Android via Platform Views is problematic and should be avoided when possible. Prefer
SurfaceViewfor better Flutter rendering performance.TextureLayerHybridComposition
- 线程安全: 当你在平台侧调用要发送到Flutter的通道方法时,必须在平台的主线程/UI线程调用。如果从后台线程跳转,请使用(Android)或
Handler(Looper.getMainLooper()).post(iOS)DispatchQueue.main.async - WebAssembly兼容性: 不要使用、
dart:html或dart:js。必须使用package:js和package:web来确保应用可以编译为Wasmdart:js_interop - Wasm iOS限制: 由于WebKit的限制,编译为Wasm的Flutter目前无法在任何浏览器的iOS版本上运行。请确保保留回退到JS编译的功能可用
- FFI命名规范: 当为Apple平台实现钩子时,动态库在所有目标架构上的文件名必须保持一致(例如不要使用
build.dart)lib_arm64.dylib - Platform View性能: 通过Platform Views在Android上处理存在问题,应尽可能避免。优先使用
SurfaceView以获得更好的Flutter渲染性能TextureLayerHybridComposition