个人博客:http://www.milovetingting.cn
新建项目
项目结构
创建完成后的目录如图所示,其中example
是测试工程,用来测试我们写的插件。lib
目录下的文件,就是需要具体实现的。
flutter_plugin_platform_interface.dart
文件就是我们定义接口的地方,flutter_plugin_method_channel.dart
是对应Andoid
、IOS
的文件,flutter_plugin_web.dart
是对应web
平台。
方法实现 Android
、IOS
平台要分别实现flutter_plugin_platform_interface.dart
定义的方法。这里以Android
和Web
为例,实现接口中的方法。
Android端 1、在android
目录上点击右键,选择Flutter
菜单下的Open Android module in Android Studio
2、打开后的界面如下
我们主要在FlutterPlugin
这个文件的onMethodCall
方法中做具体实现
无参方法的调用 1、在flutter_plugin_platform_interface.dart
类中增加方法
1 2 3 Future<String? > hello(){ throw UnimplementedError('hello() has not been implemented.' ); }
2、在flutter_plugin_method_channel.dart
类中实现上面的方法
1 2 3 4 5 @override Future<String? > hello() async { final msg = await methodChannel.invokeMethod<String >('hello' ); return msg; }
3、在flutter_plugin.dart
中调用
1 2 3 Future<String? > hello() { return FlutterPluginPlatform.instance.hello(); }
4、Android
端实现
FlutterPlugin.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 override fun onMethodCall (@NonNull call: MethodCall , @NonNull result: Result ) { when (call.method) { "getPlatformVersion" -> { result.success("Android ${android.os.Build.VERSION.RELEASE} " ) } "hello" -> { result.success("Android invoke==>hello()" ) } else -> { result.notImplemented() } } }
5、在Example
中测试
main.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 import 'package:flutter/foundation.dart' ;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' ; String? _msg; final _flutterPlugin = FlutterPlugin(); @override void initState() { super .initState(); initPlatformState(); } Future<void > initPlatformState() async { String platformVersion; try { platformVersion = await _flutterPlugin.getPlatformVersion() ?? 'Unknown platform version' ; } on PlatformException { platformVersion = 'Failed to get platform version.' ; } 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' ), Text('msg: ${_msg ?? "" } \n' ), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.hello(); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用hello" )), ], ), ), ), ); } }
6、测试结果
可以看出,成功调用到了Android
端的方法
有参方法的调用 1、在flutter_plugin_platform_interface.dart
类中增加方法
1 2 3 Future<String? > hi(String message){ throw UnimplementedError('hi() has not been implemented.' ); }
2、在flutter_plugin_method_channel.dart
类中实现上面的方法
1 2 3 4 5 6 7 @override Future<String? > hi(String message) async { Map <String , dynamic > param = <String , dynamic >{}; param["message" ] = message; final msg = await methodChannel.invokeMethod<String >('hi' , param); return msg; }
3、在flutter_plugin.dart
中调用
1 2 3 Future<String? > hi(String message) { return FlutterPluginPlatform.instance.hi(message); }
4、Android
端实现
FlutterPlugin.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 override fun onMethodCall (@NonNull call: MethodCall , @NonNull result: Result ) { when (call.method) { "getPlatformVersion" -> { result.success("Android ${android.os.Build.VERSION.RELEASE} " ) } "hello" -> { result.success("Android invoke==>hello()" ) } "hi" -> { val param = call.arguments as Map<String, String> result.success("Android invoke==>hi(${param["message" ]} )" ) } else -> { result.notImplemented() } } }
5、在Example
中测试
main.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 @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' ), Text('msg: ${_msg ?? "" } \n' ), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.hello(); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用hello" )), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.hi("hi" ); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用hi(msg)" )), ], ), ), ), ); }
Map参数方法调用 1、在flutter_plugin_platform_interface.dart
类中增加方法
1 2 3 Future<String? > hey(String message){ throw UnimplementedError('hey() has not been implemented.' ); }
2、在flutter_plugin_method_channel.dart
类中实现上面的方法
1 2 3 4 5 6 7 8 @override Future<String? > hey(String message) async { Map <String , dynamic > param = <String , dynamic >{}; param["message" ] = message; final msg = await methodChannel.invokeMethod<Map <dynamic , dynamic >>('hey' , param); return msg?["message" ]; }
3、在flutter_plugin.dart
中调用
1 2 3 Future<String? > hey(String message) { return FlutterPluginPlatform.instance.hey(message); }
4、Android
端实现
FlutterPlugin.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 override fun onMethodCall (@NonNull call: MethodCall , @NonNull result: Result ) { when (call.method) { "getPlatformVersion" -> { result.success("Android ${android.os.Build.VERSION.RELEASE} " ) } "hello" -> { result.success("Android invoke==>hello()" ) } "hi" -> { val param = call.arguments as Map<String, String> result.success("Android invoke==>hi(${param["message" ]} )" ) } "hey" -> { val param = call.arguments as Map<String, String> val response = mutableMapOf<String, String>() response["message" ] = "Android invoke==>hey(${param["message" ]} )" result.success(response) } else -> { result.notImplemented() } } }
5、在Example
中测试
main.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 @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' ), Text('msg: ${_msg ?? "" } \n' ), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.hello(); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用hello" )), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.hi("hi" ); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用hi(msg)" )), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.hey("hey" ); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用hey(msg)" )), ], ), ), ), ); }
事件处理 1、在flutter_plugin_platform_interface.dart
类中增加方法
1 2 3 Future<String? > event(){ throw UnimplementedError('event() has not been implemented.' ); }
2、在flutter_plugin_method_channel.dart
类中实现上面的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 late StreamSubscription<dynamic > _eventSubscription;MethodChannelFlutterPlugin() { _initEvent(); } void _initEvent() { _eventSubscription = _eventChannel() .receiveBroadcastStream() .listen((event) { final Map <dynamic ,dynamic > map = event; switch (map["event" ]){ case "demoEvent" :{ String message = map["message" ]; if (kDebugMode) { print ("demo event:$message " ); } } } }, onDone: () {}, onError: (err) { final PlatformException e = err; throw e; }); } EventChannel _eventChannel() { return const EventChannel("flutter_plugin_demo_event" ); } @override Future<String? > event() async { final msg = await methodChannel.invokeMethod<Map <dynamic , dynamic >>('event' ); return msg?["message" ]; }
3、在flutter_plugin.dart
中调用
1 2 3 Future<String? > event() { return FlutterPluginPlatform.instance.event(); }
4、Android
端实现
FlutterPlugin.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 private var eventSink: (EventChannel.EventSink)? = null private val streamHandler = object : EventChannel.StreamHandler { override fun onListen (arguments: Any ?, events: EventChannel .EventSink ?) { eventSink = events } override fun onCancel (arguments: Any ?) { eventSink = null } } override fun onAttachedToEngine (@NonNull flutterPluginBinding: FlutterPlugin .FlutterPluginBinding ) { channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_plugin_demo" ) channel.setMethodCallHandler(this ) val eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "flutter_plugin_demo_event" ) eventChannel.setStreamHandler(streamHandler) } override fun onMethodCall (@NonNull call: MethodCall , @NonNull result: Result ) { when (call.method) { "getPlatformVersion" -> { result.success("Android ${android.os.Build.VERSION.RELEASE} " ) } "hello" -> { result.success("Android invoke==>hello()" ) } "hi" -> { val param = call.arguments as Map<String, String> result.success("Android invoke==>hi(${param["message" ]} )" ) } "hey" -> { val param = call.arguments as Map<String, String> val response = mutableMapOf<String, String>() response["message" ] = "Android invoke==>hey(${param["message" ]} )" result.success(response) } "event" -> { if (eventSink != null ) { val response = mutableMapOf<String, String>() response["event" ] = "demoEvent" response["message" ] = "Android invoke==>event" eventSink?.success(response) } val response = mutableMapOf<String, String>() response["message" ] = "Android invoke==>event" result.success(response) } else -> { result.notImplemented() } } }
5、在Example
中测试
main.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 @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' ), Text('msg: ${_msg ?? "" } \n' ), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.hello(); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用hello" )), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.hi("hi" ); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用hi(msg)" )), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.hey("hey" ); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用hey(msg)" )), ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.event(); if (kDebugMode) { print ('msg from android:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用event()" )), ], ), ), ), ); }
Web端 Alert 1、在flutter_plugin_platform_interface.dart
类中增加方法
1 2 3 Future<String? > alert(String message){ throw UnimplementedError('alert() has not been implemented.' ); }
2、在项目根目录下新增assets文件夹,然后增加plugin.css,plugin.js文件,在plugin.js文件里加入以下代码
1 2 3 function showAlert (msg ) { alert (msg); }
3、在pubspec.yaml
中增加以下配置
4、在flutter_plugin_web.dart
类中实现上面的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 FlutterPluginWeb(){ injectCssAndJSLibraries(); } @override Future<String? > alert(String message) { _showAlert(msg: message); return Future(() => message); } Future<void > injectCssAndJSLibraries() async { final List <Future<void >> loading = <Future<void >>[]; final List <html.HtmlElement> tags = <html.HtmlElement>[]; final html.LinkElement css = html.LinkElement() ..id = 'plugin-css' ..attributes = {"rel" : "stylesheet" } ..href = 'assets/packages/flutter_plugin/assets/plugin.css' ; tags.add(css); final html.ScriptElement script = html.ScriptElement() ..async = true ..src = "assets/packages/flutter_plugin/assets/plugin.js" ; loading.add(script.onLoad.first); tags.add(script); html.querySelector ('head' )!.children.addAll(tags); await Future.wait(loading); } _showAlert({String msg = "" }) { _insertAlertJs(msg); } _insertAlertJs(String msg) { String m = msg.replaceAll("'" , "\\'" ).replaceAll("\n" , "<br />" ); html.Element? ele = html.querySelector ("#alert-js" ); String content = """ showAlert('$m '); """ ; if (html.querySelector ("#alert-js" ) != null ) { ele!.remove(); } final html.ScriptElement scriptText = html.ScriptElement() ..id = "alert-js" ..innerHtml = content; html.querySelector ('head' )!.children.add(scriptText); }
5、在flutter_plugin.dart
中调用
1 2 3 Future<String? > alert(String message) { return FlutterPluginPlatform.instance.alert(message); }
6、在Example
中测试
main.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Plugin example app' ), ), body: Center( child: Column( children: [ ElevatedButton( onPressed: () async { var msg = await _flutterPlugin.alert("hello,web!" ); if (kDebugMode) { print ('msg from web:$msg ' ); setState(() { _msg = msg; }); } }, child: const Text("调用alert()" )), ], ), ), ), ); }
Copy 1、在flutter_plugin_platform_interface.dart
类中增加方法
1 2 3 Future<bool? > copy(String message){ throw UnimplementedError('copy() has not been implemented.' ); }
2、在plugin.js
文件里加入以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function copy (msg ) { const input = document .getElementById ('input_cp' ); input.focus (); if (input.setSelectionRange ) { input.setSelectionRange (0 , input.value .length ); } else { input.select (); } try { const result = document .execCommand ('copy' ); } catch (e) { console .err ("复制失败,请重试~" ); } input.blur (); document .activeElement .blur (); }
3、在plugin.css
文件中加入以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 .main { position : relative; } .input_wrap { position : absolute; top : 0 ; left : 0 ; width : 1px ; opacity : 0 ; overflow : hidden; user-select: none; } .input_wrap input { width : 1px ; resize : none; border : none; outline : none; user-select: none; color : transparent; background : transparent; }
4、在flutter_plugin_web.dart
类中实现上面的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 @override Future<bool? > copy(String message) { _copy(msg: message); return Future(() => true ); } _copy({String msg = "" }) { _insertCopyHtml(msg); _insertCopyJs(msg); } _insertCopyHtml(String msg) { String m = msg.replaceAll("'" , "\\'" ).replaceAll("\n" , "<br />" ); html.Element? ele = html.querySelector ("#copy-html" ); String content = """ <div class="input_wrap"> <input id="input_cp" type="text" readonly="true" value='$m '> </div> """ ; if (html.querySelector ("#copy-html" ) != null ) { ele!.remove(); } final html.BodyElement scriptText = html.BodyElement() ..id = "copy-html" ..innerHtml = content; html.querySelector ('body' )!.children.add(scriptText); } _insertCopyJs(String msg) { String m = msg.replaceAll("'" , "\\'" ).replaceAll("\n" , "<br />" ); html.Element? ele = html.querySelector ("#copy-js" ); String content = """ copy('$m '); """ ; if (html.querySelector ("#copy-js" ) != null ) { ele!.remove(); } final html.ScriptElement scriptText = html.ScriptElement() ..id = "copy-js" ..innerHtml = content; html.querySelector ('head' )!.children.add(scriptText); }
5、在flutter_plugin.dart
中调用
1 2 3 Future<bool? > copy(String message) { return FlutterPluginDemoPlatform.instance.copy(message); }
6、在Example
中测试
main.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Plugin example app' ), ), body: Center( child: Column( children: [ ElevatedButton( onPressed: () async { var result = await _flutterPlugin.copy("hello,web!!!" ); if (kDebugMode) { print ('copy result:$result ' ); setState(() { _msg = "copy result:$result " ; }); } }, child: const Text("调用copy()" )) ], ), ), ), ); }