UniFFI 跨平台开发Rust 与 Android (Kotlin) 集成

UniFFI 跨平台开发:Rust 与 Android (Kotlin) 集成实战教程

本文将指导你如何使用 UniFFI 自动化生成 Rust 与 Kotlin 的胶水层代码,省去繁琐的手写 JNI 过程。

第一阶段 环境准备

1.1 编译的环境

复制代码
ubuntu 操作系统(Linux操作系统)
	1、开发工具 RustRover
	2、安装NDK环境。
		     mkdir -p ~/lib/android-ndk && cd ~/lib/android-ndk
             wget https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
             unzip android-ndk-r26b-linux.zip

windows 操作系统
	1、开发工具 AndroidStudio

1.2 结构图

效果图

1.3 生活案例

可以用 "一家跨国公司(Android)聘请一位只会讲家乡话的外国专家(Rust)来干活,并安排一位全能翻译(UniFFI)" 的故事来完美解释

第一阶段:外国专家入职(Rust 项目区)

  • 故事背景: 你的公司(Android 应用)需要解决一个超级复杂的数学难题(比如高效的图像处理)。你听说有个叫 Rust 的外国专家特别厉害,不仅干活快(高性能),还从来不犯错(内存安全)。
  • src/lib.rs (业务逻辑) = 专家的核心技能: 专家在他的办公室(Rust 环境)里,用他的家乡话(Rust 语言)写好了解决难题的数学公式(代码)。
  • UniFFI setup_scaffolding! (自动生成脚手架) = 专家安装办公桌: 专家为了能接收工作和传递结果,需要在办公室里安装一张特制的办公桌。这个办公桌是全自动的,能把东西整齐地摆放好,不需要专家自己操心。
  • CARGO 编译 (cargo-ndk build) = 专家打包行李和工具: 专家要把他的技能和办公桌打包,准备去你的公司。因为你的公司在不同的地方(真机 arm64-v8a 或模拟器 x86_64),专家必须把行李打包成能在不同地方打开的样式(.so 动态库)。

第二阶段:全能翻译官的准备(中间产物与生成工具)

  • 故事背景: 专家虽然厉害,但他只说家乡话(Rust),你的员工(Kotlin)一句也听不懂。你需要一个中间人。
  • uniffi-bindgen.rs (生成器工具) = 招聘全能翻译官: 你雇佣了一个叫 UniFFI 的翻译官。
  • KOTLIN 胶水代码生成 = 翻译官编写工作手册: 翻译官 UniFFI 非常聪明。他先去专家的办公室看了一眼,搞清楚了专家能干什么活。然后,翻译官用你的员工能听懂的语言(Kotlin),写了一本详细的**《工作调用手册》**(asrust.kt)。这本手册告诉你的员工,如果想找专家干活,该怎么说、传递什么参数。
  • .so 动态库 + asrust.kt = 专家的行李 + 工作手册: 这时候,专家的行李(能在 Android 上运行的核心逻辑)和翻译官写的《工作调用手册》(asrust.kt)都准备好了。

第三阶段:入驻公司(Android 集成区)

  • 故事背景: 你把专家和翻译官都请进了公司。
  • asrust.kt 入驻 src/main/java/ = 手册放到员工办公桌: 你把《工作调用手册》发给了负责具体业务的员工(MainActivity.kt)。
  • .so 库入驻 src/main/jniLibs/ = 行李搬进公司仓库: 你把专家的行李放进了公司的专属仓库(jniLibs)。公司会根据当前的地址(真机还是模拟器),自动打开对应仓库里的行李。
  • build.gradle (依赖配置) = 购买翻译设备(JNA): 翻译官在工作时,需要一套专业的无线对讲机和耳机(JNA 库)。你在公司的采购清单(build.gradle)里加上了这套设备。

第四阶段:正式开工(运行时调用流)

  • 故事背景: 准备就绪,客户提出了请求。
  • 1. 调用 Kotlin 函数 (MainActivity.kt -> asrust.kt) = 员工按手册下单: 客户让你的员工计算一个题。员工翻开桌上的《工作调用手册》(asrust.kt),拨通了手册上的内部电话。员工用普通的 Kotlin 语言说:"我要计算这个题,参数是 A 和 B。"
  • 2. JNA 动态加载 (asrust.kt -> JNA -> libasrust.so) = 翻译官拿起设备打电话: 翻译官(asrust.kt)接到电话后,立刻戴上对讲机(JNA 运行时),按下按钮,对讲机连接到了仓库里的专家行李(libasrust.so)。
  • 3. 执行 Rust 逻辑 (libasrust.so -> Rust 方法) = 对讲机那头专家干活: 在对讲机的另一头,专家的行李自动激活了核心逻辑。专家接收到了翻译官传来的参数,飞快地用他的家乡话(Rust)把题算完了。
  • 4. 返回结果 (专家 -> 翻译官 -> 员工) = 专家回复,翻译官传达: 专家算完后,对着对讲机说:"结果是 C。"翻译官听完后,摘下耳机,用回 Kotlin 语言对你的员工说:"专家算出来了,结果是 C。"

你的员工(MainActivity.kt)拿到了结果 C,开心地展示给了客户。而在这个过程中,你的员工从头到尾都不需要知道专家住在哪个仓库(JNI 细节),也不需要学会一句 Rust 方言,一切都由翻译官(UniFFI)和翻译设备(JNA)在背后默默处理好了。

