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三方库通信也是一个不错的选择

相关推荐
2501_9160074733 分钟前
iOS 混淆工具链实战,多工具组合完成 IPA 混淆与加固(iOS混淆|IPA加固|无源码混淆|App 防反编译)
android·ios·小程序·https·uni-app·iphone·webview
LinXunFeng1 小时前
Flutter webview 崩溃率上升怎么办?我的分析与解决方案
flutter·ios·webview
Jeled2 小时前
Retrofit 与 OkHttp 全面解析与实战使用(含封装示例)
android·okhttp·android studio·retrofit
游戏开发爱好者82 小时前
FTP 抓包分析实战,命令、被动主动模式要点、FTPS 与 SFTP 区别及真机取证流程
运维·服务器·网络·ios·小程序·uni-app·iphone
西西学代码4 小时前
Flutter---GridView+自定义控件
flutter
Nick56835 小时前
Xcode16 避坑
ios
ii_best5 小时前
IOS/ 安卓开发工具按键精灵Sys.GetAppList 函数使用指南:轻松获取设备已安装 APP 列表
android·开发语言·ios·编辑器
2501_915909065 小时前
iOS 26 文件管理实战,多工具组合下的 App 数据访问与系统日志调试方案
android·ios·小程序·https·uni-app·iphone·webview
hweiyu005 小时前
苹果iOS开发零基础特训(视频教程)
ios
limingade6 小时前
手机转SIP-手机做中继网关-落地线路对接软交换呼叫中心
android·智能手机·手机转sip·手机做sip中继网关·sip中继