Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通信

Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通信

背景

前面我们讲了很多 Flutter 相关的知识点,但是我们并没有介绍怎样实现 Flutter 与原生的通信。

比如我在 Flutter UI 上面点击了一个按钮,我希望原生做一些处理,那么原生怎么知道?

比如我在原生有些变化需要告知 Flutter,Flutter 又如何获知?

本篇我们先解决第一个问题。即 Flutter-> 原生的通信。

路由回顾

之前我们一直在讲 Flutter 相关的知识点,而且基本上都是在 main.dart 文件上面折腾,为了避免很多小伙伴觉得我们跨度过大。

因此我们这里补充一下之前第三篇 Flutter 即学即用系列博客——03 在旧有项目引入 Flutter 的知识点。

在 Flutter Module 的 main.dart 文件里面,对于存在多个页面的情况,我们可以写下面的模板代码:

import 'dart:ui'; import 'package:flutter/material.dart'; void main() => runApp(_widgetForRoute(window.defaultRouteName)); Widget _widgetForRoute(String route) { switch (route) { case 'route1': return SomeWidget(...); case 'route2': return SomeOtherWidget(...); default: return Center( child: Text('Unknown route: $route', textDirection: TextDirection.ltr), ); } }

这段代码我们可以重点关注 switch 那一块代码。这里会根据不同的路由,返回不同的页面。

下面我们会用到这种写法。

实际案例

接下来我们通过实际案例来说明如何实现 Flutter 向原生发送消息?

我们的案例是假设我要获取 Android 设备的当前电量,我希望点击按钮之后电量会显示出来。

当然这里的按钮和显示电量的文本都是 Flutter 界面的。

那么步骤是怎样的呢?

1. 搭建 Flutter 界面

我们将界面写成一个单独的 battery_widget.dart 文件:

import 'package:flutter/material.dart'; class BatteryWidget extends StatefulWidget { @override _BatteryWidgetState createState() => _BatteryWidgetState(); } class _BatteryWidgetState extends State<BatteryWidget> { String _batteryLevel = 'Battery level: unknown.'; void _getBatteryLevel() {} @override Widget build(BuildContext context) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text(_batteryLevel), RaisedButton( child: const Text('Refresh'), onPressed: _getBatteryLevel, ), ], ), ); } }

很简单的界面,就是一个文本和一个按钮,排成一列。

然后我们 main.dart 修改如下:

import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:my_flutter/battery_widget.dart'; void main() => runApp(_widgetForRoute(window.defaultRouteName)); Widget _widgetForRoute(String route) { switch (route) { case 'battery': return MaterialApp( home: Scaffold( body: BatteryWidget(), ), ); default: return MaterialApp( home: Scaffold( body: Container(), ), ); } }

这里的关键点是指定 route 名字为 battery 时,返回我们刚刚新建的 battery_widget 界面。

2. 原生调用 Flutter 界面

在 MainActivity.java 里面,我们写出下面代码:

package com.nesger.flutterdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import io.flutter.facade.Flutter; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); View flutterView = Flutter.createView( MainActivity.this, getLifecycle(), "battery" ); FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); addContentView(flutterView, layout); } }

可以看到 battery 指定了要加载的 Flutter 界面。

运行后效果如下:

Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通信

接下来就是关键的在点击按钮的时候如何获取原生设备电量。

根据上面的代码,我们知道点击按钮会执行 _getBatteryLevel 方法。因此我们要在这里做一些修改。

3. Flutter 定义 MethodChannel

我们在 _BatteryWidgetState 里面加入下面变量:

static const MethodChannel methodChannel = MethodChannel('samples.flutter.io/battery');

samples.flutter.io/battery 可以自己指定,一般保证唯一,所以 samples 实际使用可以替换为包名。主要是要跟原生对应即可。

4. Flutter 调用 methodChannel API invokeMethod 调用原生某个方法并获取对应的值。 final int result = await methodChannel.invokeMethod('getBatteryLevel');

比如我们这里要通过原生的 getBatteryLevel 方法获取到对应的电量,并将返回值用 result 保存。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspwgp.html