第二阶段:Rust 项目配置

2.1 Cargo.toml 配置

Cargo.toml 中,关键点是定义 crate-type 为动态库,并引入 UniFFI 依赖。

Ini, TOML

toml 复制代码
[package]
name = "asrust"
version = "0.1.0"
edition = "2021"

[lib]
name = "asrust"
crate-type = ["cdylib", "staticlib"] # 必须包含 cdylib 以生成 .so 库

[dependencies]
uniffi = { version = "0.31.1", features = ["cli"] }

[build-dependencies]
uniffi = { version = "0.31.1", features = ["build"] }

# 优化 Android 编译链接参数,解决某些设备上的符号链接问题
[target.aarch64-linux-android]
rustflags = ["-C", "link-arg=-lgcc", "-C", "link-arg=-static-libgcc"]

[target.x86_64-linux-android]
rustflags = ["-C", "link-arg=-lgcc", "-C", "link-arg=-static-libgcc"]

2.2 编写业务逻辑 (src/lib.rs)

使用 setup_scaffolding! 宏是 UniFFI 的核心,它会自动处理底层的 FFI 转换。

rust 复制代码
// 自动生成底层的脚手架代码
uniffi::setup_scaffolding!();

#[uniffi::export]
pub fn hello_world(a: i32, b: i32) -> i32 {
    a + b
}

2.3 定义生成器入口 (src/bin/uniffi-bindgen.rs)

为了方便在项目内部生成 Kotlin 代码,我们需要这个二进制入口。

rust 复制代码
fn main() {
    uniffi::uniffi_bindgen_main()
}

第三阶段:编译与代码生成

3.1 环境准备 (NDK)

确保你的环境变量中包含 ANDROID_NDK_HOME

shell 复制代码
# 下载并解压 NDK (以 r26b 为例)
mkdir -p ~/lib/android-ndk && cd ~/lib/android-ndk
wget https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
unzip android-ndk-r26b-linux.zip

3.2 编译 Rust 库

使用 cargo-ndk 针对指定架构进行编译。

shell 复制代码
# 安装工具
cargo install cargo-ndk

# 编译 arm64 架构(真机常用)或 x86_64(模拟器)
cargo ndk -t arm64-v8a -t x86_64 build --release

3.3 生成 Kotlin 胶水层

运行生成的二进制工具,根据编译出的 .so 文件提取接口并生成 Kotlin 代码。

注意这里的参数

1、输入路径 --library

2、输出路径 --out-dir

两部分内容:

shell 复制代码
cargo run --bin uniffi-bindgen generate \
    --library ./target/x86_64-linux-android/release/libasrust.so \
    --language kotlin \
    --out-dir ./src

第四阶段:Android 集成

4.1 引入依赖与配置

UniFFI 生成的代码依赖于 JNA (Java Native Access)。

build.gradle (Module level):

groovy 复制代码
dependencies {
    // UniFFI 运行时必须依赖 JNA
    implementation("net.java.dev.jna:jna:5.18.1@aar")
}

4.2 放置二进制库

将生成的 .so 文件放入对应的目录。注意目录名必须与 Android 架构对应。

Plaintext

复制代码
app/src/main/jniLibs/
├── arm64-v8a/
│   └── libasrust.so
└── x86_64/
    └── libasrust.so

4.3 导入生成的代码

将生成的 asrust.kt 文件拷贝到你的项目包名目录下(例如 com.example.app)。

注意: 你不需要手动修改 asrust.kt 里的代码。UniFFI 会自动为你封装好 FfiConverter 等复杂逻辑。

4.4 最终调用

在 Kotlin 中,你不再需要编写 external 方法,直接像调用普通函数一样使用:

Kotlin 复制代码
import com.example.app.helloWorld

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 直接调用,UniFFI 在后台处理了所有复杂的 JNI 转换
        val sum = helloWorld(10, 20)
        println("Result from Rust: $sum")
    }
}

相关推荐
DogDaoDao12 小时前
Android 播放器开发:从零构建全功能视频播放器
android·ffmpeg·音视频·播放器·mediacodec·编解码
Kapaseker12 小时前
Kotlin 的 SAM 到底解决了什么?
kotlin
真鬼12312 小时前
【Unity安卓】Unity 嵌入 Android Studio 完整流程
android·unity·android studio
星间都市山脉12 小时前
Windows 环境 Android 系统 APK 签名操作文档
android·windows
樱桃花下的小猫12 小时前
Rust 服务器存档管理 & 地图配置指南
服务器·rust·云鸢互联·零门槛一键开服·腐蚀rust服务器·腐蚀rust稳定低延迟联机·腐蚀rust服务器一键开服
shuaiqinke12 小时前
【分享】OrbitV工具箱| 手表手环全能适配 |表盘应用一键装
android·智能手机
子非吾喵13 小时前
HBuilder X本地打包的资源放到Android Studio本地打包的记录
android·ide·android studio
红尘散仙1 天前
一个 `#[uniffi::export]`,把 Rust 接进 React Native
前端·后端·rust
红尘散仙1 天前
一行 `#[specta::specta]`,让 Tauri IPC 有类型
前端·后端·rust