

Rust + Flutter 高性能的跨端尝试
source link: https://zhuanlan.zhihu.com/p/108308284
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Rust + Flutter 高性能的跨端尝试
稍作配置,同一份代码横跨 Android & IOS,相比于 React Native 方案更加高性能。除此之外,得益于 Rust 跨平台加持,Rust 部分的代码可在种种场合复用。
这篇文章旨在记录作者尝试结合 Rust 和 Flutter 的过程,且仅为初步尝试。不会涉及诸如:
如何搭建一个 Flutter 开发环境,以及 Dart 语言怎么用
如何搭建一个 Rust 开发环境,以及 Rust 语言怎么学
开头给自己博客打波广告
Environment
- Flutter: Android, IOS 工具配置妥当
- Rust: Stable 就好
Rust Part
Prepare cross-platform toolchains & deps
# Download targets for IOS ( 64 bit targets (real device & simulator) )
rustup target add aarch64-apple-ios x86_64-apple-ios
# Install cargo-lipo to generate the iOS universal library
cargo install cargo-lipo
Android
这里有一些行之有效的辅助脚本用于更加快捷配置交叉编译工具。
- 获取 Android NDK
sh sdkmanager --verbose ndk-bundle
如果已经准备好了 Android NDK ,则设置环境变量$ANDROID_NDK_HOME
```sh
example:
export ANDROID_NDK_HOME=/Users/yinsiwei/Downloads/android-ndk-r20b2. Create the standalone NDK
sh
$(pwd) == ~/Downloads
git clone https://github.com/kennytm/rust-ios-android.git cd rust-ios-android ./create-ndk-standalone.sh3. 在 Cargo default config VS 配置 Android 交叉编译工具
sh cat cargo-config.toml >> ~/.cargo/config执行上述命令后会在 Cargo 默认配置中,增加有关 Android 跨平台目标 (targets, `aarch64-linux-android`, `armv7-linux-androideabi`, `i686-linux-android`) 的工具信息,指向刚刚创建的 `standalone NDK`。
ini [target.aarch64-linux-android] ar = ... linker = ..
[target.armv7-linux-androideabi] ...
[target.i686-linux-android] ..4. 下载 Rust 支持 Android 交叉编译的依赖
sh rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android ```
Start a simple rust library
- 创建一个 Rust 项目
sh cargo init my-app-base --lib
- 编辑
Cargo.toml
修改crate-type
ini [lib] name = "my_app_base" crate-type = ["staticlib", "cdylib"]
Rust 构建出来的二进制库,在 IOS 中是静态链接进最终的程序之中,需要对构建staticlib
的支持;在 Android 是通过动态链接在运行时装在进程序运行空间的,需要对构建cdylib
的支持。 - 写一些符合 C ABI 的函数
src/lib.rs
```rust use std::os::raw::c_char; use std::ffi::CString;
[no_mangle]
pub unsafe extern fn hello() -> *const c_char { let s = CString::new("world").unwrap(); s.into_raw() } ```
在上述代码中,每次当外部调用hello
函数时,会在晋城堆空间中创建一个字符串 (CString
),并将所有权 ( 释放该字符串所占堆空间的权利 ) 移交给调用者。
Build libraries
# IOS
cargo lipo --release
# Android
cargo build --target aarch64-linux-android --release
cargo build --target armv7-linux-androideabi --release
cargo build --target i686-linux-android --release
然后在 target
目录下会得到以下有用的物料。
target
├── aarch64-linux-android
│ └── release
│ ├── libmy_app_base.a
│ └── libmy_app_base.so
├── armv7-linux-androideabi
│ └── release
│ ├── libmy_app_base.a
│ └── libmy_app_base.so
├── i686-linux-android
│ └── release
│ ├── libmy_app_base.a
│ └── libmy_app_base.so
├── universal
│ └── release
│ └── libmy_app_base.a
至此, Rust
部分就告于段落了。
Flutter Part
Copy build artifacts to flutter project
from: target/universal/release/libmy_app_base.a
to: ios/
from: target/aarch64-linux-android/release/libmy_app_base.so
to: android/app/src/main/jniLibs/arm64-v8a/
from: target/armv7-linux-androideabi/release/libmy_app_base.so
to: android/app/src/main/jniLibs/armeabi-v7a/
from: target/i686-linux-android/release/libmy_app_base.so
to: android/app/src/main/jniLibs/x86/
Call FFI function in Dart
- 添加依赖
pubspec.yaml
->dev_dependencies:
+=ffi: ^0.1.3
- 添加代码
(直接在生成的项目上修改,暂不考虑代码设计问题,就简简单单的先把项目跑起来 ) ```dart import 'dart:ffi'; import 'package:ffi/ffi.dart';
// ... final dylib = Platform.isAndroid ? DynamicLibrary.open('libmy_app_base.so') :DynamicLibrary.process(); var hello = dylib.lookupFunction Function(),Pointer Function()>('hello');
// ... hello(); // -> world ```
Build Android Project
flutter run # 如果连接着 Android 设备就直接运行了起来
Build IOS Project
( 复杂了许多 )
- 跟随
Flutter
官方文档,配置XCode
项目。 - 在
Build Phases
中Link Binary With Libraries
添加libmy_app_base.a
文件 (按照图上箭头点...)
- 在
Build Settings
中Other Linker Flags
中添加force_load
的参数。
这是由于在 Dart 中通过动态的方式调用了该库的相关函数,但在编译期间静态分析的时候,这些都是未曾被调用过的无用函数,就被剪裁掉了。要通过 force_load
方式解决这个问题。
Result

