13 KiB
Rust 在移动端可以做什么
uniffi 的思路,和早期类似营销计算的逻辑用 ts 写好,端上 js 引擎加速,Android、iOS 再去使用是一个思路。
一、Uniffi 在移动端能做什么?
1. uniffi 是什么?
uniffi(全称 “Uniffi-rs”)是 Mozilla 开发的一个跨语言绑定生成工具,核心作用是让 Rust 代码能被其他编程语言(如 Swift、Kotlin、Python、JavaScript 等)无缝调用,通过自动生成类型安全的绑定层,大幅简化跨语言 FFI(Foreign Function Interface)开发的复杂度。
2. 为什么营销计算的逻辑适合用 ts 写?
纯函数,给定恒定的输入,输出不变。这非常适合 ts、rust 去实现。所以可以说,纯函数、纯逻辑适合用 Rust 去开发。区别在于即使采用类似 Wasm、JS 引擎预热、预加载等技术手段,Rust 天然比 JS 效率高。
3. ffi 能做什么?
早期 Flutter 和 Native 交互走 method channel 效率低,所以腾讯的同学开发了 Dart Native 方案,就是基于 ffi 的思路。
所以可以回答 Uniffi 能做什么的问题了:
uniffi 的核心是 “让 Rust 成为跨语言共享逻辑的‘通用语言’”,尤其在移动端,它解决了 iOS 和 Android 逻辑重复开发的问题,同时借助 Rust 的安全和性能优势,提升核心模块的可靠性。它更适合 “业务逻辑层” 而非 “UI 层”(UI 仍需依赖各平台原生框架),是移动端跨平台开发的重要补充工具
uniffi 的核心价值是跨语言复用 Rust 代码,因此它适合开发 “需要在多平台 / 多语言间共享的核心逻辑”,尤其适合以下场景:
- 跨平台共享的业务逻辑当同一套逻辑需要在多个平台(如移动端 iOS/Android、桌面端、后端服务)实现时,用 Rust 编写一次核心逻辑,再通过 uniffi 生成各平台对应的绑定(如 Swift 绑定供 iOS 调用,Kotlin 绑定供 Android 调用、桌面端 Electron js 去调用、小程序 js 去调用),避免重复开发,保证逻辑一致性。
- 对安全性、性能要求高的模块 Rust 自带内存安全和零成本抽象特性,适合处理敏感逻辑(如加密解密、用户认证、支付流程)或性能敏感操作(如数据解析、复杂计算、实时处理)。uniffi 能让这些 Rust 模块被其他语言(如动态语言)安全调用,兼顾安全性与开发效率。
- 需要跨语言交互的中间层例如,在一个混合技术栈的项目中(如前端用 JavaScript、后端用 Python、移动端用 Kotlin/Swift),可以用 Rust 编写通用的数据处理或协议解析逻辑,再通过 uniffi 生成多语言绑定,作为各层之间的 “桥梁”。
- 替代手动 FFI 开发传统跨语言调用需要手动编写 FFI 绑定(如用 extern "C" 暴露 Rust 接口,再在其他语言中手动适配类型),容易出错且维护成本高。uniffi 可自动生成类型安全的绑定,大幅降低开发和维护成本。
二、移动端中 uniffi 可以做什么?
移动端开发的核心痛点之一是 “iOS(Swift/Objective-C)和 Android(Kotlin/Java)需要重复实现相同逻辑”,而 uniffi 恰好能通过 Rust 实现跨平台逻辑复用,具体应用场景包括:共享核心业务逻辑例如:用户登录流程、权限验证、数据校验规则、业务状态管理等。用 Rust 编写一次,通过 uniffi 生成 Swift 绑定(供 iOS)和 Kotlin 绑定(供 Android),两端直接调用,避免 “同一逻辑两套代码” 的冗余和不一致问题。
高性能数据处理移动端涉及的复杂数据处理(如 JSON/Protobuf 解析、大数据集合过滤 / 排序、二进制协议编解码),用 Rust 实现可获得比 Kotlin/Swift 更高的性能,uniffi 可让两端高效调用这些逻辑。
安全敏感操作如加密(AES、RSA)、解密、签名验证、敏感数据(密码、Token)存储逻辑等,Rust 的内存安全特性可减少传统 C/C++ 调用可能带来的内存漏洞风险,uniffi 则确保调用过程的类型安全。
跨平台工具类例如:日期时间处理、字符串工具、设备信息计算(如唯一标识生成)等通用工具,用 Rust 实现后,通过 uniffi 让 iOS 和 Android 共享,减少重复开发。
与现有跨平台框架配合即使项目使用 Flutter、React Native 等跨平台 UI 框架,也可通过 uniffi 将 Rust 逻辑作为 “原生能力扩展”:例如 Flutter 中通过 Platform Channel 调用 uniffi 生成的 Rust 绑定,处理 Flutter 难以高效实现的复杂计算。
三、Rust 中使用 Unifii 实现与 Swift 高效互操作性
UniFFI(Universal Foreign Function Interface)是一个工具集,旨在帮助开发者轻松生成适用于多个编程语言(如 Swift、Kotlin 和 Python)的外部函数接口 (FFI) 绑定。它允许你通过定义一个接口描述语言 (UDL) 文件,自动生成跨语言的绑定代码,从而简化 Rust 代码与其他语言之间的交互。
1. 必要工具
开始之前,你需要确保已经安装了以下工具:
- Rust 和 Cargo:Rust 是一种系统编程语言,强调安全性和性能。Cargo 是 Rust 的包管理器和构建系统。 验证安装:运行以下命令确保 Rust 和 Cargo 已正确安装。
rustc --version
cargo --version
- UniFFI CLI 工具:UniFFI 提供了一个命令行工具,用于生成绑定代码。安装 UniFFI:你可以通过 Cargo 安装 UniFFI。
cargo install uniffi_bindgen
验证安装:运行以下命令确保 UniFFI 已正确安装。
uniffi-bindgen --version
2. 项目设置
- 创建 Rust 项目
- 打开终端并运行以下命令创建一个新的 Rust 库项目:
cargo new my_rust_library --lib
cd my_rust_library
- 编辑Cargo.toml文件,添加 Uniffi 依赖项
[dependencies]
uniffi = "0.27.0"
serde = { version = "1.0", features = ["derive"] }
- 配置Cargo.toml文件中的lib部分,设置 crate 类型为 cdylib:
[lib]
crate-type = ["cdylib"]
- 创建名为
MySwiftApp的Swift 项目
3. Rust 库的创建
我们将创建一个简单的 Rust 库,并配置它以便与 Swift 互操作。我们将定义一个数据结构和一些基本的功能,使用 UniFFI 来生成绑定。
- 设置 Cargo.toml 首先,我们需要在 Cargo.toml 文件中配置项目依赖和库类型:
[package]
name = "my_rust_library"
version = "0.1.0"
edition = "2018"
[dependencies]
uniffi = "0.27.0" # 检查最新版本
serde = { version = "1.0", features = ["derive"] }
[lib]
crate-type = ["cdylib"]
- 编写 Rust 代码 在 src/lib.rs 文件中编写 Rust 代码。我们将定义一个简单的结构体 Greeting 和相关的方法。
// src/lib.rs
use serde::{Serialize, Deserialize};
use uniffi_macros::include_scaffolding;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Greeting {
pub message: String,
}
impl Greeting {
pub fn new(name: String) -> Greeting {
Greeting {
message: format!("Hello, {}!", name),
}
}
pub fn greet(&self) -> String {
self.message.clone()
}
}
include_scaffolding!("my_library");
- 编写 UDL 文件 在项目根目录下创建一个新的文件 src/my_library.udl,用于定义接口描述语言 (UDL)。
namespace my_library {
struct Greeting {
message: string;
}
Greeting {
static Greeting new(string name);
string greet();
}
}
这个 UDL 文件描述了 Greeting 结构体及其方法。
4. 生成 Uniffi 绑定
使用 UniFFI 工具生成 Swift 绑定文件。确保你在项目根目录下,然后运行以下命令:
uniffi-bindgen generate src/my_library.udl --language swift --out-dir gen/
该命令将生成必要的 Swift 文件,并保存在gen/目录下。
5. 构建 Rust 库
使用以下命令构建 Rust 库:
cargo build --release
生成的动态库文件将位于 target/release 目录下,文件名为 libmy_rust_library.dylib(在 macOS 上)。
通过上述步骤,我们创建了一个简单的 Rust 库,并配置了 Uniffi 以生成 Swift 绑定文件。在下一部分中,我们将把生成的 Swift 文件集成到 Swift 项目中,并编写代码调用 Rust 库。
6. 生成 UniFFI 绑定
在这一部分,我们将使用 UniFFI 工具生成 Swift 绑定代码。这将使得我们可以在 Swift 项目中调用 Rust 库的功能。
- 编写 UDL 文件 首先,我们需要编写一个 UniFFI 接口描述语言 (UDL) 文件。这个文件描述了我们希望暴露给 Swift 的数据结构和函数接口。 在项目根目录的 src 文件夹中创建一个名为 my_library.udl 的文件,并添加以下内容:
namespace my_library {
struct Greeting {
message: string;
}
Greeting {
static Greeting new(string name);
string greet();
}
}
这个 UDL 文件定义了一个名为 Greeting 的结构体及其两个方法:new 和 greet
- 生成 Swift 绑定 在终端中导航到项目根目录,并运行以下命令生成 Swift 绑定:
uniffi-bindgen generate src/my_library.udl --language swift --out-dir gen/
这个命令会根据 my_library.udl 文件生成 Swift 绑定代码,并将其放在 gen/ 目录下。生成的文件包括:
- my_library.swift:包含 Swift 代码,用于调用 Rust 库。
- my_libraryFFI.h:C 头文件,用于描述 Rust 和 Swift 之间的接口。
- my_libraryFFI.swift:内部使用的 Swift 文件,处理底层的 FFI 调用。
下是生成的 my_library.swift 文件的示例内容:
import Foundation
public struct Greeting {
public let message: String
public init(name: String) {
self = Greeting.new(name: name)
}
public func greet() -> String {
return greeting_greet(self)
}
}
my_libraryFFI.h 文件的示例内容:
#ifndef MY_LIBRARY_FFI_H
#define MY_LIBRARY_FFI_H
#include <stdint.h>
#include <stdbool.h>
typedef struct {
char* message;
} Greeting;
Greeting* greeting_new(const char* name);
const char* greeting_greet(const Greeting* self);
void greeting_free(Greeting* self);
#endif // MY_LIBRARY_FFI_H
- 构建 Rust 库 在继续之前,确保 Rust 库可以成功构建。运行以下命令:
cargo build --release
生成的动态库文件位于 target/release 目录下,文件名为 libmy_rust_library.dylib(在 macOS 上)。这个文件将被 Swift 项目使用。
通过以上步骤,你已经成功生成了用于 Swift 调用的 Rust 绑定文件。在下一部分中,我们将这些文件集成到 Swift 项目中,并编写代码调用 Rust 库。
集成到 Swift 项目
-
打开 Finder,导航到 Rust 项目中的
gen/目录,选择 my_library.swift、my_libraryFFI.h、my_libraryFFI.swift 文件。 拖动这些文件到 Xcode 项目导航器中的项目目录下。在弹出的对话框中,确保选中 "Copy items if needed" 选项,然后点击 "Finish"。 -
添加 Rust 动态库 为了让 Swift 项目能够找到并使用 Rust 动态库,需要将动态库文件添加到 Xcode 项目中:
- 在 Finder 中,导航到 Rust 项目的target/release目录。
- 找到生成的动态库文件libmy_rust_library.dylib(在 macOS 上)。
- 拖动这个文件到 Xcode 项目导航器中的项目目录下。在弹出的对话框中,确保选中 "Copy items if needed" 选项,然后点击 "Finish"。
- 配置 Xcode 项目 为了让 Xcode 项目能够正确地链接和加载 Rust 动态库,需要进行一些配置:
- 选择项目文件,在左侧的 "TARGETS" 列表中选择你的应用目标。
- 选择 "Build Phases" 选项卡。
- 展开 "Link Binary With Libraries" 部分,点击 "+" 按钮,添加刚才拖动到项目中的 libmy_rust_library.dylib 文件。
- 配置动态库加载路径 选择项目文件,在左侧的 "TARGETS" 列表中选择你的应用目标。
- 选择 "Build Settings" 选项卡。
- 搜索 "Runpath Search Paths"。
- 添加以下路径到 "Runpath Search Paths" 配置项中:
@executable_path/../Frameworks
- 编写 Swift 调用代码 在 ViewController.swift 文件中,编写代码调用 Rust 库:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 调用 Rust 库
let greeting = Greeting(name: "World")
print(greeting.greet())
}
}
通过这些步骤,已经掌握了如何在 Swift 项目中高效地使用 Rust 库,并了解了相关的高级技术。这种跨语言的集成不仅能利用 Rust 的性能优势,还能享受 Swift 的便捷开发体验。