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
目录下。