- 创建一个插件
flutter create --template=plugin --platforms=android,ios,windows flutter_plugin
- 目录结构
flutter_plugin/
├── android/ # Android 平台代码
├── ios/ # iOS 平台代码
├── lib/ # 插件的 Dart 代码
├── macos/ # macOS 平台代码
├── test/ # 插件的测试代码
├── windows/ # Windows 平台代码
├── pubspec.yaml # 插件的配置信息
└── example/ # 示例应用,用于展示插件如何工作
3.编写插件的dart代码
在 lib/flutter_plugin.dart 文件中,你可以定义插件的 Dart API,通常是通过 MethodChannel 来调用平台特定的代码。
3.1编辑 lib/flutter_plugin.dart:
import 'flutter_plugin_platform_interface.dart';
class FlutterPlugin {
Future<String?> getPlatformVersion() {
return FlutterPluginPlatform.instance.getPlatformVersion();
}
Future<int> add(int a,int b) {
return FlutterPluginPlatform.instance.add(a,b);
}
}
3.2lib/flutter_plugin_platform_interface.dart:
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'flutter_plugin_method_channel.dart';
abstract class FlutterPluginPlatform extends PlatformInterface {
/// Constructs a FlutterPluginPlatform.
FlutterPluginPlatform() : super(token: _token);
static final Object _token = Object();
static FlutterPluginPlatform _instance = MethodChannelFlutterPlugin();
/// The default instance of [FlutterPluginPlatform] to use.
///
/// Defaults to [MethodChannelFlutterPlugin].
static FlutterPluginPlatform get instance => _instance;
/// Platform-specific implementations should set this with their own
/// platform-specific class that extends [FlutterPluginPlatform] when
/// they register themselves.
static set instance(FlutterPluginPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Future<String?> getPlatformVersion() {
throw UnimplementedError('platformVersion() has not been implemented.');
}
Future<int> add(int a,int b) {
throw UnimplementedError('add() has not been implemented.');
}
}
3.3编辑 lib/flutter_plugin_methoed_channel.dart:
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'flutter_plugin_platform_interface.dart';
/// An implementation of [FlutterPluginPlatform] that uses method channels.
class MethodChannelFlutterPlugin extends FlutterPluginPlatform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel('flutter_plugin');
@override
Future<String?> getPlatformVersion() async {
final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
return version;
}
@override
Future<int> add(int a,int b) async {
final sum = await methodChannel.invokeMethod<int>('add',{'a':a,'b':b});
return sum??0;
}
}
4.实现平台代码
#include "flutter_plugin.h"
// This must be included before many other Windows headers.
#include <windows.h>
// For getPlatformVersion; remove unless needed for your plugin implementation.
#include <VersionHelpers.h>
#include <flutter/method_channel.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>
#include <memory>
#include <sstream>
namespace flutter_plugin {
// static
void FlutterPlugin::RegisterWithRegistrar(
flutter::PluginRegistrarWindows *registrar) {
auto channel =
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
registrar->messenger(), "flutter_plugin",
&flutter::StandardMethodCodec::GetInstance());
auto plugin = std::make_unique<FlutterPlugin>();
channel->SetMethodCallHandler(
[plugin_pointer = plugin.get()](const auto &call, auto result) {
plugin_pointer->HandleMethodCall(call, std::move(result));
});
registrar->AddPlugin(std::move(plugin));
}
FlutterPlugin::FlutterPlugin() {}
FlutterPlugin::~FlutterPlugin() {}
void FlutterPlugin::HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue> &method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
if (method_call.method_name().compare("getPlatformVersion") == 0) {
std::ostringstream version_stream;
version_stream << "Windows ";
if (IsWindows10OrGreater()) {
version_stream << "10+";
} else if (IsWindows8OrGreater()) {
version_stream << "8";
} else if (IsWindows7OrGreater()) {
version_stream << "7";
}
result->Success(flutter::EncodableValue(version_stream.str()));
} else if((method_call.method_name().compare("add") == 0)){
const auto* arguments =
std::get_if<flutter::EncodableMap>(method_call.arguments());
auto a = arguments->find(flutter::EncodableValue("a"));
auto b = arguments->find(flutter::EncodableValue("b"));
//first is key;second is value
int valueA = std::get<int>(a->second);
int valueB = std::get<int>(b->second);
int sum = valueA + valueB;
result->Success(flutter::EncodableValue(sum));
}else {
result->NotImplemented();
}
}
} // namespace flutter_plugin
5.测试
import 'dart:developer';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_plugin/flutter_plugin.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
final _firstPluginFlutterPlugin = FlutterPlugin();
TextEditingController a = TextEditingController(text: '0');
TextEditingController b = TextEditingController(text: '1');
int sum = 1;
getInt(String sInt) {
if (sInt.isNotEmpty) {
return int.parse(sInt);
}
}
getSumInt() async {
if (a.text.isNotEmpty) {
int c = (int.parse(a.text) + 1);
sum = await _firstPluginFlutterPlugin.add(int.parse(b.text), c);
a.text = c.toString();
}
}
@override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try {
platformVersion = await _firstPluginFlutterPlugin.getPlatformVersion() ?? 'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
children: [
Text('Running on: $_platformVersion\n'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 200,
child: TextField(
controller: a,
decoration: const InputDecoration(
border: OutlineInputBorder(),
),
onChanged: (v) async {
if (v.isNotEmpty) {
sum = await _firstPluginFlutterPlugin.add(getInt(a.text), getInt(b.text));
setState(() {});
}
},
),
),
const SizedBox(
width: 20,
),
SizedBox(
width: 200,
child: TextField(
controller: b,
decoration: const InputDecoration(
border: OutlineInputBorder(),
),
onChanged: (v) async {
if (v.isNotEmpty) {
sum = await _firstPluginFlutterPlugin.add(getInt(a.text), getInt(b.text));
setState(() {});
}
;
},
),
),
Text(' = $sum'),
],
),
const SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () async {
await getSumInt();
setState(() {});
},
child: const Text('sum+1'))
],
),
),
),
);
}
}