Rinf(Rust in Flutter)框架的源码分析之一
更新日期:
Rinf,即Rust in Flutter,在Flutter项目中使用Rust代码,该项目实现了一种集成方案,简化了构建过程。前一篇里简单介绍了Rinf的使用, 这里将分析下Rinf项目的源代码,了解其实现Flutter与Rust代码通信的原理。
Rinf项目生成的应用在运行时的结构如下图所示:
- 应用主体为flutter项目,Rust代码将生成一个动态链接库,在flutter中通过
dart:ffi
来加载。动态链接库在linux下名字为libhub.so
,windows下为hub.dll
- flutter与rust之间通过发送消息的方式通信,消息格式为probobuf编码;flutter中调用消息实例的
sendSignalToRust()
方法通过ffi将消息放入rust中的队列channel
,rust中使用get_dart_signal_receiver()
接收消息,然后在集成的tkio
异步框架里协程中进行消息处理;rust向flutter发送时, 调用结构体的send_signal_to_dart()
方法,消息将发送到flutter框架中的 dart isolate的端口上, 监听端口的listner处理器将消息放入消息类关联的队列rustSignalStream
, 然后flutter里处理消息后更新界面状态。 - 框架中命令行集成了
protobuf
代码生成工具,在生成消息对应的代码时插入发送消息代码,如flutter中sendSignalToRust()
, rust中的send_signal_to_dart()
- 消息通信过程是异步的、单向的,发送消息时定义请求消息的
protobuf
结构体,接收响应需要另外定义响应protobuf
结构体, 分别实现逻辑进行消息的发送与接收处理
由rinf创建的项目中的代码
代码分析分为2部分: 1) 在已有flutter项目中集成rinf框架时,由rinf工具创建的代码,即框架的使用; 2) rinf项目自身的源代码
在flutter项目目录下执行rinf template
命令后,项目下会生成messages与native2个目录 ,native的子目录下hub
是为rust cargo项目,构建时将生成libhub.so
或hub.dll
动态库。 执行rinf message
命令后,根据messages
下的.proto
定义生成源代码,生成的rust代码位于native/hub/src/messages
下,生成的dart代码位于lib/messages
下。
rust项目代码
先来看下rust中代码,native/hub/src/lib.rs
为主要方法,宏rinf::write_interface!()
用于生成动态链接库中的中方法,供dart:ffi
调用;main()
中使用tokio::spawn()
启动异步代码方法,3个方法为消息处理函数,下面将只关注sample_functions::tell_numbers()
native/hub/src/sample_functions.rs
是消息处理方法, 正如前面构架图里所说,SampleNumberInput::get_dart_signal_receiver()
获取receiver后,调用其recv()
获取消息体进行处理,结果再通过SampleNumberOutput::send_signal_to_dart()
发送。
宏rinf::write_interface!()
的实现方法如下,生成代码在mod interface_os
内,方法都使用extern "C"
进行声明。
flutter项目中的dart代码
lib/main.dart
即dart的main()方法,首行被插入代码await initializeRust()
,而其实现位于lib/main.dart
文件中。
lib/main.dart
文件内容如下,await prepareInterface(handleRustSignal)
的参数是函数指针handleRustSignal
,其根据messageId
从map中获取处理进行处理,其逻辑不过是将消息字节码转为对象,封装成RustSignal
对象后入Stream中。prepareInterface()
与startRustLogic()
都是rinf框架实现的
sampleNumberOutputController
对象的定义:
读取消息时使用的rustSignalStream
对象: