写点什么

Flutter 如何和 Native 通信 -Android 视角,首发 10 万字 Android 开发实战文档

用户头像
Android架构
关注
发布于: 1 小时前

batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);}


return batteryLevel;}


这个函数需要能被 Flutter app 调用,此时就需要通过MethodChannel来建立这个通道了。 首先在MainActivityonCreate函数中加入以下代码来新建一个MethodChannel


public class MainActivity extends FlutterActivity {//channel 的名称,由于 app 中可能会有多个 channel,这个名称需要在 app 内是唯一的。private static final String CHANNEL = "samples.flutter.io/battery";


@Overridepublic void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);GeneratedPluginRegistrant.registerWith(this);


// 直接 new MethodChannel,然后设置一个 Callback 来处理 Flutter 端调用 new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodCallHandler() {@Overridepublic void onMethodCall(MethodCall call, Result result) {// 在这个回调里处理从 Flutter 来的调用}});}}


注意,每个MethodChannel需要有唯一的字符串作为标识,用以互相区分,这个名称建议使用package.module...这样的模式来命名。因为所有的MethodChannel都是保存在以通道名为 Key 的 Map 中。所以你要是设了两个名字一样的 channel,只有后设置的那个会生效。


接下来我们来填充onMethodCall


@Overridepublic void onMethodCall(MethodCall call, Result result) {if (call.method.equals("getBatteryLevel")) {int batteryLevel = getBatteryLevel();


if (batteryLevel != -1) {result.success(batteryLevel);} else {result.error("UNAVAILABLE", "Battery level not available.", null);}} else {result.notImplemented();}}


onMethodCall有两个入参,MethodCall里包含要调用的方法名称和参数。Result是给 Flutter 的返回值。方法名是两端协商好的。通过 if 语句判断MethodCall.method来区分不同的方法,在我们的例子里面我们只会处理名为“getBatteryLevel”的调用。在调用本地方法获取到电量以后通过result.success(batteryLevel)调用把电量值返回给 Flutter。 Native 端的代码就完成了。是不是很简单?

MethodChannel-Flutter 端

接下来看 Flutter 端代码怎么写: 首先在 State中创建 Flutter 端的MethodChannel


import 'dart:async';


import 'package:flutter/material.dart';import 'package:flutter/services.dart';...class _MyHomePageState extends State<MyHomePage> {static const platform = const MethodChannel('samples.flutter.io/battery');


// Get battery level.}


channel 的名称要和 Native 端的一致。 然后是通过 MethodChannel 调用的代码


String _batteryLevel = 'Unknown battery level.';


Future<Null> _getBatteryLevel() async {String batteryLevel;try {final int result = await platform.invokeMethod('getBatteryLevel');batteryLevel = 'Battery level at {e.message}'.";}


setState(() {_batteryLevel = batteryLevel;});}


final int result = await platform.invokeMethod('getBatteryLevel');这行代码就是通


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


过通道来调用 Native 方法了。注意这里的await关键字。前面我们说过 MethodChannel 是异步的,所以这里必须要使用await关键字。 在上面 Native 代码中我们把获取到的电量通过result.success(batteryLevel);返回给 Flutter。这里await表达式执行完成以后电量就直接赋值给result变量了。剩下的就是怎么展示的问题了,就不再细说了,具体可以去看代码。


需要注意的是,这里我们只介绍了从 Flutter 调用 Native 方法,其实通过MethodChannel,Native 也能调用 Flutter 的方法,这是一个双向的通道


举个例子,我们想从 Native 端请求 Flutter 端的一个getName方法获取一个字符串。在 Flutter 端你需要给MethodChannel设置一个MethodCallHandler


_channel.setMethodCallHandler(platformCallHandler);


Future<dynamic> platformCallHandler(MethodCall call) async {switch (call.method) {case "getName":return "Hello from Flutter";break;}}


在 Native 端,只需要让对应的的 channel 调用invokeMethod就行了


channel.invokeMethod("getName", null, new MethodChannel.Result() {@Overridepublic void success(Object o) {// 这里就会输出 "Hello from Flutter"Log.i("debug", o.toString());}@Overridepublic void error(String s, String s1, Object o) {}@Overridepublic void notImplemented() {}});


至此,MethodChannel的用法就介绍完了。可以发现,通过MethodChannelNative 和 Flutter 方法互相调用还是蛮直接的。这里只是做了个大概的介绍,具体细节和一些复杂用法还有待大家的探索。


MethodChannel提供了方法调用的通道,那如果 Native 有数据流需要传送给 Flutter 该怎么办呢?这时候就要用到EventChannel了。

EventChannel

EventChannel的使用我们也以官方获取电池电量的 demo 为例,手机的电池状态是不停变化的。我们要把这样的电池状态变化由 Native 及时通过EventChannel来告诉 Flutter。这种情况用之前讲的MethodChannel办法是不行的,这意味着 Flutter 需要用轮询的方式不停调用getBatteryLevel来获取当前电量,显然是不正确的做法。而用EventChannel的方式,则是将当前电池状态"推送"给 Flutter.

EventChannel - Native 端

先看我们熟悉的 Native 端怎么来创建EventChannel, 还是在MainActivity.onCreate中,我们加入如下代码:


new EventChannel(getFlutterView(), "samples.flutter.io/charging").setStreamHandler(new StreamHandler() {// 接收电池广播的 BroadcastReceiver。private BroadcastReceiver chargingStateChangeReceiver;@Override// 这个 onListen 是 Flutter 端开始监听这个 channel 时的回调,第二个参数 EventSink 是用来传数据的载体。public void onListen(Object arguments, EventSink events) {chargingStateChangeReceiver = createChargingStateChangeReceiver(events);registerReceiver(chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));}


@Overridepublic void onCancel(Object arguments) {// 对面不再接收 unregisterReceiver(chargingStateChangeReceiver);chargingStateChangeReceiver = null;}});

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Flutter如何和Native通信-Android视角,首发10万字Android开发实战文档