Flutter与Native通信,四种方式,MethodChannel、EventChannel、BasicMessageChannel
MethodChannel通信,是基于FlutterEngine来实现的,FlutterEngine作为中间连接桥路。 MethodChannel.
注意:在启动Flutter的Activity(FlutterActivity)中,通信测试好像没什么效果
消息和响应以异步的形式进行传递,以确保用户界面能够保持响应。
标准平台通道使用标准消息编解码器,它支持简单的类似 JSON 值的高效二进制序列化,例如布尔值、数字、字符串、字节缓冲区及这些类型的列表和映射(详情请参阅 StandardMessageCodec
)。当你发送和接收值时,它会自动对这些值进行序列化和反序列化。
下表展示了如何在平台端接收 Dart 值,反之亦然:
Dart | Java | Kotlin | OC | Swift |
---|---|---|---|---|
null | null | null | nil (NSNull when nested) | nil |
bool | java.lang.Boolean | Boolean | NSNumber numberWithBool: | NSNumber(value: Bool) |
int | java.lang.Integer | Int | NSNumber numberWithInt: | NSNumber(value: Int32) |
int, if 32 bits not enough | java.lang.Long | Long | NSNumber numberWithLong: | NSNumber(value: Int) |
double | java.lang.Double | Double | NSNumber numberWithDouble: | NSNumber(value: Double) |
String | java.lang.String | String | NSString | String |
Uint8List | byte[] | ByteArray | FlutterStandardTypedData typedDataWithBytes: | FlutterStandardTypedData(bytes: Data) |
Int32List | int[] | IntArray | FlutterStandardTypedData typedDataWithInt32: | FlutterStandardTypedData(int32: Data) |
Int64List | long[] | LongArray | FlutterStandardTypedData typedDataWithInt64: | FlutterStandardTypedData(int64: Data) |
Float64List | double[] | DoubleArray | FlutterStandardTypedData typedDataWithFloat64: | FlutterStandardTypedData(float64: Data) |
List | java.util.ArrayList | List | NSArray | Array |
Map | java.util.HashMap | HashMap | NSDictionary | Dictionary |
private void setListener() {
FlutterEngine flutterEngine = FlutterEngineCache.getInstance().get("my_engine_id");
GeneratedPluginRegistrant.registerWith(flutterEngine); //Flutter2.0之后,可以去掉
methodChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL);
methodChannel.setMethodCallHandler(
(call, 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();
}
}
);
}
private int getBatteryLevel() {
int batteryLevel;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(Context.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页面
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State {
static const platform = const MethodChannel('samples.flutter.dev/battery');
// Get battery level.
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;
});
}
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
child: Text('Get Battery Level'),
onPressed: _getBatteryLevel,
),
Text(_batteryLevel),
],
),
),
);
}
}
代码一致
代码一致
内部核心还是MethodChannel,只不过封装了,EventChannel,只能是Native->channel
package com.uih.flutternative;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.plugin.common.EventChannel;
public class EventActivity extends AppCompatActivity {
private static final String CHANNEL_NAME = "com.flutter.guide.EventChannel";
private TextView textView;
private EventChannel eventChannel;
private EventChannel.EventSink eventSink;
private FlutterView flutterView;
private FlutterEngine flutterEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
textView = findViewById(R.id.textView);
flutterView = findViewById(R.id.flutterView);
initFlutterView();
setListener();
textView.setOnClickListener(v -> {
eventSink.success("hello world"); //一定要在主线程
});
}
public void initFlutterView() {
flutterEngine = new FlutterEngine(this);
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
);
flutterView.attachToFlutterEngine(flutterEngine);
flutterEngine.getNavigationChannel().setInitialRoute("/");//设置需要启动的页面
}
private void setListener() {
eventChannel = new EventChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_NAME);
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
Toast.makeText(EventActivity.this,"channel",Toast.LENGTH_LONG).show();
eventSink = events;
}
@Override
public void onCancel(Object arguments) {
eventSink = null;
}
});
}
@Override
protected void onResume() {
super.onResume();
flutterEngine.getLifecycleChannel().appIsResumed();
}
@Override
protected void onPause() {
super.onPause();
flutterEngine.getLifecycleChannel().appIsInactive();
}
@Override
protected void onStop() {
super.onStop();
flutterEngine.getLifecycleChannel().appIsPaused();
}
}
Flutter:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class EventChannelDemo extends StatefulWidget {
@override
_EventChannelDemoState createState() => _EventChannelDemoState();
}
class _EventChannelDemoState extends State {
var _eventChannel = EventChannel('com.flutter.guide.EventChannel');
var _data;
@override
void initState() {
super.initState();
_eventChannel
.receiveBroadcastStream()
.listen(_onData, onError: _onError, onDone: _onDone);
}
_onData(event) {
setState(() {
_data = event;
});
}
_onError(event) {
setState(() {
_data = event;
});
}
_onDone() {}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text('$_data'),
),
);
}
}
1.发送消息
BasicMessageChannel(String name, MessageCodec codec, {BinaryMessenger binaryMessenger})
注意:相对与其他Channel类型的创建,MessageChannel的创建除了channel名以外,还需要指定编码方式:
发送的消息会以二进制的形式进行处理,所以要针对不同类型的数进行二进制编码
优点:类似于Android中Binder通信,适合相对大的数据传输,而且还能回复
编码类型 | 消息格式 |
---|---|
BinaryCodec | 发送二进制消息时 |
JSONMessageCodec | 发送Json格式消息时 |
StandardMessageCodec | 发送基本型数据时 |
StringCodec | 发送String类型消息时 |
package com.uih.flutternative;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.StringCodec;
public class BasicActivity extends FlutterActivity {
private TextView textView;
private FlutterView flutterView;
private FlutterEngine flutterEngine;
private BasicMessageChannel basicMessageChannel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_basic);
textView = findViewById(R.id.textView);
flutterView = findViewById(R.id.flutterView);
initFlutterView();
setListener();
}
public void initFlutterView() {
flutterEngine = new FlutterEngine(this);
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
);
flutterView.attachToFlutterEngine(flutterEngine);
flutterEngine.getNavigationChannel().setInitialRoute("/");//设置需要启动的页面
}
private void setListener() {
basicMessageChannel = new BasicMessageChannel(
flutterEngine.getDartExecutor().getBinaryMessenger(),
"com.example.messagechannel/interop",
StringCodec.INSTANCE);
//监听接收消息
basicMessageChannel.setMessageHandler((message, reply) -> {
Toast.makeText(BasicActivity.this, "Received message =" + message, Toast.LENGTH_LONG).show();
reply.reply("Reply from Android"); //回复值
});
textView.setOnClickListener(v -> {
basicMessageChannel.send("Hello World from Android", reply -> {
Toast.makeText(BasicActivity.this, "" + reply, Toast.LENGTH_LONG).show();
});//发送, replay为回复值
});
}
@Override
protected void onResume() {
super.onResume();
flutterEngine.getLifecycleChannel().appIsResumed();
}
@Override
protected void onPause() {
super.onPause();
flutterEngine.getLifecycleChannel().appIsInactive();
}
@Override
protected void onStop() {
super.onStop();
flutterEngine.getLifecycleChannel().appIsPaused();
}
}
Flutter
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class BasicMessagerChannelDemo extends StatefulWidget {
BasicMessagerChannelDemo({Key key}) : super(key: key);
@override
_BasicMessagerChannelDemoState createState() {
return _BasicMessagerChannelDemoState();
}
}
class _BasicMessagerChannelDemoState extends State {
static const _channel = BasicMessageChannel('com.example.messagechannel/interop', StringCodec());
String _platformMessage;
void _sendMessage() async {
final String reply = await _channel.send('Hello World form Dart');
print(reply);//回复值
}
@override
void initState() {
super.initState();
// Receive messages from platform
_channel.setMessageHandler((String message) async { //监听
print('Received message = $message');
setState(() => _platformMessage = message);
return 'Reply from Dart';
});
_sendMessage();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text('$_platformMessage'),
),
);
}
}