Rinf(Rust in Flutter)框架的源码分析之二
更新日期:
前一篇文章中分析了Rinf生成的项目的部分代码, 本篇将对Rinf在github的源代码进行情境分析。
Rinf项目的源代码结构如下图, 顶层有4个目录, automate里包含一个项目作者用于方便开发的python脚本, documentation是项目官网的源代码, flutter_ffi_plugin为fultter相关的代码, rust_crate为rust相关的源代码,将生成rinf。

将要进行入如下的情境分析:
rinf命令行的实现方式rinf template创建项目模板的过程rinf message生成protobuf代码的过程- Rinf项目构建过程
参考:
https://github.com/cunarist/rinf
rinf命令行的实现方式
从之前介绍Rinf文章中知道, 使用命令cargo install rinf来安装的rinf命令行工具,则可知其是在Rust中实现的,主要源代码在rust_crate/src/main.rs中。main.rs中主要内容是main()主函数的实现,lib.rs则是用于生成的项目中使用。

main()的大体流程是,先检查是否存在protoc命令,不存在则安装;拼接flutter/dart执行路径后,将protoc命令与dart执行路径加入PATH环境,最后调用dart命令dart run rinf,并传递执行命令行时剩余的参数。代码中使用宏#[cfg(not(target_family = "wasm"))]与#[cfg(target_family = "wasm")]来区分是否web wasm环境, 同样使用 #[cfg(target_family = "windows")]与 #[cfg(target_family = "unix")]区分windows与unix环境,进行有条件分别执行。
- 引用crate
which来执行linux/linux下的which命令,查找是否存在protoc命令:which::which("protoc") - 引用crate
home来获取当前用户的主目录let home_path = home::home_dir().unwrap(); - 引用crate
protoc_prebuilt,let install_result = protoc_prebuilt::init("25.2"); - 使用
process::Command来执行dart命令,处理命令行参数;执行的命令为dart run rinf,真正执行的逻辑又回到了dart代码中
rinf template创建项目模板的过程
在分析rust代码可知, 执行的dart命令为dart run rinf, 对应的主文件为flutter_ffi_plugin/bin/rinf.dart, 代码如下图所示, 是dart中的main()方法。它对传入的第一个参数使用switch-case进行, 对config/template/message/wasm等子命令分别进行处理, template命令对应于函数applyRustTemplate(), 实现位于文件flutter_ffi_plugin/bin/src/helpers.dart中, 使用import 'src/helpers.dart'引入。
函数applyRustTemplate() 执行的大致流程如下,大多是文件复制与修改操作:
- 获取当前应用项目的包路径,并会读取项目中的
pubspec.yaml,得到rinf包的路径 - 复制模板文件,将rinf包文件夹下的
example/native/的内容复制到项目下native/,将example/messages/复制到messages/ - 通过拼接字符串生成Rust项目的
Cargo.toml, 更新.gitgnore文件, 并生成README.md文件 - 格式化dart文件
./lib/main.dart, 然后进行修改操作,比如添加一行import './messages/generated.dart';, 在主函数main()的最开始部分加入调用await initializeRust(); - 最后调用
generateMessageCode()生成protobuf文件

rinf message生成protobuf代码的过程
rinf message命令的实现方法为generateMessageCode(), 位于文件flutter_ffi_plugin/bin/src/message.dart中。从.proto文件生成编程语言的代码,主要是通过protoc命令行编译工具来生成,rinf message命令的确也是通过命令行调用protoc命令进行的。
- 先收集proto文件的列表,将文件中
syntax开始的行替换为syntax = "proto3";即使用版本3,并插入一行package $resourceName;语句, 保证文件配置的完整 - 命令行调用
protoc分别生成rust与dart的代码: rust代码使用参数--prost_out=$rustFullPath, 会自动安装rust crateprotoc-gen-prost, 并为生成的包创建一个mod.rs文件; 生成dart代码使用参数--dart_out=$dartFullPath - 修改生成的protobuf message代码,添加相互传递消息的实现代码: rust文件中添加函数
get_dart_signal_receiver()与send_signal_to_dart()的实现, 在generated.rs文件中添加handle_dart_signal()实现代码; dart文件中添加函数sendSignalToRust()的实现与变量rustSignalStream的定义,生成handleRustSignal()的实现。
Rinf项目构建过程
rinf项目的构建过程就是flutter/dart的项目的构建,因为项目主体是flutter,而rust是作为动态链接库存在, 在构建过程中使用dart自动化rust插件的编译过程即可。
rinf使用了dart库Cargokit来编译rust, 源代码在flutter_ffi_plugin/cargokit目录下。