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

相关推荐
程一个大前端1 小时前
【Flutter高效开发】GetX指南:一文学会状态管理、路由与依赖注入
flutter
DEVIL2 小时前
Flutter中各类Controller的本质
android·flutter
ak啊5 小时前
Flutter UI 组件应用一:布局、交互、动画与弹窗
flutter
JarvanMo10 小时前
# 还在用灰秃秃的图片占位符?快来试试这款神器
前端·flutter
恋猫de小郭11 小时前
Flutter 在全新 Platform 和 UI 线程合并后,出现了什么大坑和变化?
android·前端·flutter
程序员老刘1 天前
差生文具多
flutter·客户端
星释1 天前
鸿蒙Flutter仓库停止更新?
flutter·华为·harmonyos
ak啊1 天前
Flutter UI 组件基础
flutter
在广东捡破烂的吴彦祖1 天前
window配置Flutter开发环境
前端·flutter