一、架构概述:平台通道
消息使用平台通道在客户端(UI)和宿主(平台)之间传递,如下图所示:
消息和响应以异步的形式进行传递,以确保用户界面能够保持响应。
简单介绍Platfrom Channel的三个API
MethodChannel : Flutter与原生方法相互调用,用于方法掉用。
EventChannel : 原生发送消息,Flutter接收,用于数据流通信
BasicMessageChannel : Flutter与原生相互发送消息,用于数据传递
三种Channel之间互相独立,各有用途,但它们在设计上却非常相近。每种Channel均有三个重要成员变量:
- name: String类型,代表Channel的名字,也是其唯一标识符。
- messager:BinaryMessenger类型,代表消息信使,是消息的发送与接收的工具。
- codec: MessageCodec类型或MethodCodec类型,代表消息的编解码器。
- 例:
MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec)
注:一个Flutter应用中可能存在多个Channel,每个Channel在创建时必须指定一个独一无二的name,Channel之间使用name来区分彼此。当有消息从Flutter端发送到Platform端时,会根据其传递过来的channel name找到该Channel对应的Handler(消息处理器)。
下面我们通过一个获取电池电量的插件来介绍一下MethodChannel 与 EventChannel ,该插件中我们在Dart中通过getBatteryLevel
调用Android BatteryManager
API
二、MethodChannel 与 EventChannel 官方示例
首先创建一个新的应用:
在终端中运行:
flutter create batterylevel
默认情况下,我们的模板使用 Kotlin 编写 Android 或使用 Swift 编写 iOS 代码。要使用 Java 或 Objective-C,请使用
-i
和/或-a
标志:
在终端中运行:
flutter create -a kotlin batterylevel / flutter create -a java batterylevel
1、MethodChannel 基本流程
MethodChannel 是双向的,此处以flutter调用native为例,native调用flutter是一样的只是角色互调
- [native端] 使用MethodChannel.setMethodCallHandler注册回调
- [flutter端] 使用MethodChannel.invokeMethod发起异步调用,调用原生里的方法,等待返回值
- [native端] 通过Result.success返回值
2、EventChannel基本流程
- [native端] 使用EventChannel.setStreamHandler注册
- [native端] EventChannel初始完成后,在StreamHandler的onListen回调中创建和注册广播
- [flutter端] 通过EventChannel.receiveBroadcastStream注册监听,实时监听返回值。
- [native端] 使用EventSink.success发送消息
- [flutter端] 接受值
Flutter端代码
class _MyHomePageState extends State<MyHomePage> {
//一个应用中所使用的所有通道名称必须是唯一的,并且两端使用的名称要相同
static const MethodChannel methodChannel =
MethodChannel('samples.flutter.io/battery');
static const EventChannel eventChannel =
EventChannel('samples.flutter.io/charging');
String _batteryLevel = 'Battery level: unknown.';
String _chargingStatus = 'Battery status: unknown.';
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
//MethodChannel-2.[flutter端] 使用MethodChannel.invokeMethod发起异步调用,调用原生里的方法,等待返回值
final int result = await methodChannel.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level: $result%.';
} on PlatformException {
batteryLevel = 'Failed to get battery level.';
}
setState(() {
_batteryLevel = batteryLevel;
});
}
@override
void initState() {
super.initState();
//EventChannel-3.[flutter端] 通过EventChannel.receiveBroadcastStream注册监听,实时监听返回值。
eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
}
void _onEvent(Object event) {
setState(() {
_chargingStatus = event;
});
}
void _onError(Object error) {
setState(() {
_chargingStatus = 'error';
});
}
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(_batteryLevel, key: const Key('Battery level label')),
Padding(
padding: const EdgeInsets.all(16.0),
child: RaisedButton(
child: const Text('Refresh'),
onPressed: _getBatteryLevel,
),
),
],
),
Text(_chargingStatus),
],
),
));
}
}
Android端代码
Java:
package com.example.platformchannel;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
//两端使用的通道名称要相同
private static final String BATTERY_CHANNEL = "samples.flutter.io/battery";
private static final String CHARGING_CHANNEL = "samples.flutter.io/charging";
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
//EventChannel-1.[native端] 使用EventChannel.setStreamHandler注册
new EventChannel(flutterEngine.getDartExecutor(), CHARGING_CHANNEL).setStreamHandler(
new StreamHandler() {
private BroadcastReceiver chargingStateChangeReceiver;
@Override
public void onListen(Object arguments, EventSink events) {
//EventChannel-2.[native端] EventChannel初始完成后,在StreamHandler的onListen回调中创建和注册广播
chargingStateChangeReceiver = createChargingStateChangeReceiver(events);//创建
registerReceiver(//注册
chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
@Override
public void onCancel(Object arguments) {
unregisterReceiver(chargingStateChangeReceiver);
chargingStateChangeReceiver = null;
}
}
);
//MethodChannel-1.[native端] 使用MethodChannel.setMethodCallHandler注册回调
new MethodChannel(flutterEngine.getDartExecutor(), BATTERY_CHANNEL).setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
//MethodChannel-3.[native端] 通过Result.success返回值
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
} else {
result.notImplemented();
}
}
}
);
}
private BroadcastReceiver createChargingStateChangeReceiver(final EventSink events) {
return new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if (status == BatteryManager.BATTERY_STATUS_UNKNOWN) {
events.error("UNAVAILABLE", "Charging status unavailable", null);
} else {
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
status == BatteryManager.BATTERY_STATUS_FULL;
//EventChannel-4.[native端] 使用EventSink.success发送消息
events.success(isCharging ? "charging" : "discharging");
}
}
};
}
private int getBatteryLevel() {
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
return (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
}
}
Kotlin:Java代码复制AndroidStudio的kotlin文件里会自动提示转成kotlin 此处省略。
MethodChannel.setMethodCallHandler、EventChannel.setStreamHandler也可以封装到外面
像这样开发Flutter 的 Android 插件有个注意的地方:
自 1.12 版本发布后, Android 平台已可以使用新的 Android 插件 API 。基于
PluginRegistry.Registrar
的 API 不会立刻废弃,但我们鼓励您向基于FlutterPlugin
的 API 进行迁移。此次涉及最大的调整,应该是 Android 插件的改进 Android plugins APIs 的相关变化,该调整需要用户重新调整 Flutter 项目中 Android 模块和插件的代码进行适配。
新旧版本差异请看这里:https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects
我在flutter与native原生通信开发完后出现了这样的错误:
[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: MissingPluginException(No implementation found for method getAll on channel plugins.flutter.io/shared_preferences)
解决办法:https://github.com/flutter/flutter/issues/10912
我解决问题是通过在public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine)方法里加上了GeneratedPluginRegistrant.registerWith(flutterEngine);
-import io.flutter.app.FlutterActivity;
-import io.flutter.plugin.common.MethodCall;
+import androidx.annotation.NonNull;
+import io.flutter.embedding.android.FlutterActivity;
+import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
-import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
-import io.flutter.plugin.common.MethodChannel.Result;
+import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "samples.flutter.dev/battery";
- //以前的注册方法
- @Override
- public void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
- GeneratedPluginRegistrant.registerWith(this);
-
- new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
- new MethodCallHandler() {
- @Override
- public void onMethodCall(MethodCall call, Result result) {
- // Your existing code
- }
- });
- }
+ //现在的注册方法
+ @Override
+ public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
+ GeneratedPluginRegistrant.registerWith(flutterEngine);//我忘了这句
+ new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
+ .setMethodCallHandler(
+ (call, result) -> {
+ // Your existing code
+ }
+ );
+ }
}
觉得文章不错的话,点个赞把,比心~