用途
本技能用于将 Flutter 应用与平台特定代码和原生功能集成,覆盖 Android、iOS 和 Web 环境。它会根据用户需求确定最优的互操作策略,并实现所需的 Dart 与原生代码绑定,同时遵循线程安全、WebAssembly(Wasm)兼容性以及现代构建钩子标准。
主要能力
技能通过决策逻辑选择集成路径,涵盖四类场景:
- 场景 A:调用原生 C/C++ 代码。使用 dart:ffi 配合 package_ffi 模板和构建钩子。例外情况:若需访问 Flutter Plugin 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 组件。
使用方式
C/C++ 互操作(dart:ffi)
若选择场景 A,使用构建钩子(Flutter 3.38+)实现现代 FFI 架构。
生成包:
flutter create --template=package_ffi native_add
配置构建钩子(hook/build.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);
});
}
在 Dart 中绑定原生函数(lib/src/native_add.dart):
import 'dart:ffi';
@Native<Int32 Function(Int32, Int32)>()
external int sum(int a, int b);
Platform Channels(MethodChannel)
若选择场景 B,实现异步消息传递。
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):
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):
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)
}
}
Platform Views
若选择场景 C,嵌入原生视图。
Dart 实现(iOS 示例):
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):
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>") 注册。
Web 集成(Wasm 与 JS Interop)
若选择场景 D,实现 Wasm 兼容的 Web 集成。
JS Interop(Dart):
import 'dart:js_interop';
import 'package:web/web.dart' as web;
@JS('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 元素:
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%';
});
}
适用场景
- 需要在 Flutter 应用中调用 C/C++ 原生库。
- 需要调用 Android(Java/Kotlin)或 iOS(Swift/Obj-C)的操作系统特定 API。
- 需要将原生 UI 组件嵌入 Flutter widget 树。
- 需要进行 Web 集成或调用 JavaScript API,并希望保持 Wasm 兼容。
限制与约束
- 线程安全:在平台侧调用面向 Flutter 的 channel 方法时,必须在平台的主/UI 线程上调用。若从后台线程跳转,Android 使用 Handler(Looper.getMainLooper()).post,iOS 使用 DispatchQueue.main.async。
- 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 渲染性能。