Flutter与原生交互

Overview

Flutter-Native 消息通道一共有以下三种,在日常开发的过程中我们可能使用的MethodChannel相对比较多一些。

而这三种消息通道都是在Flutterflutter/services.dart库中提供,具体使用哪种方式,需要根据具体的业务来决定。

  • MethodChannel:用于单向调用,Flutter端可以调用原生平台的方法,原生端可以返回结果给Flutter端。

  • EventChannel:用于双向通信,Flutter端可以监听原生平台发出的事件,原生端也可以发送事件给Flutter端。

  • BasicMessageChannel:用于传递任意类型的消息,可以实现双向通信。Flutter端和原生端可以互相发送和接收不同类型的消息。

MethodChannel

使用MethodChannel可以实现Flutter与原生平台的单向通信,Flutter端可以调用原生平台的方法,并接收返回的结果。

在实际开发中,我们获取设备的信息、或者唤起原生的相机、相册等功能都会使用MethodChannel实现。

Flutter端实现

需要在Flutter端创建一个MethodChannel,具体示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import 'package:flutter/services.dart';

class YourMethodChannel {
const platform = const MethodChannel('com.example.flutter_native_communication');

Future<void> callNativeMethod() async {
try {
final String result = await platform.invokeMethod('getPlatformVersion');
print('Response from native code: $result');
} on PlatformException catch (e) {
print('Error: ${e.message}');
}
}
}

安卓端实现

在Android平台上实现相应的方法。具体我们可以创建一个插件类来处理Flutter调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.example.flutter_channel_plugin;

import androidx.annotation.NonNull;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

/// MethodChannel:用于单向调用,Flutter端可以调用原生平台的方法,原生端可以返回结果给Flutter端。
public class FlutterChannelPlugin implements FlutterPlugin, MethodCallHandler {
private MethodChannel channel;

@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_channel_plugin");
channel.setMethodCallHandler(this);
}

@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (call.method.equals("getPlatformVersion")) {
result.success("Android " + android.os.Build.VERSION.RELEASE);
} else {
result.notImplemented();
}
}

@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
}

iOS实现

在iOS端我们同样需要创建个插件类来处理Flutter的调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#import <Flutter/Flutter.h>

@interface FlutterChannelPlugin () <FlutterPlugin>

@property (nonatomic, strong) FlutterMethodChannel *channel;

@end

@implementation FlutterChannelPlugin

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
// 创建插件实例并注册
FlutterChannelPlugin* instance = [[FlutterChannelPlugin alloc] init];
[instance setupMethodChannel:registrar];
}

- (void)setupMethodChannel:(NSObject<FlutterPluginRegistrar> *)registrar {
// 创建FlutterMethodChannel实例
self.channel = [FlutterMethodChannel
methodChannelWithName:@"com.example.flutter_native_communication"
binaryMessenger:[registrar messenger]];

// 设置回调函数
__weak typeof(self) weakSelf = self;
[self.channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[weakSelf handleMethodCall:call result:result];
}];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([call.method isEqualToString:@"getPlatformVersion"]) {
NSString* platform = [NSString stringWithFormat:@"iOS %@", [[UIDevice currentDevice] systemVersion]];
result(platform);
} else {
result(FlutterMethodNotImplemented);
}
}

@end

EventChannel

EventChannel基本用于Flutter与原生平台之间进行双向通信,允许原生平台向 Flutter发送事件。

Flutter端实现

在Flutter端,我们需要使用Dart语言中创建一个EventChannel的实例,并设置事件监听器,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import 'package:flutter/services.dart';

class YourEventChannel {
// 创建 EventChannel 实例
EventChannel eventChannel = EventChannel('com.example.flutter_native_communication/events');

// 监听来自原生平台的事件
StreamSubscription subscription;
subscription = eventChannel.receiveBroadcastStream().listen((event) {
// 处理来自原生平台的事件
print('Received event: $event');
});

// 在不需要时取消监听
subscription.cancel();
}

安卓端实现

在安卓端,我们同样需要创建一个EventChannel实例,并通过该实例发送事件到 Flutter,具体代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.example.flutter_channel_plugin;

import android.content.Context;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;

public class FlutterEventChannelPlugin implements StreamHandler {
private static final String EVENT_CHANNEL = "com.example.flutter_native_communication/events";
private EventSink eventSink;

public static void register(Context context, BinaryMessenger messenger) {
FlutterEventChannelPlugin plugin = new FlutterEventChannelPlugin();
EventChannel eventChannel = new EventChannel(messenger, EVENT_CHANNEL);
eventChannel.setStreamHandler(plugin);
}

@Override
public void onListen(Object arguments, EventSink eventSink) {
this.eventSink = eventSink;

// 将事件发送到Flutter端
sendMessageToFlutter();
}

@Override
public void onCancel(Object arguments) {
// 取消监听
eventSink = null;
}

private void sendMessageToFlutter() {
// 模拟发送事件到Flutter端
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

if (eventSink != null) {
eventSink.success("Event: " + i);
}
}
}
}).start();
}
}

iOS端实现

在iOS端,我们同样也需要创建一个EventChannel实例,并通过该实例发送事件到 Flutter,具体代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@interface FlutterEventChannelPlugin()<FlutterStreamHandler>

@property (nonatomic, strong) FlutterEventChannel *eventChannel;
@property (nonatomic, copy) FlutterEventSink eventSink;

@end

@implementation FlutterEventChannelPlugin

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterEventChannelPlugin* instance = [[FlutterEventChannelPlugin alloc] init];
[instance setupEventChannel:registrar];
}

- (void)setupEventChannel:(NSObject<FlutterPluginRegistrar> *)registrar {
// 创建 FlutterEventChannel 实例
self.eventChannel = [FlutterEventChannel
eventChannelWithName:@"com.example.flutter_native_communication/events"
binaryMessenger:[registrar messenger]];
[self.eventChannel setStreamHandler:self];
}

// 在某个地方调用这个方法向 Flutter 发送事件
- (void)sendEventToFlutter:(NSString*)event {
if (self.eventSink) {
self.eventSink(event);
}
}

- (void)stopListening {
// 在这里添加停止监听事件的逻辑
}

- (void)sendEvent:(id)eventData {
if (self.eventSink) {
self.eventSink(eventData);
}
}

- (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(FlutterEventSink)events {
self.eventSink = events;
return nil;
}

- (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments {
self.eventSink = nil;
// 在这里添加取消监听事件的逻辑
return nil;
}

@end

BasicMessageChannel

BasicMessageChannel可以进行原生和Flutter双向通信。

Flutter端实现

在Flutter我们需要使用Dart语言创建个BasicMessageChannel实例,并设置消息监听器,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import 'package:flutter/services.dart';

class YourBasicMessageChannel {
static const String _channelName = 'your_basic_message_channel_name';
final MethodChannel _methodChannel = MethodChannel(_channelName);

Future<dynamic> sendMessage(dynamic message) async {
final dynamic response = await _methodChannel.invokeMethod('sendMessage', message);
return response;
}

void setMessageHandler(Future<dynamic> Function(dynamic) handler) {
_methodChannel.setMethodCallHandler((MethodCall call) {
if (call.method == 'receiveMessage') {
return handler(call.arguments);
}
return handler(null);
});
}
}

Android端实现

在Android端,我们同样需要创建一个BasicMessageChannel实例,并通过该实例发送消息到 Flutter,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.example.flutter_channel_plugin;

import android.content.Context;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.StringCodec;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MessageCodec;

public class FlutterBasicChannelPlugin {
private static final String CHANNEL_NAME = "com.example.flutter_native_communication/basic_message";

public static void register(Context context, BinaryMessenger messenger) {
BasicMessageChannel<String> messageChannel = new BasicMessageChannel<>(messenger, CHANNEL_NAME, StringCodec.INSTANCE);
messageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler<String>() {
@Override
public void onMessage(String message, BasicMessageChannel.Reply<String> reply) {
// 处理来自Flutter端的消息
String replyMessage = "Received message: " + message;
reply.reply(replyMessage);
}
});
}
}

iOS端实现

在Android端,我们也需要创建一个BasicMessageChannel实例,并通过该实例发送消息到 Flutter,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#import <Flutter/Flutter.h>
@interface NativeCommunicationPlugin () <FlutterMessageListener>

@property (nonatomic, strong) FlutterBasicMessageChannel *messageChannel;

@end

@implementation NativeCommunicationPlugin

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
// 创建插件实例并注册
NativeCommunicationPlugin* instance = [[NativeCommunicationPlugin alloc] init];
[instance setupMessageChannel:registrar];
}

- (void)setupMessageChannel:(NSObject<FlutterPluginRegistrar> *)registrar {
// 创建 FlutterBasicMessageChannel 实例
self.messageChannel = [FlutterBasicMessageChannel
messageChannelWithName:@"com.example.flutter_native_communication/basic_message"
binaryMessenger:[registrar messenger]];

// 设置消息处理器
__weak typeof(self) weakSelf = self;
[self.messageChannel setMessageHandler:^(id message, FlutterReply reply) {
// 处理来自 Flutter 的消息
NSLog(@"Received message: %@", message);

// 回复消息给 Flutter
reply(@"Reply from iOS");
}];
}

// 在某个地方调用这个方法向 Flutter 发送消息
- (void)sendMessageToFlutter:(NSString *)message {
[self.messageChannel sendMessage:message reply:^(id reply) {
// 处理来自 Flutter 的回复消息
NSLog(@"Received reply: %@", reply);
}];
}

@end

参考资料