在Flutter中通过PlatformChannel与原生 Android 和 iOS 进行通信,其中 PlatformChannel 分为三种:

  • MethodChannel:用于传递方法调用。Flutter主动调用Native的方法,并获取相应的返回值。

  • EventChannel:用于数据流(event streams)的通信。

  • BasicMessageChannel:用于传递字符串和半结构化的信息。

一、MethodChannel(方法通道)

  1. 基本原理

    • MethodChannel 允许在 Flutter 和原生平台之间进行双向方法调用。通过定义一个特定的通道名称,Flutter 和原生代码都可以使用这个通道来发送和接收消息。

    • 在 Flutter 端,使用 MethodChannel类创建一个通道实例,并通过 invokeMethod方法调用原生平台的方法,或者使用 setMethodCallHandler方法设置一个处理原生平台调用 Flutter 方法的回调。

    • 在原生平台(Android 和 iOS)端,分别通过特定的代码来接收来自 Flutter 的方法调用,并可以通过通道向 Flutter 端返回结果。

  2. 示例

    • Flutter 端调用原生 Android 方法

      import 'package:flutter/services.dart';
      
      final MethodChannel _channel = MethodChannel('com.example.channel');
      
      Future
                           
        getPlatformVersion() async {   try {     final String version = await _channel.invokeMethod('getAndroidVersion');     return version;   } on PlatformException catch (e) {     return "Failed to get platform version: '${e.message}'.";   } }
                
    • 原生 Android 端响应 Flutter 调用

      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;
      import android.os.Build;
      import android.util.Log;
      
      public class MainActivity extends FlutterActivity {
        private static final String CHANNEL = "com.example.channel";
      
        @Override
        protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
              new MethodCallHandler() {
                @Override
                public void onMethodCall(MethodCall call, Result result) {
                  if (call.method.equals("getAndroidVersion")) {
                    result.success(Build.VERSION.RELEASE);
                  } else {
                    result.notImplemented();
                  }
                }
              });
        }
      }
    • Flutter 端调用原生 iOS 方法

      import 'package:flutter/services.dart';
      
      final MethodChannel _channel = MethodChannel('com.example.channel');
      
      Future
                           
        getPlatformVersion() async {   try {     final String version = await _channel.invokeMethod('getiOSVersion');     return version;   } on PlatformException catch (e) {     return "Failed to get platform version: '${e.message}'.";   } }
                
    • 原生 iOS 端响应 Flutter 调用

      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 channel = FlutterMethodChannel(name: "com.example.channel", binaryMessenger: controller.binaryMessenger)
          channel.setMethodCallHandler({
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            if call.method == "getiOSVersion" {
              result(UIDevice.current.systemVersion)
            } else {
              result(FlutterMethodNotImplemented)
            }
          })
          GeneratedPluginRegistrant.register(with: self)
          return super.application(application, didFinishLaunchingWithOptions: launchOptions)
        }
      }

