Channel
实现与原生通信
【1】MethodChannel
通过MethodChannel来传递数据,调用方法
案例
分别调用Android和Ios原生的获取电量的方法
Flutter端
实例一个MethodChannel, 唯一标识name,定义方法名称getBatteryLevel
methodchannel.invokeMethod(name)来调用方法
dart
static const platform = MethodChannel('sample.flutter.dev/battery');
static const method = 'getBatteryLevel';
String _batteryLevel = 'Unknown battery level';
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final result = await platform.invokeMethod<int>(method);
batteryLevel = 'Battery level at $result';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
界面操作
dart
@override
Widget build(BuildContext context) {
return Material(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _getBatteryLevel,
child: const Text('Get Battery Level'),
),
Text(_batteryLevel),
],
),
);
}
Android端
java
private static final String CHANNEL = "sample.flutter.dev/battery";
private MethodChannel methodChannel;
private static final String METHOD = "getBatteryLevel";
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
BinaryMessenger binaryMessenger = flutterEngine.getDartExecutor().getBinaryMessenger();
methodChannel = new MethodChannel(binaryMessenger, CHANNEL);
methodChannel.setMethodCallHandler((call, result) -> {
});
}
java
if (call.method.equals(METHOD)) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not avaiable", null);
}
} else {
result.notImplemented();
}
java
private int getBatteryLevel() {
int batteryLevel = -1;
if (VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent intent = new ContextWrapper(getApplicationContext()).registerReceiver(null, intentFilter);
batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
return batteryLevel;
}
Ios端
实例FlutterMethodChannel
swift
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let method : String = "getBatteryLevel"
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let batteryChannel = FlutterMethodChannel(name: "sample.flutter.dev/battery", binaryMessenger: controller.binaryMessenger)
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
guard call.method == method else {
result(FlutterMethodNotImplemented)
return
}
self.receiveBatteryLevel(result: result)
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
定义获取电量的方法
swift
func receiveBatteryLevel(result: FlutterResult) -> Void {
let device = UIDevice.current
device.isBatteryMonitoringEnabled = true
if device.batteryState == UIDevice.BatteryState.unknown {
result(FlutterError(code: "UNAVAILABLE", message: "Battery level not available.", details: nil))
} else {
result(Int(device.batteryLevel * 100))
}
}
运行测试
【2】EventChannel
区别MethodChannel,它是continuously
采用event streams
案例
在原生端(Android&Ios)会有个计时器,不停的传时间给Flutter端,Flutter端显示出来
Flutter端
实例一个EventChannel,唯一标识name
dart
late EventChannel eventChannel;
@override
void initState() {
eventChannel = const EventChannel('timeHandlerEvent');
super.initState();
}
在Flutter注册监听
dart
Stream<String> get streamTimeFromNative =>
eventChannel.receiveBroadcastStream().map((event) => event.toString());
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder<String>(
stream: streamTimeFromNative,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text(
'${snapshot.data}',
style: Theme.of(context).textTheme.headlineMedium,
);
} else {
return const CircularProgressIndicator();
}
},
),
),
);
}
Ios端
实例一个FlutterEventChannel,加上唯一标识timeHandlerEvent
swift
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let eventChannel = FlutterEventChannel(name: "timeHandlerEvent", binaryMessenger: controller.binaryMessenger)
定义FlutterStreamHandler
swift
class TimeHandler: NSObject, FlutterStreamHandler {
func onCancel(withArguments arguments: Any?) -> FlutterError? {
return nil
}
func onListen(withArguments arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? {
return nil
}
}
每间隔1秒发送一次当前时间
swift
class TimeHandler: NSObject, FlutterStreamHandler {
var timer = Timer()
private var eventSink: FlutterEventSink?
func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}
func onListen(withArguments arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = eventSink
self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: {_ in
let dateFormat = DateFormatter()
dateFormat.dateFormat = "HH:mm:ss"
let time = dateFormat.string(from: Date())
eventSink(time)
})
return nil
}
}
注册监听
swift
eventChannel.setStreamHandler(TimeHandler())
Android端
new 一个EventChannel对象
在channel注册一个stream Handler
java
EventChannel.StreamHandler streamHandler = new EventChannel.StreamHandler() {
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
}
@Override
public void onCancel(Object arguments) {
}
};
eventChannel.setStreamHandler(streamHandler);
不断将当前时间返回
java
EventChannel.StreamHandler streamHandler = new EventChannel.StreamHandler() {
private final Handler handler = new Handler(Looper.getMainLooper());
private EventChannel.EventSink eventSink = null;
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
eventSink = events;
Runnable runnable = new Runnable() {
@Override
public void run() {
Locale locale = new Locale("zh", "CN");
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss", locale);
String time = dateFormat.format(new Date());
events.success(time);
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(runnable, 1000);
}
@Override
public void onCancel(Object arguments) {
eventSink = null;
}
};
eventChannel.setStreamHandler(streamHandler);
运行测试
在建立好EventChannel之后,运行项目。
获取到当前的时间,并且不停的
【3】BasicMessageChannel
约定一种数据格式,来互相传递数据
案例
传递Map数据到Android/Ios端,再解析并返回数据到Flutter端
Flutter端
构建BasicMessageChannel, 唯一标识name,约定数据格式StandardMessageCodec
dart
static const messageChannel =
BasicMessageChannel('basic_message_channel', StandardMessageCodec());
发送数据
dart
Map<String, dynamic> message = {
"name": "apple",
"time": "2024-04-09 12:30:00"
};
messageChannel.send(arguments)
接收数据
dart
Map reply = await messageChannel.send(arguments) as Map;
Android 端
接收数据
java
messageChannel.setMessageHandler((message, reply) -> {});
发送数据
java
reply.reply(resultMap);
java
package com.example.basic_message_channel_example;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StandardMessageCodec;
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
BinaryMessenger binaryMessenger = Objects.requireNonNull(getFlutterEngine()).getDartExecutor().getBinaryMessenger();
BasicMessageChannel<Object> messageChannel = new BasicMessageChannel<Object>(binaryMessenger, "basic_message_channel", StandardMessageCodec.INSTANCE);
messageChannel.setMessageHandler((message, reply) -> {
Map<Object, Object> arguments = (Map<Object, Object>) message;
assert message != null;
String name = (String) arguments.get("name");
assert name != null;
if (name.equals("apple")) {
Map<String, Object> resultMap = new HashMap<>();
String timeStr = (String) arguments.get("time");
Timestamp timestamp = Timestamp.valueOf(timeStr);
resultMap.put("message", "i eat the " + name + " at " + timestamp.toString());
resultMap.put("code", 200);
reply.reply(resultMap);
} else {
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("message", "i dislike " + name);
resultMap.put("code", 500);
reply.reply(resultMap);
}
});
}
}
Ios 端
构建通道
swift
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let basicMessageChannel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: controller.binaryMessenger)
接收数据
swift
basicMessageChannel.setMessageHandler { message, reply in
}
返回数据
swift
reply(result)
swift
import UIKit
import Flutter
@available(iOS 15.0, *)
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let channelName : String = "basic_message_channel"
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let basicMessageChannel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: controller.binaryMessenger)
basicMessageChannel.setMessageHandler { message, reply in
if let data = message as? Dictionary<String, Any> {
let name: String = data["name"] as? String ?? ""
if name == "apple" {
let timeStr: String = data["time"] as? String ?? ""
var message: String = "I eat the "
message.append(name)
message.append(" at ")
message.append(timeStr)
let result = ["code": 200, "message": message]
reply(result)
} else {
var message = "I dislike "
message.append(name)
let result = ["code": 500, "message": message]
reply(result)
}
}
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
运行测试
总结
MethodChannel 定义方法名调用
EventChannel 持续监听数据传递
BasicMessageChannel 约定一种数据格式,传递数据