用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/xuelongqy/flutter_easy_refresh --skill flutter-native-interop命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | flutter-native-interop |
| description | Interoperate with native APIs in a Flutter app on Android, iOS, and the web |
| metadata | {"model":"models/gemini-3.1-pro-preview","last_modified":"Wed, 04 Mar 2026 19:26:40 GMT"} |
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.
Evaluate the user's requirements using the following decision tree to select the correct integration path:
dart:ffi with the package_ffi template and build hooks.plugin_ffi template.MethodChannel) or the pigeon package for type-safe code generation.AndroidView / AndroidViewSurface for Android, UiKitView for iOS).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?"
dart:ffi)If Scenario A is selected, implement the modern FFI architecture using build hooks (Flutter 3.38+).
flutter create --template=package_ffi native_add
hook/build.dart) to compile the native code:
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);
});
}
lib/src/native_add.dart):
import 'dart:ffi';
@Native<Int32 Function(Int32, Int32)>()
external int sum(int a, int b);
If Scenario B is selected, implement asynchronous message passing.
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}'.";
}
}
}
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()
}
}
}
}
import Flutter
import UIKit
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ : ,
: [.: ]
) -> {
controller : window.rootViewController
channel (name: , binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({
(call: , result: ) ->
call.method {
result()
} {
result()
}
})
.register(with: )
.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
If Scenario C is selected, embed native views.
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(),
);
}
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()
}
}
: , {
_view:
(: , : , : , : ?) {
_view ()
.()
_view.backgroundColor .blue
}
() -> { _view }
}
Ensure the factory is registered in using .If Scenario D is selected, implement Wasm-compatible web integrations.
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);
}
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%';
});
}
Handler(Looper.getMainLooper()).post (Android) or DispatchQueue.main.async (iOS) if jumping from a background thread.dart:html, dart:js, or package:js. You MUST use package:web and dart:js_interop to ensure the app compiles to Wasm.build.dart hooks for Apple platforms, dynamic libraries MUST have consistent filenames across all target architectures (e.g., do not use lib_arm64.dylib).SurfaceView on Android via Platform Views is problematic and should be avoided when possible. Prefer TextureLayerHybridComposition for better Flutter rendering performance.AppDelegate.swiftregistrar.register(factory, withId: "<platform-view-type>")