在 Flutter 里,和原生代码通讯的通道主要有三种,分别是MethodChannel
、EventChannel
和BasicMessageChannel
,下面为你详细介绍它们的适用场景和使用方法。
1. MethodChannel
适用场景
适用于 Flutter 和原生之间进行方法调用,也就是 Flutter 调用原生方法,原生返回结果,或者原生调用 Flutter 方法,Flutter 返回结果。比如调用原生的相机、分享功能等。
使用方法
以下是一个简单的示例,展示了 Flutter 如何通过 MethodChannel
调用原生 iOS 的方法。
Flutter 端代码
dart
dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
static const platform = MethodChannel('samples.flutter.dev/battery');
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level: $result%';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
print(batteryLevel);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Battery Level'),
),
body: Center(
child: ElevatedButton(
onPressed: _getBatteryLevel,
child: const Text('Get Battery Level'),
),
),
),
);
}
}
iOS 端代码(Swift)
swift
swift
import Flutter
import UIKit
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery", binaryMessenger: controller.binaryMessenger)
batteryChannel.setMethodCallHandler {
(call: FlutterMethodCall, result: @escaping FlutterResult) in
if call.method == "getBatteryLevel" {
self.receiveBatteryLevel(result: result)
} else {
result(FlutterMethodNotImplemented)
}
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func receiveBatteryLevel(result: @escaping FlutterResult) {
UIDevice.current.isBatteryMonitoringEnabled = true
if UIDevice.current.batteryState == .unknown {
result(FlutterError(code: "UNAVAILABLE",
message: "Battery info unavailable",
details: nil))
} else {
result(Int(UIDevice.current.batteryLevel * 100))
}
}
}
2. EventChannel
适用场景
适用于原生向 Flutter 发送连续的事件流,比如传感器数据、网络状态变化等。
使用方法
以下是一个简单的示例,展示了 iOS 端如何通过 EventChannel
向 Flutter 发送模拟的传感器数据。
Flutter 端代码
dart
php
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
static const stream = EventChannel('samples.flutter.dev/sensor');
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Sensor Data'),
),
body: StreamBuilder(
stream: stream.receiveBroadcastStream(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
if (snapshot.hasData) {
return Text('Sensor data: ${snapshot.data}');
}
return const Text('Waiting for data...');
},
),
),
);
}
}
iOS 端代码(Swift)
swift
swift
import Flutter
import UIKit
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let eventChannel = FlutterEventChannel(name: "samples.flutter.dev/sensor", binaryMessenger: controller.binaryMessenger)
eventChannel.setStreamHandler(SensorStreamHandler())
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
class SensorStreamHandler: NSObject, FlutterStreamHandler {
private var timer: Timer?
private var eventSink: FlutterEventSink?
private var counter = 0
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
eventSink = events
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
guard let self = self else { return }
if self.counter < 10 {
self.eventSink?(self.counter)
self.counter += 1
} else {
self.eventSink?(FlutterEndOfEventStream)
self.timer?.invalidate()
}
}
return nil
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
timer?.invalidate()
eventSink = nil
return nil
}
}
3. BasicMessageChannel
适用场景
适用于 Flutter 和原生之间进行简单的消息传递,比如传递字符串、JSON 数据等。
使用方法
以下是一个简单的示例,展示了 Flutter 和 iOS 之间通过 BasicMessageChannel
传递字符串消息。
Flutter 端代码
dart
dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
static const messageChannel = BasicMessageChannel<String>('samples.flutter.dev/message', StringCodec());
Future<void> _sendMessage() async {
try {
final String reply = await messageChannel.send('Hello from Flutter!');
print('Received reply: $reply');
} catch (e) {
print('Error sending message: $e');
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Message Channel'),
),
body: Center(
child: ElevatedButton(
onPressed: _sendMessage,
child: const Text('Send Message'),
),
),
),
);
}
}
iOS 端代码(Swift)
swift
swift
import Flutter
import UIKit
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let messageChannel = FlutterBasicMessageChannel(name: "samples.flutter.dev/message", binaryMessenger: controller.binaryMessenger, codec: FlutterStringCodec.sharedInstance())
messageChannel.setMessageHandler { (message: Any?, reply: @escaping (Any?) -> Void) in
if let messageString = message as? String {
print("Received message: (messageString)")
reply("Hello from iOS!")
} else {
reply(nil)
}
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
这些示例展示了三种通道在 Flutter 和 iOS 之间的基本使用方法。