MethodChannel-Native 端

为简单起见,本例的Android端代码都直接写在MainActivity中。Android平台下获取电量是通过调用BatteryManager来获取的,所以我们先在MainActivity中增加一个获取电量的函数:

private int getBatteryLevel() {
int batteryLevel = -1;
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}

return batteryLevel;
}

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

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

@Override
public void onCreate(Bundle savedInstanceState) {

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

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

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

接下来我们来填充onMethodCall。

@Override
public 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 {
static const platform = const MethodChannel(‘samples.flutter.io/battery’);

// Get battery level.
}

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

String _batteryLevel = ‘Unknown battery level.’;

Future _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod(‘getBatteryLevel’);
batteryLevel = ‘Battery level at KaTeX parse error: Expected 'EOF', got '}' at position 14: result % .'; }̲ on PlatformExc…{e.message}’.";
}

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

final int result = await platform.invokeMethod('getBatteryLevel');这行代码就是通过通道来调用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 platformCallHandler(MethodCall call) async {
switch (call.method) {
case “getName”:
return “Hello from Flutter”;
break;
}
}

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

channel.invokeMethod(“getName”, null, new MethodChannel.Result() {
@Override
public void success(Object o) {
// 这里就会输出 “Hello from Flutter”
Log.i(“debug”, o.toString());
}
@Override
public void error(String s, String s1, Object o) {
}
@Override
public 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));
ingStateChangeReceiver = createChargingStateChangeReceiver(events);
registerReceiver(
chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