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

相关推荐
寒水馨12 分钟前
macOS下载、安装 Tailwind CSS-v4.3.3(附安装包tailwindcss-macos-arm64)
前端·css·macos·tailwind css·utility-first·css 框架·实用优先
shawxlee26 分钟前
vue3+axios挑战最简洁实用的配置封装+接口调用:请求拦截器、响应拦截器、通用请求方法(单个请求/并发请求/下载文件)、统一接口管理
前端·经验分享·vue·接口·axios·api
yuhaiqiang1 小时前
上线一个人静态网站需要多少钱,难不难?
前端·后端·程序员
宸津-代码粉碎机1 小时前
Jar热部署进阶实战|修复原生方案OOM与类冲突问题,生产级无BUG优化方案
java·大数据·服务器·开发语言·前端·人工智能·python
To_OC9 小时前
写了三遍 Todo List,我终于搞懂了 React 父子组件到底怎么通信
前端·javascript·react.js
勇往直前plus10 小时前
Vue3(篇一) 核心概念——响应式模板语法与组件基础
前端·javascript·vue.js
咩咩啃树皮10 小时前
第43篇:Vue3计算属性(computed)完全精讲——缓存机制、依赖计算、业务最优解
前端·vue.js·缓存
徐小夕12 小时前
花了一周,3亿tokens,我开源了一款 Word 文档智能审查平台,文稿自动质检+可视化分析,告别低效人工审核
前端·算法·github
kyriewen13 小时前
别再乱用useEffect了——你写的10个里有8个不该存在
前端·javascript·react.js
Ivanqhz13 小时前
Rust &‘static str浅析
java·前端·javascript·rust