Troubleshooting
XCode & IOS
Error getting attached iOS device: ideviceinfo could not find device
sudo xattr -d com.apple.quarantine ~/flutter/bin/cache/artifacts/libimobiledevice/ideviceinfo
将后面的路径替换成你的
dyld: Library not loaded
dyld: Library not loaded: /b/s/w/ir/k/homebrew/Cellar/libimobiledevice-flutter/HEAD-398c120_3/lib/libimobiledevice.6.dylib
Referenced from: /Users/hey/flutter/bin/cache/artifacts/libimobiledevice/idevice_id
Reason: image not found
删除&重新下载
rm -rf /Users/hey/flutter/bin/cache && flutter doctor -v
真机无法启动 Flutter 程序
参见 https://github.com/flutter/flutter/issues/49504#issuecomment-581554697 不要升级到 IOS 13.3.1 系统
What's next
- 如何高效的实现 Rust & Dart 部分的通信
我们知道 Flutter 和广大 GUI 库类似,属于单线程模型结合事件系统,因此在主线程中使用 FFI 调用 Rust 部分的代码不能阻塞线程。Dart 语言提供 async/await 语法特性用于在 Flutter 中处理网络请求等阻塞任务。而 Rust 也在最近版本中提供了 async/await 语法支持,如何优雅的把两部分结合起来,这是一个问题。 - 对 MacOS Windows Linux 桌面端的支持
Flutter 已经有了对桌面端的实验性支持,可以研究下如何结合在一起,实现跨 6 个端共享代码。
References
介绍了如何构建出 Android, IOS 库,并提供了例子 - https://github.com/TimNN/cargo-lipo
用于构建 universal library - https://github.com/hanabi1224/flutter_native_extensions
Recommend
-
47
当下的前端同学对 React 与 Vue 的组件化开发想必不会陌生,RN 与 Weex 的跨界也常为我们所津津乐道。UI 框架在实现这样的跨端渲染时需要做哪些工作,其技术方案能否借鉴乃至应用到我们自己的项目中呢?这就是本文所希望分享的主题。 概念简介 什么是
-
45
-
71
2019-01-21 前端快爆 微软 Edge 开发者意图为 Chrome 实现 HTML Modules,该规范用来替代之前的 HTML Imports。其优点是基于 ES Modules,可以避免全局对象污染、脚本解析阻塞等问题。? 点评
-
52
文章较长,信息量很大,请耐心阅读,必然有收获。下面正文开始~ 背景 解决方案 原理 久经考验 生产应用举例 易用性好 多态协议 学习成本低 渐进式接入 业内对比 后期规划 理想主义 历经近20个月打磨,滴滴跨端方案chameleon终于开源了github.
-
57
上周,Taro 团队发布了一篇《小程序多端框架全面测评》,让开发者对业界主流的跨端框架,有了初步认识。感谢 Taro 团队的付出。 不过横评这件事,要想做完善,其实非常花费时间。不是只看文档就行,它需要: 真实的动手写多个平台的测试demo,比较各个平台的功
-
60
出品 | 滴滴技术作者 | 张楠 Conan前言:历经近20个月打磨,滴滴跨端方案chameleon终于开源了https://github.com/didi/chameleon, 真正专注于一套代码运行多端一、背景微信月活10亿月活(超过网民数量,用户多个账号
-
80
滴滴在 GitHub 上开源的跨端解决方案 Chameleon(简写 CML)正式发布 1.0 版本,中文名卡梅龙;中文意思变色龙,意味着就像变色龙一样能适应不同环境的企业级跨端整体解决方案,具有易用、轻量、面向未来等特点。下文将详细介绍 Chameleon...
-
41
12月20日,腾讯开源跨端框架 Hippy。 在腾讯内部,Hippy 已运行3年之久,跨 BG 共有 18 款线上业务正在使用 Hippy,日均 PV 过亿,且已建立一套完整生态。相较于其他跨端框架,Hippy 对前端开发者更友好:紧贴 W3C 标准,遵从网页
-
27
1 前言 近几年随着移动互联网的发展,尤其各个端平台推出了小程序入口,比如微信、支付宝、头条等,不同端平台之间的语法规范不统一,代码组织结构复杂,开发者早期应对同样的业务需求,需要在各端平台上各自维护一套代码,开...
-
5
Lynx:来自字节跳动的高性能跨端框架2021-12-09 18:24 InfoQ 编辑|邓艳琴嘉宾|师绍琨在跨端技术高速演进的背景下,字节跳动自...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK