前言

Flutter 作为混合开发,跟native端做一些交互在所难免,比如说调用原生系统传感器、原生端的网络框架进行数据请求就会用到 Flutter 调用android 及android 原生调用 Flutter的方法,这里就涉及到Platform Channels(平台通道)

Platform Channels (平台通道)

Flutter 通过Channel 与客户端之间传递消息,如图:

Flutter 混合开发(Android)Flutter跟Native相互通信_第1张图片

image.png

图中就是通过MethodChannel的方式实现Flutter 与客户端之间的消息传递。MethodChannel是Platform Channels中的一种,Flutter有三种通信类型:

BasicMessageChannel:用于传递字符串和半结构化的信息MethodChannel:用于传递方法调用(method invocation)通常用来调用native中某个方法EventChannel: 用于数据流(event streams)的通信。有监听功能,比如电量变化之后直接推送数据给flutter端。

为了保证UI的响应,通过Platform Channels传递的消息都是异步的。

Platform Channels 使用

1.MethodChannel的使用

原生客户端写法(以Android 为例)

首先定义一个获取手机电量方法

private int getBatteryLevel() {        return 90;    }

这函数是要给Flutter 调用的方法,此时就需要通过 MethodChannel 来建立这个通道了。

首先新增一个初始化 MethodChannel 的方法

private String METHOD_CHANNEL = "common.flutter/battery";private String GET_BATTERY_LEVEL = "getBatteryLevel";private MethodChannel methodChannel;@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        GeneratedPluginRegistrant.registerWith(this);        initMethodChannel();        getFlutterView().postDelayed(() ->            methodChannel.invokeMethod("get_message", null, new MethodChannel.Result() {                @Override                public void success(@Nullable Object o) {                    Log.d(TAG, "get_message:" + o.toString());                }                @Override                public void error(String s, @Nullable String s1, @Nullable Object o) {                }                @Override                public void notImplemented() {                }            }), 5000);    }    private void initMethodChannel() {        methodChannel = new MethodChannel(getFlutterView(), METHOD_CHANNEL);        methodChannel.setMethodCallHandler(                (methodCall, result) -> {                    if (methodCall.method.equals(GET_BATTERY_LEVEL)) {                        int batteryLevel = getBatteryLevel();                        if (batteryLevel != -1) {                            result.success(batteryLevel);                        } else {                            result.error("UNAVAILABLE", "Battery level not available.", null);                        }                    } else {                        result.notImplemented();                    }                });    }    private int getBatteryLevel() {        return 90;    }

METHOD_CHANNEL 用于和flutter交互的标识,由于一般情况下会有多个channel,在app里面需要保持唯一性

MethodChannel 都是保存在以通道名为Key的Map中。所以要是设了两个名字一样的channel,只有后设置的那个会生效。

onMethodCall 有两个参数,onMethodCall 里包含要调用的方法名称和参数。Result是给Flutter的返回值。方法名是客户端与Flutter统一设定。通过if/switch语句判断 MethodCall.method 来区分不同的方法,在我们的例子里面我们只会处理名为“getBatteryLevel”的调用。在调用本地方法获取到电量以后通过 result.success(batteryLevel) 调用把电量值返回给Flutter。

MethodChannel-Flutter 端

直接先看一下Flutter端的代码

class _MyHomePageState extends State {  int _counter = 0;  static const platform = const MethodChannel('common.flutter/battery');  void _incrementCounter() {    setState(() {      _counter++;      _getBatteryLevel();    });  }  @override  Widget build(BuildContext context) {    platform.setMethodCallHandler(platformCallHandler);    return Scaffold(      appBar: AppBar(        title: Text(widget.title),      ),      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            Text(              'You have pushed the button this many times:',            ),            Text(              '$_counter',              style: Theme.of(context).textTheme.display1,            ),            Text('$_batteryLevel'),          ],        ),      ),      floatingActionButton: FloatingActionButton(        onPressed: _incrementCounter,        tooltip: 'Increment',        child: Icon(Icons.add),      ),     );  }  String _batteryLevel = 'Unknown battery level.';  Future _getBatteryLevel() async {    String batteryLevel;    try {      final int result = await platform.invokeMethod('getBatteryLevel');      batteryLevel = 'Battery level at $result % .';    } on PlatformException catch (e) {      batteryLevel = "Failed to get battery level: '${e.message}'.";    }    setState(() {      _batteryLevel = batteryLevel;    });  } //客户端调用  Future platformCallHandler(MethodCall call) async {    switch (call.method) {      case "get_message":        return "Hello from Flutter";        break;    }  }}

上面代码解析:
首先,定义一个常量result.success(platform),和Android客户端定义的channel一致;
接下来定义一个 result.success(_getBatteryLevel())方法,用来调用Android 端的方法,result.success(final int result = await platform.invokeMethod('getBatteryLevel');) 这行代码就是通过通道来调用Native(Android)方法了。因为MethodChannel是异步调用的,所以这里必须要使用await关键字。

在上面Android代码中我们把获取到的电量通过result.success(batteryLevel);返回给Flutter。这里await表达式执行完成以后电量就直接赋值给result变量了。然后通过result.success(setState); 去改变Text显示值。到这里为止,是通过Flutter端调用原生客户端方法。

