如何通过 FFI 调用 Flutter (Dart) 中的 Rust 函数,又方便又安全?

How to call Rust functions in Flutter (Dart) via FFI, but with convenience and safety?

我知道我们可以通过 FFI 从 Flutter/Dart 调用 Rust。但是Flutter在做FFI的时候只允许C ABI。因此,我必须手动写下样板代码。特别是 Rust unsafe 代码——因为我必须处理很多原始指针:(

因此,有什么方法可以安全地做到这一点吗?我们知道 Rust 本身是非常安全的(因为它独特的内存管理方式),Dart/Flutter 本身也非常安全(因为 GC)。但我不希望 ffi 调用成为致命弱点并破坏我的应用程序的安全性!

有几种方法可以做到。

一个。 JSON/Protobuf-based 方法

我在生产环境使用了一年的第一种方式是,可以使用JSON或者Protobuf来传递Rust和Dart/Flutter之间的所有数据。通过这样做,您不需要将大量样板代码写到 allocate/free 字符串、字节列表、struct/class 等。您需要做的就是写下 one 接受字节数组负载并输出字节数组结果的单个函数。通过说“一个”函数,我的意思是,您可以在 JSON/Protobuf 中有一个 action 字段,因此可以将对不同 Rust 函数的调用交错到这个薄接口中。

尽管它很方便(只有一点点 不安全 样板),缺点也很明显。序列化和反序列化不是免费的。您将不得不为此付出 CPU 的时间和内存,有时可能会非常大。此外,您不能轻易绕过大物体。例如,如果你有一个图像(你知道,至少有兆字节大小),将它序列化到 Protobuf,然后从 Protobuf 反序列化它可能会浪费 CPU 和内存 - 无用的副本!更糟糕的是,由于 Flutter/Dart FFI 不支持异步 FFI 的便捷方式,您必须将其 运行 放在一个单独的工作隔离区中 - 多一份内存副本。你可以在这里看到更多:https://github.com/dart-lang/language/issues/1862(这是我打开的问题)。

b。代码生成器

我最近使用的第二种方法是写一个代码生成器。事实上,代码遵循几种常见的模式,例如“分配 - 填充数据 - 调用 FFI - 免费”等。因此编写一个生成器来自动执行此类操作并不难。这个想法是模仿人类在手动写下样板代码时会做什么。

本来希望已经有可以直接使用的代码生成器了,不过好像有none...所以,自己写吧

c。使用现有的开源代码生成器

我把代码生成器写下来后,我猜大家可能和我有同样的问题,所以我把它开源了:https://github.com/fzyzcjy/flutter_rust_bridge

确实,我的代码生成器不仅解决了上面的问题,而且有丰富的类型支持,允许零拷贝,允许异步编程和直接从main isolate调用等,这些都可以通过代码生成器实现,但是会如果您手动完成,则需要大量样板代码。

免责声明:这是一个问答式的回答,以展示我的想法以及我对这个问题所做的工作,这个问题对我自己的应用程序在生产环境中至关重要。事实上,我从去年就开始使用 JSON 方法,后来重构为代码生成器方法。希望也能帮到其他遇到同样情况的人!