二、EventChannel(事件通道)

  1. 基本原理

    • EventChannel 用于从原生平台向 Flutter 端发送数据流。原生平台可以不断地发送事件,Flutter 端通过设置事件监听器来接收这些事件。

    • 在 Flutter 端,使用 EventChannel类创建一个通道实例,并通过 receiveBroadcastStream方法获取一个流,然后可以使用 StreamBuilder等方式监听这个流。

    • 在原生平台端,通过特定的方式生成事件流并发送给 Flutter。

  2. 示例

    • Flutter 端监听原生 Android 事件

      import 'package:flutter/services.dart';
      
      final EventChannel _eventChannel = EventChannel('com.example.event');
      
      StreamSubscription _subscription;
      
      void startListening() {
        _subscription = _eventChannel.receiveBroadcastStream().listen((event) {
          print('Received event from Android: $event');
        }, onError: (error) {
          print('Error receiving event: $error');
        }, onDone: () {
          print('Event stream completed.');
        });
      }
      
      void stopListening() {
        _subscription?.cancel();
      }
    • 原生 Android 端发送事件到 Flutter

      import io.flutter.plugin.common.EventChannel;
      import io.flutter.plugin.common.EventChannel.EventSink;
      import android.util.Log;
      
      public class EventEmitterService extends Service {
        private static final String TAG = "EventEmitterService";
        private EventChannel.EventSink _eventSink;
      
        @Override
        public void onCreate() {
          super.onCreate();
          new EventChannel(getApplicationContext().getMainLooper(), "com.example.event").setStreamHandler(
              new EventChannel.StreamHandler() {
                @Override
                public void onListen(Object args, EventSink eventSink) {
                  _eventSink = eventSink;
                  startEmittingEvents();
                }
      
                @Override
                public void onCancel(Object args) {
                  _eventSink = null;
                }
              });
        }
      
        private void startEmittingEvents() {
          new Thread(new Runnable() {
            @Override
            public void run() {
              while (_eventSink!= null) {
                _eventSink.success("Event from Android");
                try {
                  Thread.sleep(5000);
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
              }
            }
          }).start();
        }
      }
    • Flutter 端监听原生 iOS 事件

      import 'package:flutter/services.dart';
      
      final EventChannel _eventChannel = EventChannel('com.example.event');
      
      StreamSubscription _subscription;
      
      void startListening() {
        _subscription = _eventChannel.receiveBroadcastStream().listen((event) {
          print('Received event from iOS: $event');
        }, onError: (error) {
          print('Error receiving event: $error');
        }, onDone: () {
          print('Event stream completed.');
        });
      }
      
      void stopListening() {
        _subscription?.cancel();
      }
    • 原生 iOS 端发送事件到 Flutter

      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: "com.example.event", binaryMessenger: controller.binaryMessenger)
          eventChannel.setStreamHandler(MyEventStreamHandler())
          GeneratedPluginRegistrant.register(with: self)
          return super.application(application, didFinishLaunchingWithOptions: launchOptions)
        }
      }
      
      class MyEventStreamHandler: NSObject, FlutterStreamHandler {
        private var eventSink: FlutterEventSink?
      
        func onListen(withArguments arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? {
          self.eventSink = eventSink
          startEmittingEvents()
          return nil
        }
      
        func onCancel(withArguments arguments: Any?) -> FlutterError? {
          eventSink = nil
          return nil
        }
      
        private func startEmittingEvents() {
          DispatchQueue.global().async {
            while self.eventSink!= nil {
              self.eventSink!("Event from iOS")
              sleep(5)
            }
          }
        }
      }

三、BasicMessageChannel(基本消息通道)

  1. 基本原理

    • BasicMessageChannel 用于在 Flutter 和原生平台之间进行异步消息传递。可以发送任意类型的消息,并可以处理消息的回复。

    • 在 Flutter 端,使用 BasicMessageChannel类创建一个通道实例,并通过 send方法发送消息,设置一个处理原生平台回复的回调。

    • 在原生平台端,接收来自 Flutter 的消息,并可以通过通道向 Flutter 端发送回复。

  2. 示例

    • Flutter 端发送消息到原生 Android 并接收回复

      import 'package:flutter/services.dart';
      
      final BasicMessageChannel
                           
        _messageChannel =     BasicMessageChannel
                              
       ('com.example.message', StringCodec()); Future
                                
        sendMessageToAndroid(String message) async {   try {     final String reply = await _messageChannel.send(message);     return reply;   } on PlatformException catch (e) {     return "Failed to send message: '${e.message}'.";   } }
                   
                  
                
    • 原生 Android 端接收 Flutter 消息并回复

      import io.flutter.plugin.common.BasicMessageChannel;
      import io.flutter.plugin.common.BasicMessageChannel.MessageHandler;
      import io.flutter.plugin.common.BasicMessageChannel.Reply;
      import android.util.Log;
      
      public class MainActivity extends FlutterActivity {
        private static final String CHANNEL = "com.example.message";
      
        @Override
        protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          final BasicMessageChannel
                
        messageChannel =  new BasicMessageChannel<>(         getFlutterView(), CHANNEL, StringCodec.INSTANCE);     messageChannel.setMessageHandler( new MessageHandler () {        @Override        public void onMessage(String message, Reply  reply)  {         Log.d( "MessageChannel",  "Received message from Flutter: " + message);         reply.reply( "Reply from Android: " + message);       }     });   } }
    • Flutter 端发送消息到原生 iOS 并接收回复

      import 'package:flutter/services.dart';
      
      final BasicMessageChannel
                           
        _messageChannel =     BasicMessageChannel
                              
       ('com.example.message', StringCodec()); Future
                                
        sendMessageToiOS(String message) async {   try {     final String reply = await _messageChannel.send(message);     return reply;   } on PlatformException catch (e) {     return "Failed to send message: '${e.message}'.";   } }
                   
                  
                
    • 原生 iOS 端接收 Flutter 消息并回复

      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: "com.example.message", binaryMessenger: controller.binaryMessenger, codec: FlutterStringCodec.sharedInstance())
          messageChannel.setMessageHandler({ (message, reply) in
            print("Received message from Flutter: \(message?? "")")
            reply("Reply from iOS: \(message?? "")")
          })
          GeneratedPluginRegistrant.register(with: self)
          return super.application(application, didFinishLaunchingWithOptions: launchOptions)
        }
      }

--- END ---