Flutter 与原生通信

Flutter 与原生之间的通信主要基于通道机制,包括 MethodChannel、EventChannel 和 BasicMessageChannel。

  • MethodChannel:用于 Flutter 与原生之间的方法调用,实现双向通信,适合一次性的方法调用并获取返回值,如 Flutter调用原生拍照功能并获取照片路径。
  • EventChannel:主要用于原生向 Flutter 发送数据流,例如原生端将传感器数据实时传递给 Flutter 端。
  • BasicMessageChannel:用于 Flutter 与原生之间传递字符串、二进制数据等基本类型的数据,可进行简单的数据交换。

1. Flutter 调用原生

Flutter 端代码

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter 调用原生示例'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              const platform = MethodChannel('com.example.flutter_native');
              try {
                final String result = await platform.invokeMethod('getNativeMessage');
                print('原生返回的消息: $result');
              } on PlatformException catch (e) {
                print('调用原生方法失败: ${e.message}');
              }
            },
            child: const Text('调用原生方法'),
          ),
        ),
      ),
    );
  }
}

在 Flutter 端,创建 MethodChannel 实例,使用 invokeMethod 方法调用原生端的 getNativeMessage 方法,并处理返回结果。

安卓原生端代码(Kotlin)

kotlin 复制代码
package com.example.flutter_native

import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.example.flutter_native"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "getNativeMessage") {
                result.success("这是来自安卓原生的消息")
            } else {
                result.notImplemented()
            }
        }
    }
}

在安卓端,创建 MethodChannel 实例,设置方法调用处理程序,当接收到 getNativeMessage 方法调用时,返回消息给 Flutter 端。

iOS 原生端代码(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 channel = FlutterMethodChannel(name: "com.example.flutter_native", binaryMessenger: controller.binaryMessenger)
        channel.setMethodCallHandler { [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) in
            if call.method == "getNativeMessage" {
                result("这是来自 iOS 原生的消息")
            } else {
                result(FlutterMethodNotImplemented)
            }
        }
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

在 iOS 端,创建 FlutterMethodChannel 实例,设置方法调用处理程序,处理 getNativeMessage 方法调用并返回消息给 Flutter 端。

2. 原生调用 Flutter

Flutter 端代码

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const platform = MethodChannel('com.example.native_flutter');
    platform.setMethodCallHandler((call) async {
      if (call.method == "getFlutterMessage") {
        return "这是来自 Flutter 的消息";
      }
      return null;
    });

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('原生调用 Flutter 示例'),
        ),
        body: const Center(
          child: Text('等待原生调用...'),
        ),
      ),
    );
  }
}

在 Flutter 端,创建 MethodChannel 实例,使用 setMethodCallHandler 方法设置处理原生调用的回调,当接收到 getFlutterMessage 方法调用时,返回消息给原生端。

安卓原生端代码(Kotlin)

kotlin 复制代码
package com.example.native_flutter

import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.example.native_flutter"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
        channel.invokeMethod("getFlutterMessage", null) { result ->
            println("Flutter 返回的消息: $result")
        }
    }
}

在安卓端,创建 MethodChannel 实例,使用 invokeMethod 方法调用 Flutter 端的 getFlutterMessage 方法,并处理返回结果。

iOS 原生端代码(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 channel = FlutterMethodChannel(name: "com.example.native_flutter", binaryMessenger: controller.binaryMessenger)
        channel.invokeMethod("getFlutterMessage", arguments: nil) { (result) in
            if let message = result as? String {
                print("Flutter 返回的消息: \(message)")
            }
        }
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

在 iOS 端,创建 FlutterMethodChannel 实例,使用 invokeMethod 方法调用 Flutter 端的 getFlutterMessage 方法,并处理返回结果。

3. EventChannel和BasicMessageChannel

EventChannel和BasicMessageChannel跟上面MethodChannel大同小异。

EventChannel

Flutter端

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const eventChannel = EventChannel('com.example.event_channel');
    eventChannel.receiveBroadcastStream().listen((event) {
      print('接收到原生端的事件: $event');
    }, onError: (error) {
      print('接收事件时出错: $error');
    });

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('EventChannel 示例'),
        ),
        body: const Center(
          child: Text('等待原生端发送事件...'),
        ),
      ),
    );
  }
}

在 Flutter 端,创建 EventChannel 实例,使用 receiveBroadcastStream 方法接收原生端发送的数据流,并通过 listen 方法监听事件。

安卓端

kotlin 复制代码
 package com.example.event_channel

