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)")

相关推荐
菜根Sec9 分钟前
XSS跨站脚本攻击漏洞练习
前端·xss
m0_7482571816 分钟前
Spring Boot FileUpLoad and Interceptor(文件上传和拦截器,Web入门知识)
前端·spring boot·后端
桃园码工33 分钟前
15_HTML5 表单属性 --[HTML5 API 学习之旅]
前端·html5·表单属性
百万蹄蹄向前冲1 小时前
2024不一样的VUE3期末考查
前端·javascript·程序员
轻口味2 小时前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami2 小时前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
吃杠碰小鸡2 小时前
lodash常用函数
前端·javascript
emoji1111112 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼2 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250033 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html