当 pub.dev 上没有满足需求的插件时,可以自己开发 Flutter 插件,封装原生能力。Pigeon 工具提供类型安全的跨语言通信。
一、创建 Flutter 插件
flutter create--template=plugin\--platforms=android,ios\--orgcom.example\my_plugin插件结构:
my_plugin/ ├── lib/ │ └── my_plugin.dart # Dart 公共 API ├── android/ │ └── src/main/kotlin/... │ └── MyPlugin.kt # Android 实现 ├── ios/ │ └── Sources/my_plugin/ │ └── MyPlugin.swift # iOS 实现 ├── test/ │ └── my_plugin_test.dart ├── example/ │ └── lib/main.dart # 示例 App └── pubspec.yaml二、实现插件(以设备信息为例)
2.1 Dart 接口层
// lib/my_plugin.dartclassMyPlugin{staticconstMethodChannel_channel=MethodChannel('my_plugin');staticFuture<String?>getDeviceModel()async{return_channel.invokeMethod<String>('getDeviceModel');}staticFuture<String?>getOsVersion()async{return_channel.invokeMethod<String>('getOsVersion');}staticFuture<Map<String,dynamic>?>getDeviceInfo()async{finalresult=await_channel.invokeMethod<Map<Object?,Object?>>('getDeviceInfo');returnresult?.map((k,v)=>MapEntry(k.toString(),v));}}2.2 Android 实现
// android/.../MyPlugin.ktclassMyPlugin:FlutterPlugin,MethodCallHandler{privatelateinitvarchannel:MethodChannelprivatelateinitvarcontext:ContextoverridefunonAttachedToEngine(binding:FlutterPlugin.FlutterPluginBinding){context=binding.applicationContext channel=MethodChannel(binding.binaryMessenger,"my_plugin")channel.setMethodCallHandler(this)}overridefunonMethodCall(call:MethodCall,result:Result){when(call.method){"getDeviceModel"->result.success(Build.MODEL)"getOsVersion"->result.success(Build.VERSION.RELEASE)"getDeviceInfo"->result.success(mapOf("model"toBuild.MODEL,"brand"toBuild.BRAND,"osVersion"toBuild.VERSION.RELEASE,"sdkInt"toBuild.VERSION.SDK_INT,))else->result.notImplemented()}}overridefunonDetachedFromEngine(binding:FlutterPlugin.FlutterPluginBinding){channel.setMethodCallHandler(null)}}三、Pigeon(类型安全通信)
Pigeon 通过代码生成确保 Dart 和原生之间的 API 类型一致。
dev_dependencies:pigeon:^18.0.03.1 定义 Pigeon API
// pigeons/messages.dartimport'package:pigeon/pigeon.dart';// 输出配置@ConfigurePigeon(PigeonOptions(dartOut:'lib/src/messages.g.dart',kotlinOut:'android/src/main/kotlin/.../Messages.g.kt',swiftOut:'ios/Sources/my_plugin/Messages.g.swift',))// 数据类(自动生成 Kotlin/Swift 对应类)classDeviceInfo{String?model;String?brand;int?sdkVersion;}// Flutter 调用原生(HostApi)@HostApi()abstractclassDeviceInfoApi{DeviceInfogetInfo();@asyncStringgetUniqueId();}// 原生调用 Flutter(FlutterApi)@FlutterApi()abstractclassEventFlutterApi{voidonBatteryChanged(int level);}# 生成代码dart run pigeon--inputpigeons/messages.dart3.2 使用生成的类型安全 API
// 使用生成的 Dart 类finalapi=DeviceInfoApi();finalinfo=awaitapi.getInfo();print('Model:${info.model}, SDK:${info.sdkVersion}');四、使用现有插件原理
dependencies:camera:^0.10.5image_picker:^1.0.7大多数 Flutter 插件都采用 Platform Channel 模式:
- Dart 层:提供简洁的 API(如
ImagePicker().pickImage()) - Platform 层:Android 调用 Camera API / iOS 调用 PHPickerViewController
- 通道:通过 MethodChannel 双向通信
小结
| 方式 | 类型安全 | 适用场景 |
|---|---|---|
| 手写 MethodChannel | ❌ 运行时检查 | 快速原型 |
| Pigeon | ✅ 编译期 | 生产插件推荐 |
| 使用 pub.dev 插件 | ✅(取决于插件) | 优先使用现有插件 |
👉 下一节:9.3 多端支持