MethodChannel 其实是一个可以双向调用的方法,在上面的代码中,其实我们也体现了,通过原生客户端调用Flutter的方法。

在原生端通过 methodChannel.invokeMethod 的方法调用

methodChannel.invokeMethod("get_message", null, new MethodChannel.Result() {                @Override                public void success(@Nullable Object o) {                    Log.d(TAG, "get_message:" + o.toString());                }                @Override                public void error(String s, @Nullable String s1, @Nullable Object o) {                }                @Override                public void notImplemented() {                }            });

在Flutter端就需要给MethodChannel设置一个MethodCallHandler

static const platform = const MethodChannel('common.flutter/battery');platform.setMethodCallHandler(platformCallHandler);Future platformCallHandler(MethodCall call) async {    switch (call.method) {      case "get_message":        return "Hello from Flutter";        break;    }  }

以上就是MethodChannel的相关用法了。

EventChannel

将数据推送给Flutter端,类似我们常用的推送功能,有需要就推送给Flutter端,是否需要去处理这个推送由Flutter那边决定。相对于MethodChannel是主动获取,EventChannel则是被动推送。

EventChannel 原生客户端写法

private String EVENT_CHANNEL = "common.flutter/message";private int count = 0;private Timer timer;private void initEventChannel() {        new EventChannel(getFlutterView(), EVENT_CHANNEL).setStreamHandler(new EventChannel.StreamHandler() {            @Override            public void onListen(Object arguments, EventChannel.EventSink events) {                timer.schedule(new TimerTask() {                    @Override                    public void run() {                        if (count < 10) {                            count++;                            events.success("当前时间:" + System.currentTimeMillis());                        } else {                            timer.cancel();                        }                    }                }, 1000, 1000);            }            @Override            public void onCancel(Object o) {            }        });    }

在上面的代码中,我们做了一个定时器,每秒向Flutter推送一个消息,告诉Flutter我们当前时间。为了防止一直倒计时,我这边做了个计数,超过10次就停止发送。

EventChannel Flutter端

String message = "not message";static const eventChannel = const EventChannel('common.flutter/message');@override  void initState() {    super.initState();    eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);  }void _onEvent(Object event) {    setState(() {      message =      "message: $event";    });  }  void _onError(Object error) {    setState(() {      message = 'message: unknown.';    });  }

上面的代码就是Flutter端接收原生客户端数据,通过_onEvent 来接收数据,将数据显示Text。这个实现相对简单,如果要达到业务分类,需要将数据封装成json,通过json数据包装一些对应业务标识和数据来做区分。

BasicMessageChannel

BasicMessageChannel (主要是传递字符串和一些半结构体的数据)

BasicMessageChannel Android端

private void initBasicMessageChannel() {        BasicMessageChannel basicMessageChannel = new BasicMessageChannel<>(getFlutterView(), BASIC_CHANNEL, StandardMessageCodec.INSTANCE);        //主动发送消息到flutter 并接收flutter消息回复            basicMessageChannel.send("send basic message", (object)-> {                Log.e(TAG, "receive reply msg from flutter:" + object.toString());            });        //接收flutter消息 并发送回复        basicMessageChannel.setMessageHandler((object, reply)-> {            Log.e(TAG, "receive msg from flutter:" + object.toString());            reply.reply("reply:got your message");        });    }   

BasicMessageChannel Flutter端

  static const basicChannel = const BasicMessageChannel('common.flutter/basic', StandardMessageCodec());//发送消息到原生客户端 并且接收到原生客户端的回复  Future sendMessage() async {    String reply = await basicChannel.send('this is flutter');    print("receive reply msg from native:$reply");    return reply;  }  //接收原生消息 并发送回复  void receiveMessage() async {    basicChannel.setMessageHandler((msg) async {      print("receive from Android:$msg");      return "get native message";    });

上面例子中用到的编解码器为StandardMessageCodec ,例子中通信都是String,用StringCodec也可以。

以上就是Flutter提供三种platform和dart端的消息通信方式。
 

更多相关文章

  1. Android 总结:进阶之路(资源与方法)
  2. Android 关闭所有Activity完全退出程序方法
  3. android 图文列表的实现方法
  4. Android客户端嵌入html5页面
  5. 使用universal-image-loader中出现的EOFException解决方法
  6. android 隐藏输入键盘的方法
  7. Delphi XE5 android 获取电池电量
  8. Android 使用decodeFile方法加载手机磁盘中的图片文件
  9. Android设置全屏的两种方法

随机推荐

  1. android获取string.xml的值
  2. Android之Menu基本使用(显示图标icon)
  3. 使用QQ2013时连接Android物理设备Eclipse
  4. Android通过微信实现第三方登录并使用OKH
  5. 【移动开发】Android中Activity剖析
  6. 【Android那些高逼格的写法】Callable与
  7. 【转】Android开发者必须深入学习的10个
  8. android之计时器(Chronometer)的使用以及
  9. Android工程:引用另一个Android工程的方
  10. Android应用内搜索