Flutter Plugin插件开发之利用BasicMessageChannel在Platform和Flutter之间通信

一步步实现一个Flutter plugin插件这篇文章我们介绍了如何实现一个plugin,但是这里通过MethodChannel只实现了Flutter向Platform的通信,并未实现从Platform向Flutter的通信,今天我们就来介绍如何通过BasicMessageChannel实现Platform向Flutter方向的通信。

创建Plugin

关于在命令行中或者Android Studio中如何新建一个Plugin项目,我们在一步步实现一个Flutter plugin插件这片文章中已经有详细介绍,这里不再赘述

Flutter端代码

首先创建一个BasicMessageChannel对象

第一个参数为channel名,需与Platform中的BasicMessageChannel对象传的channel名一致

第二个参数为codec,表示消息编解码器,Flutter中已经默认为我们实现了如下几种,基本够用,也支持自定义,我们这里用StringCodec,支持简单的内容为String的消息通信。codec的类型也必须和Platform中的BasicMessageChannel对象传的codec类型一致

  • BinaryCodec

    BinaryCodec是最为简单的一种Codec,因为其返回值类型和入参的类型相同,均为二进制格式(Android中为ByteBuffer,iOS中为NSData)。实际上,BinaryCodec在编解码过程中什么都没做,只是原封不动将二进制数据消息返回而已。或许你会因此觉得BinaryCodec没有意义,但是在某些情况下它非常有用,比如使用BinaryCodec可以使传递内存数据块时在编解码阶段免于内存拷贝。

  • StringCodec

    StringCodec用于字符串与二进制数据之间的编解码,其编码格式为UTF-8。

  • JSONMessageCodec

    JSONMessageCodec用于基础数据与二进制数据之间的编解码,其支持基础数据类型以及列表、字典。其在iOS端使用了NSJSONSerialization作为序列化的工具,而在Android端则使用了其自定义的JSONUtil与StringCodec作为序列化工具。

  • StandardMessageCodec

    StandardMessageCodec是BasicMessageChannel的默认编解码器,其支持基础数据类型、二进制数据、列表、字典

static const BasicMessageChannel _messageChannel = const BasicMessageChannel('plugin_version', StringCodec());

 然后通过setMessageHandler方法设置一个消息处理器,用于处理从platform传过来的消息

 _messageChannel.setMessageHandler(_handleMessage);

Future<String> _handleMessage(message) async {
  print('收到native的消息${message}');
}

Android端代码

与Flutter端的代码类似,首先创建一个BasicMessageChannel对象

第二个参数为channel名,需与Flutter中的BasicMessageChannel对象传的channel名一致

第三个参数为codec,表示消息编解码器,也必须和Flutter中的BasicMessageChannel对象传的codec类型一致,codec类型在上文中已具体介绍,这里不再赘述

private static BasicMessageChannel messageChannel;

public static void registerWith(PluginRegistry.Registrar registrar) {
    messageChannel = new BasicMessageChannel(registrar.messenger(),"plugin_version", StringCodec.INSTANCE);
}

然后调用send方法向Flutter发送消息

messageChannel.send("message from platform");

iOS端代码

说实话,iOS开发臣妾不懂啊

实现方法跟Android类似,可以参考官方文档

完整实现代码

结合一步步实现一个Flutter plugin插件这篇文章中的Flutter端向Platform端的通信,贴上完整的Flutter和Platform双向通信的完整实现代码

flutter端代码

import 'dart:async';

import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter/material.dart';

class PluginVersion {
  static const MethodChannel _methodChannel = const MethodChannel('plugin_version');
  static const BasicMessageChannel _messageChannel = const BasicMessageChannel('plugin_version', StringCodec());

  PluginVersion() {
    _messageChannel.setMessageHandler(_handleMessage);
  }

  Future<String> _handleMessage(message) async {
    print('收到native的消息${message}');
    Fluttertoast.showToast(
        msg: message.toString(),
        toastLength: Toast.LENGTH_SHORT,
        gravity: ToastGravity.CENTER,
        timeInSecForIos: 1,
        backgroundColor: Colors.black,
        textColor: Colors.white);
  }

  Future<String> get platformVersion async {
    final String version = await _methodChannel.invokeMethod('getPlatformVersion');
    return version;
  }
}

Android端代码

package com.himmy.plugin_version;

import android.os.Build;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.StringCodec;

public class PluginVersionPlugin implements MethodChannel.MethodCallHandler {

    private static BasicMessageChannel messageChannel;

    public static void registerWith(PluginRegistry.Registrar registrar) {
        MethodChannel channel = new MethodChannel(registrar.messenger(), "plugin_version");
        channel.setMethodCallHandler(new PluginVersionPlugin());
        messageChannel = new BasicMessageChannel(registrar.messenger(), "plugin_version", StringCodec.INSTANCE);
    }

    @Override
    public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
        if ("getPlatformVersion".equals(methodCall.method)) {
            result.success("Android " + Build.VERSION.RELEASE);
            messageChannel.send("message from platform");
        } else {
            result.notImplemented();
        }
    }
}

插件使用

在创建的Flutter Plugin项目中默认有一个测试项目example,替换lib/main.dart中的内容为如下内容

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:plugin_version/plugin_version.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  PluginVersion pluginVersion = PluginVersion();

  @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.
    try {
      platformVersion = await pluginVersion.platformVersion;
    } 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: Text('Running on: $_platformVersion\n'),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: initPlatformState,
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

参考

flutter与native通信

 

 

posted @ 2019-10-14 16:17  野猿新一  阅读(54)  评论(0编辑  收藏  举报