import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.example.event_channel"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        EventChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setStreamHandler(
            object : EventChannel.StreamHandler {
                private var eventSink: EventChannel.EventSink? = null

                override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
                    eventSink = events
                    // 模拟每隔 1 秒发送一个事件
                    val timer = android.os.Handler()
                    val runnable = object : Runnable {
                        var counter = 0
                        override fun run() {
                            eventSink?.success("事件 $counter")
                            counter++
                            timer.postDelayed(this, 1000)
                        }
                    }
                    timer.post(runnable)
                }

                override fun onCancel(arguments: Any?) {
                    eventSink = null
                }
            }
        )
    }
}

在安卓端,创建 EventChannel 实例,设置 StreamHandler,在 onListen 方法中模拟每隔 1 秒向 Flutter 端发送一个事件,在 onCancel 方法中取消事件发送。

iOS 原生端代码(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: "com.example.event_channel", binaryMessenger: controller.binaryMessenger)
        eventChannel.setStreamHandler(
            MyStreamHandler()
        )
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

class MyStreamHandler: NSObject, FlutterStreamHandler {
    var eventSink: FlutterEventSink?
    var timer: Timer?

    func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
        eventSink = events
        // 模拟每隔 1 秒发送一个事件
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            var counter = 0
            self?.eventSink?("事件 \(counter)")
            counter += 1
        }
        return nil
    }

    func onCancel(withArguments arguments: Any?) -> FlutterError? {
        timer?.invalidate()
        timer = nil
        eventSink = nil
        return nil
    }
}

在 iOS 端,创建 FlutterEventChannel 实例,设置 StreamHandler,在 onListen 方法中模拟每隔 1 秒向 Flutter 端发送一个事件,在 onCancel 方法中取消事件发送。

BasicMessageChannel

BasicMessageChannel 用于 Flutter 与原生之间传递字符串、二进制数据等基本类型的数据,是一种双向通信机制,适用于简单的数据交换场景,比如传递配置信息、状态信息等。双方可以互相发送和接收数据。

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const messageChannel = BasicMessageChannel<String>('com.example.message_channel', StringCodec());
    messageChannel.send('来自 Flutter 的消息').then((reply) {
      if (reply != null) {
        print('收到原生端的回复: $reply');
      }
    });

    messageChannel.setMessageHandler((message) async {
      print('收到原生端的消息: $message');
      return 'Flutter 已收到消息';
    });

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('BasicMessageChannel 示例'),
        ),
        body: const Center(
          child: Text('进行消息通信...'),
        ),
      ),
    );
  }
}

在 Flutter 端,创建 BasicMessageChannel 实例,使用 send 方法向原生端发送消息,并处理原生端的回复;使用 setMessageHandler 方法设置处理原生端发送消息的回调。

安卓原生端代码(Kotlin)

kotlin 复制代码
package com.example.message_channel

import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.StringCodec

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.example.message_channel"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        val messageChannel = BasicMessageChannel<String>(
            flutterEngine.dartExecutor.binaryMessenger,
            CHANNEL,
            StringCodec()
        )
        messageChannel.send("来自安卓原生的消息") { reply ->
            if (reply != null) {
                println("收到 Flutter 的回复: $reply")
            }
        }

        messageChannel.setMessageHandler { message, reply ->
            println("收到 Flutter 的消息: $message")
            reply.reply("安卓原生已收到消息")
        }
    }
}

在安卓端,创建 BasicMessageChannel 实例,使用 send 方法向 Flutter 端发送消息,并处理 Flutter 端的回复;使用 setMessageHandler 方法设置处理 Flutter 端发送消息的回调。

iOS 原生端代码(Swift)

kotlin 复制代码
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_channel", binaryMessenger: controller.binaryMessenger, codec: FlutterStringCodec.sharedInstance())
        messageChannel.sendMessage("来自 iOS 原生的消息") { (reply) in
            if let replyMessage = reply as? String {
                print("收到 Flutter 的回复: \(replyMessage)")
            }
        }

        messageChannel.setMessageHandler { (message, reply) in
            if let message = message as? String {
                print("收到 Flutter 的消息: \(message)")
                reply("iOS 原生已收到消息")
            }
        }
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

在 iOS 端,创建 FlutterBasicMessageChannel 实例,使用 sendMessage 方法向 Flutter 端发送消息,并处理 Flutter 端的回复;使用 setMessageHandler 方法设置处理 Flutter 端发送消息的回调。

另外:采用信鸽pigeons三方库通信也是一个不错的选择

相关推荐
iceiceiceice14 小时前
iOS PDF阅读器段评实现:如何从 PDFSelection 精准还原一个自然段
前端·人工智能·ios
TT_Close14 小时前
【Flutter×鸿蒙】FVM 不认鸿蒙 SDK?4步手动塞进去
flutter·swift·harmonyos
雨白16 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk16 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
TT_Close16 小时前
【Flutter×鸿蒙】一个"插队"技巧,解决90%的 command not found
flutter·harmonyos
LING16 小时前
RN容器启动优化实践
android·react native
恋猫de小郭19 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker1 天前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴1 天前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter