Flutter与原生通信之iOS

Flutter与原生通信之iOS

Flutter 与原生交互有三种方式:

  • MethodChannel
  • EventChannel
  • BasicMessageChannel

==MethodChannel==

是Flutter与原生交互的一种方式,此种方式传递的是方法,可以双向传递,可以携带参数,双向传递都可以有返回值

Flutter给原生端发送消息

  • Flutter端代码
csharp 复制代码
final methodChannel = const MethodChannel('test_method_channel');
Future<void> sendMessageFromMethodChannel() async {
  final result = await methodChannel.invokeMethod("method_one");
  print(result);
}

定义发送消息 MethodChannel生成对应的channel,需要指定channel的name 发送消息使用的是:invokeMethod 指定方法名,也可以带参数,有返回值

  • 原生端代码配置
swift 复制代码
var channel: FlutterMethodChannel

init(messager: FlutterBinaryMessenger) {

   channel = FlutterMethodChannel(name: "test_method_channel", binaryMessenger: messager)

     channel.setMethodCallHandler { (call , result) in

     print("接收到了来自Flutter发送的方法\(call.method)")

     result("我是原生返回给Flutter的消息")
   }
}

定义好channel,注册方法 setMethodCallHandler 在AppDelegate入口函数处需要初始化

javascript 复制代码
let controller = window.rootViewController as! FlutterBinaryMessenger
MethodChannelManager(messager: controller.binaryMessenger)

原生(iOS为例)给Flutter发送消息

  • iOS原生端配置
swift 复制代码
	var channel: FlutterMethodChannel

    init(messager: FlutterBinaryMessenger) {
        channel = FlutterMethodChannel(name: "test_method_channel", binaryMessenger: messager)
        channel.setMethodCallHandler { (call , result) in
            print("接收到了来自Flutter发送的方法\(call.method)")
            result("我是原生返回给Flutter的消息")
            self.startTimer()
        }
    }

    func startTimer() {
        Timer.scheduledTimer(timeInterval: TimeInterval(2), target: self, selector: #selector(sendMessageToFlutter), userInfo: nil, repeats: false)

    }
    @objc func sendMessageToFlutter() {
        channel.invokeMethod("ios_method", arguments: "我是原生主动发送过来的") {(result) in
            print(result)

     	}
  	}

原生端发送消息也是调用 invokeMethod,也可以以闭包形式接收到Flutter端的返回值

  • Flutter端配置
dart 复制代码
Future<void> setMethodChannelCallHandler() async {
  methodChannel.setMethodCallHandler((call) async {
    print('Flutter收到了原生端的方法:${call.method}, 传参为:${call.arguments} ---- call: $call');
    return Future.value('我是Flutter回传给原生端的数据');
  });
}

@override
void initState() {
  // TODO: implement initState
    super.initState();
    setMethodChannelCallHandler();
}

Flutter中配置的setMethodChannelCallHandler也可以给原生回传数据,直接返回一个 Future即可


==BasicMessageChannel==

也是双向交互,发送字符串和半结构化信息,有返回值

  • Flutter端 需要在Flutter端创建一个channel
ini 复制代码
final basicMessageChannel = const BasicMessageChannel('test_basic_message_channel', StandardMessageCodec());

第一个参数是channel的name 第二个参数是codec

swift 复制代码
/// The message codec used by this channel, not null.
final MessageCodec<T> codec;

看源码注释,它是一个抽象类,是message的编码和解码机制,这里只需要使用系统默认的标准方式 StandardMessageCodec即可 class StandardMessageCodec implements MessageCodec<Object?> StandardMessageCodec实现了抽象类 MessageCodec,具体可以看源码 发送消息

csharp 复制代码
Future<void> sendMessageFromBasicMessageChannel() async {
  final result = await basicMessageChannel.send('我是Flutter主动传递给原生的消息');
  print(result);

send方法返回值是一个Future,类型是泛型,所以可以通过await获取原生端返回给Flutter的值,下面在原生端会体现。 接收消息

csharp 复制代码
Future<void> setBasicMessageChannelCallHandler() async {
  basicMessageChannel.setMessageHandler((message) async {
    print('Flutter收到了原生端的消息:$message');
    return Future.value('我是Flutter回传给原生的消息');
  });
}
  • iOS原生端 定义一个BasicMessageChannelManager管理类,在入口函数中初始化:
javascript 复制代码
let controller = window.rootViewController as! FlutterBinaryMessenger
BasicMessageChannelManager(messager: controller.binaryMessenger)

接收消息

swift 复制代码
class BasicMessageChannelManager {
    var channel: FlutterBasicMessageChannel
    init(messager: FlutterBinaryMessenger) {
        channel = FlutterBasicMessageChannel(name: "test_basic_message_channel", binaryMessenger: messager)
        channel.setMessageHandler { (message, reply) in
            print("原生端收到了来自Flutter端的消息\(message!)")
            reply("原生端返回给Flutter端的消息")
        }
    }
}

在初始化方法中初始化 channel,并配置channel方法监听,message表示Flutter端发送过来的消息,reply是原生端给Flutter返回值的一个闭包 发送消息

scss 复制代码
@objc func sendMessageToFlutter() {
      channel.sendMessage("原生端主动发送给Flutter的消息") {(result) in
         print(result!)
     }
 }

channel通过sendMessage发送消息,可以带上后面的闭包,result为Flutter端返回给原生端的消息


==EventChannel==

是原生向Flutter传递数据流的通道,属于单向传输,只能由原生端调用,Flutter端是接收信息,常见的有网络变化监听,屏幕横竖屏切换,位置切换,电池电量,远程通知等事件。

  • Flutter端代码 final eventChannel = const EventChannel('test_event_channel'); 定义channel
scss 复制代码
Future<void> setEventChannel() async {
  _streamSubscription = eventChannel.receiveBroadcastStream().listen((event) {
    print('Flutter收到了原生端的事件:$event');
  }, onError: (error) {
    print(error);
  }, onDone: () {
    print('done');
  }, cancelOnError: true);
}

组件初始化中设置回调

  1. 闭包第一个回调为onData,参数event为泛型,表示原生端返回的信息内容
  2. onError: 报错会执行
  3. onDone: 时间完成会执行
  4. cancelOnError: 报错后是否取消事件

iOS原生端

swift 复制代码
class EventChannelManager: NSObject  {
    var channel: FlutterEventChannel
    var eventSink: FlutterEventSink?
    var count = 0
    var timer: Timer?
    init(messager: FlutterBinaryMessenger) {
        channel = FlutterEventChannel(name: "test_event_channel", binaryMessenger: messager)
    }
    func config() {
        channel.setStreamHandler(**self**)
    }
    func startTimer() {
       timer = Timer(timeInterval: TimeInterval(2), target: self, selector: #selector triggerEventChannel), userInfo: nil, repeats: true)
        RunLoop.current.add(timer!, forMode: .common)
    }
    @objc func triggerEventChannel() {
        count += 1
        eventSink?("当前数值为:\(count)")
    }
}

extension EventChannelManager : FlutterStreamHandler {

    func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
        self.eventSink = events
        startTimer()
        return nil
    }
    func onCancel(withArguments arguments: **Any**?) -> FlutterError? {
        return nil
    }
}

AppDelegate中调用:

scss 复制代码
let eventChannelManager = EventChannelManager(messager: messager)
eventChannelManager.config()

和其他两种通信方式不同的是,EventChannel需要在原生端实现 FlutterStreamHandler协议,获取到 FlutterEventSink,用它来进行消息的发送 eventSink?("当前数值为:(count)")

相关推荐
什么鬼昵称14 分钟前
Pikachu-csrf-CSRF(get)
前端·csrf
长天一色31 分钟前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_2341 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
秋殇与星河1 小时前
CSS总结
前端·css
BigYe程普1 小时前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发
余生H2 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
程序员-珍2 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
axihaihai2 小时前
网站开发的发展(后端路由/前后端分离/前端路由)
前端
流烟默2 小时前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
2401_857297912 小时前
招联金融2025校招内推
java·前端·算法·金融·求职招聘