Flutter与原生通讯的channel

在 Flutter 里,和原生代码通讯的通道主要有三种,分别是MethodChannelEventChannelBasicMessageChannel,下面为你详细介绍它们的适用场景和使用方法。

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 之间的基本使用方法。

相关推荐
程序员Ctrl喵2 小时前
异步编程:Event Loop 与 Isolate 的深层博弈
开发语言·flutter
前端不太难3 小时前
Flutter 如何设计可长期维护的模块边界?
flutter
小蜜蜂嗡嗡4 小时前
flutter列表中实现置顶动画
flutter
始持5 小时前
第十二讲 风格与主题统一
前端·flutter
始持5 小时前
第十一讲 界面导航与路由管理
flutter·vibecoding
始持5 小时前
第十三讲 异步操作与异步构建
前端·flutter
新镜5 小时前
【Flutter】 视频视频源横向、竖向问题
flutter
黄林晴6 小时前
Compose Multiplatform 1.10 发布:统一 Preview、Navigation 3、Hot Reload 三箭齐发
android·flutter
Swift社区6 小时前
Flutter 应该按功能拆,还是按技术层拆?
flutter
肠胃炎7 小时前
树形选择器组件封装
前端·flutter