本文由 简悦SimpRead 转码,原文地址 dev.to
Dart的一小部分 Dart是一种客户端优化的语言,可以在任何平台上实现快速的应用,…
Dart的一小部分
Dart是一种客户端优化的语言,适用于任何平台上的快速应用程序,它使你的应用程序的用户界面很容易建立,而且它是相当不错的语言,它是Flutter框架使用的语言,Flutter是谷歌的UI工具包,用于从单一代码库为移动、网络和桌面建立漂亮的、本地编译的应用程序。
输入Rust
Rust速度快得惊人,内存效率高,没有运行时或垃圾收集器,它可以为性能关键的服务提供动力,在嵌入式设备上运行,并容易与其他语言集成。
我们在Sunshine同时使用Rust和Dart(在Flutter中),以使开源资助计划能够在一个链上生态系统中轻松运作。
我们几乎所有的代码都是用Rust编写的,这就是为什么我们需要考虑在我们的客户端应用程序中使用相同的代码和相同的逻辑,但如何使用?
好吧,让我们看看我们在这里有哪些选择
使用Flutter平台通道
Flutter Platform channels是一个灵活的系统,它允许你调用平台特定的API,无论是在Android上的Kotlin或Java代码中,还是在iOS上的Swift或Objective-C代码中都可以使用。 这样一来,我们将不得不首先把我们的Rust代码与Java(用于Android)、Swift(用于iOS)和WASM(用于Web)绑定,但这将是一个过于复杂的过程,也许这可能会导致未来的性能问题。下面是一个简单的图表,让我们了解一下它是怎样的。
但正如你所看到的,这里涉及到很多开销,数据序列化/反序列化在运行时非常昂贵,所以我们还能做什么呢?
FFI,打破界限
正如维基百科所说。外来函数接口(FFI)是一种机制,用一种编程语言编写的程序可以调用另一种语言编写的程序或服务。
嗯,有意思,让我们看看我们能做什么,Dart支持FFI吗? 是的!,实际上FFI在Dart 2.5 最近在去年年底引入,所以它仍在积极开发中,但相当稳定。
在玩过FFI Examples with Dart之后,我开始着手开发flutterust,这是一个简单的模板,用来展示如何通过FFI使用Flutter/Dart和Rust。
这里的简单想法是,我们为所有支持的目标建立我们的Rust代码,然后建立一个使用这些目标的Flutter包。
以下是使用FFI方法的好处
- 没有Swift/Kotlin包装器
- 没有消息传递
- 没有Dart上的async/await
- 一次写入,到处使用
- 没有垃圾收集
- 不需要导出
aar
包或.framework
。
因此,它将是这样的。
这真是太酷了,下面是一个简单的例子
学习如何计数!
我们将使用同样的flutter hello world的例子,但不是在Dart端做逻辑(增加计数器),而是在Rust端做。
我们的项目Sturcutre。
.
├── android
├── ios
├── lib <- The Flutter App Code
├── native <- Containes all the Rust Code
│ ├── adder
│ └── adder-ffi
├── packages <- Containes all the Dart Packages that bind to the Rust Code
│ └── adder_ffi
├── target <- The compiled rust code for every arch
│ ├── aarch64-apple-ios
│ ├── aarch64-linux-android
│ ├── armv7-linux-androideabi
│ ├── debug
│ ├── i686-linux-android
│ ├── universal
│ ├── x86_64-apple-ios
│ └── x86_64-linux-android
└── test
Rust方面
首先创建一个Cargo工作空间,所以我们在Flutter应用的根目录下添加一个简单的Cargo.toml
。
[workspace]
members = ["native/*"]
[profile.release]
lto = true
codegen-units = 1
debug = true # turn it off if you want.
创建我们简单的adder
包
$ cargo new --lib native/adder
我们来写一些代码
pub fn add(a: i64, b: i64) -> i64 {
a.wrapping_add(b)
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(super::add(2, 2), 4);
}
}
很无聊,不是吗?🥱
让我们向世界展示我们新的add
函数 :)
$ cargo new --lib native/adder-ffi
别忘了在 “native/adder-ffi/Cargo.toml “中改变它的类型
[lib]
name = "adder_ffi"
crate-type = ["cdylib", "staticlib"]
[dependencies]
adder = { path = "../adder" }
// lib.rs
#[no_mangle]
pub extern "C" fn add(a: i64, b: i64) -> i64 {
adder::add(a, b)
}
很好,但如何将我们的代码编译到手机上呢? 嗯,这有点复杂。我们可以直接使用cargo,当然也可以,但是我们需要配置很多其他的东西,所以我们将转而使用其他工具来为我们做这件事,比如cargo-lipo
和 cargo-ndk
。
在将我们的rust代码编译到所有这些平台后。
aarch64-apple-ios
aarch64-linux-android
armv7-linux-androideabi
i686-linux-android
x86_64-apple-ios
x86_64-linux-android
我们准备进入下一步,我们将把我们的编译代码复制到特定位置
首先生成一个以我们的rust crate命名的flutter插件。
$ flutter create --template=plugin packages/adder
target/universal/debug/libadder_ffi.a -> packages/adder/ios/libadder_ffi.a
target/aarch64-linux-android/debug/libadder_ffi.so -> packages/adder/android/src/main/jniLibs/arm64-v8a/libadder_ffi.so
...
...other android libs
我们准备好了吗?嗯,技术上是的,但是Xcode还有另外一件事要做,比如为我们的iOS的FFI写一个C头文件,如果你在macOS上开发,你应该做这些步骤这里除此之外,你已经准备好进入下一步,为我们的rust lib写一个Flutter包。
Dart方面
所以回到Dart,在我们生成的flutter插件中,我们将在Dart代码中定义我们的rust函数的样子(类型定义)。
import 'dart:ffi';
// For C/Rust
typedef add_func = Int64 Function(Int64 a, Int64 b);
// For Dart
typedef Add = int Function(int a, int b);
我们需要一个函数,根据iOS/Android或Linux/MacOS等平台,加载我们的Rust库。
import 'dart:io' show Platform;
DynamicLibrary load({String basePath = ''}) {
if (Platform.isAndroid || Platform.isLinux) {
return DynamicLibrary.open('${basePath}libadder_ffi.so');
} else if (Platform.isIOS) {
// iOS is statically linked, so it is the same as the current process
return DynamicLibrary.process();
} else if (Platform.isMacOS) {
return DynamicLibrary.open('${basePath}libadder_ffi.dylib');
} else if (Platform.isWindows) {
return DynamicLibrary.open('${basePath}libadder_ffi.dll');
} else {
throw NotSupportedPlatform('${Platform.operatingSystem} is not supported!');
}
}
class NotSupportedPlatform implements Exception {
NotSupportedPlatform(String s);
}
最后创建一个简单的类,用来存放我们的ffi函数
class Adder {
static DynamicLibrary _lib;
Adder() {
if (_lib != null) return;
// for debugging and tests
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
_lib = load(basePath: '../../../target/debug/');
} else {
_lib = load();
}
}
}
这里是 “添加 “方法
int add(int a, int b) {
// get a function pointer to the symbol called `add`
final addPointer = _lib.lookup<NativeFunction<add_func>>('add');
// and use it as a function
final sum = addPointer.asFunction<Add>();
return sum(a, b);
}
到目前为止还不错,让我们在我们的Flutter应用程序中使用它吧
在应用程序的pubspec.yaml
中,在dependencies
下添加我们的adder
包
adder:
path: packages/adder_ffi
在lib/main.dart
中改变_incrementCounter
方法的逻辑,使用我们的rust逻辑
import 'package:adder/adder.dart';
// in the `MyHomePage` add
final adder = Adder();
// and latter in `_MyHomePageState` replace
...
void _incrementCounter() {
setState(() {
_counter = widget.adder.add(_counter, 1);
});
}
...
并在安卓模拟器或iOS模拟器上启动Flutter应用程序并测试它 🔥。
吁 …
但我们发现这样做是非常无聊的,特别是当涉及到使用其他构建系统,如Xcode和Android NDK工具链,并将所有东西连接在一起的时候🤦♂️。这就是为什么我们试图把一切都自动化,但我们需要一些易于使用、跨平台和CI友好的东西。
Cargo-make来拯救🚀
cargo-make是一个用Rust开发的跨平台任务运行器和构建工具,它确实是一个令人惊奇的工具,它可以帮助你用一组简单的任务来编写你的工作流程,而且它还有很多其他很酷的功能,比如它很容易在其中添加内联脚本和[更多](medium.com/@sagiegurar… of-5-introduction and-basics-b19ced7e7057) 。 你可以在sunshine-flutter看到我们如何使用它。
就这样,我希望这有助于理解Dart FFI和Rust是如何一起工作的。
接下来,如何处理异步Rust和Dart FFI。 我将把这个问题留到下一篇博文中,很快就会发表 :)
现在,你可以看到我开始在scrap
包上进行黑客攻击,这个包是为了演示我们如何将异步Rust与Dart整合在一起。
其他有趣的Rust+移动FFI开发
- dart.dev/guides/libr…
- flutter.dev/docs/develo…
- github.com/dart-lang/s…
- mozilla.github.io/firefox-bro…
- mozilla.github.io/firefox-bro…
今天的文章[Flutter翻译]Dart与Rust:天作之合分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/15585.html