matrix-rust-sdk — Matrix 客户端的"共享发动机"
是什么
matrix-rust-sdk 是 Matrix 协议官方的 Rust 客户端 SDK。Matrix 是一个开源的去中心化聊天协议(类似 Slack/WhatsApp,但任何人都能跑自己的服务器,服务器之间互通)。这个 SDK 提供给”想做 Matrix 客户端”的人。
日常类比:像汽车厂的共享发动机。Element 公司原来给 iOS、Android、Web 三个客户端各做了一个发动机,三套代码维护不动;现在用 Rust 写一份发动机,再给 Swift / Kotlin / JS 装上不同的方向盘和外壳——都用同一颗心。
你用它写一个最小客户端(伪代码):
use matrix_sdk::Client;
let client = Client::builder().homeserver_url("https://matrix.org").build().await?;client.matrix_auth().login_username("alice", "pw").send().await?;client.sync(Default::default()).await?; // 后台一直拉新消息它是 Element X(Element 公司新一代 iOS/Android 客户端)的底层心脏,也是社区客户端 Fractal(GTK)、iamb(终端)的依赖。
为什么重要
不理解这个项目,下面这些事都看不清:
- 为什么 Element X 启动比老 Element 快 6 倍——因为老版每端各自实现状态机,新版共用 Rust 编译的核心
- 为什么”加密聊天”在每个客户端都对——Olm/Megolm 加密只在 Rust 层实现一次,三端共享,不会出现”iOS 解密对、Android 解密错”
- 为什么 2020 年后做 Matrix 客户端的人几乎都不再用 matrix-js-sdk——多语言 binding 让 Rust 这份成了上游事实标准
- Rust 在”跨平台共享逻辑”这条路上的代表作之一,FFI 绑定的工程经验值得抄
核心要点
SDK 把客户端逻辑切成 四层 crate:
-
matrix-sdk-base:协议状态机。读懂服务器返回的 JSON,维护”我加入了哪些房间、每个房间最新消息是什么”。没有网络——纯输入纯输出。
-
matrix-sdk-crypto:加密状态机。Olm(双人对话密钥交换)+ Megolm(群聊密钥分发)。也没有网络,输入是别人的密钥包,输出是要发出去的加密消息。
-
matrix-sdk:把上面两个加上 HTTP 客户端、同步循环、事件订阅。这是大多数应用应该依赖的层。
-
matrix-sdk-ui:再往上一层,提供 RoomList(房间列表抽象)、Timeline(时间线抽象)。Element X 就吃这层,UI 只负责画。
外面再裹一层 FFI binding:UniFFI 把 Rust API 暴露成 Swift/Kotlin,wasm-bindgen 暴露成 JS。一份核心,多端调用。
关键设计:核心层无 I/O。base 和 crypto 都是”纯函数 + 状态”,方便测试,也方便机器人这种”我自己管网络”的场景独立用 crypto。
实践案例
案例 1:Element X iOS——把 RoomList 直接当数据源
let roomList = try await client.roomListService().allRooms()// SwiftUI 里把 roomList 当 @ObservedObject,房间一变 UI 自动刷iOS 工程师不用写 sync 循环、不用解析 JSON、不用管加密。matrix-sdk-ui 的 RoomList 已经是”按时间倒序、按未读状态分组”的 Swift 可用对象。
案例 2:Rust 终端客户端 iamb——只用中层
iamb 是 Vim 风格的 Matrix 终端客户端,用 matrix-sdk(不用 ui 层)。它自己用 ratatui 画界面,订阅 SDK 的 sync 事件流,按自己节奏渲染。
let mut sync_stream = client.sync_stream(...).await;while let Some(response) = sync_stream.next().await { // 自己决定怎么把 response 翻译到 TUI}案例 3:纯加密机器人——只用 matrix-sdk-crypto
use matrix_sdk_crypto::OlmMachine;let machine = OlmMachine::new(user_id, device_id).await;// 外部网络层把别人发来的加密事件喂进来machine.receive_sync_changes(...).await?;let plaintext = machine.decrypt_room_event(&event, &room_id).await?;这种姿势没有 HTTP 客户端、没有 sync 循环。适合”我已经有 IM 协议栈,只想接 Matrix 的 E2EE 加密能力”。
踩过的坑
-
公共 API 只有三个 crate:
matrix-sdk/matrix-sdk-ui/matrix-sdk-crypto。其它(matrix-sdk-base、matrix-sdk-common、matrix-sdk-store-encryption等)随时改,不要直接写进 Cargo.toml 否则升级 SDK 全炸。 -
UniFFI 不直传 async:Rust 这边是
async fn,到 Swift/Kotlin 经 UniFFI 转成回调或同步阻塞。Element X 团队又自己包了一层 Swiftawait把回调转回 async,FFI 边界看着干净背后绕了一圈。 -
sliding sync 服务端尚不稳定:sliding sync(MSC3575)能让”打开 app 立刻看到第一屏”——只先拉可视范围的房间。但需要专门的 sliding sync 代理(Synapse 的实验功能或独立 proxy),不是所有 homeserver 都支持,老
/sync仍要保留兼容路径。 -
加密 store 必须持久化:crypto store 存所有会话密钥,掉了等于历史消息全部解不开。SDK 默认用 SQLite,但升级 schema 时要做迁移;加密 store 也不能简单
cp复制(同设备 ID 多实例会让 Megolm 出乱)。 -
跨设备 verification 是流程不是函数。要做”扫二维码 / SAS 短串验证”得自己驱动 SDK 的 verification 状态机,不是一次
verify()调用就结束。 -
Tokio 运行时绑死:SDK 内部用
tokio跑异步,集成async-std或单线程运行时不友好。FFI 层 binding 也是基于 Tokio 多线程模型设计。
适用 vs 不适用场景
适用:
- 做 Matrix 客户端(iOS/Android/Web/Desktop/TUI 都行)
- 做 Matrix 机器人/桥接器,需要完整客户端能力(含 E2EE)
- 想抄”Rust + UniFFI + wasm-bindgen 共享核心”的工程模式
不适用:
- 做 Matrix 服务端——服务端用 Synapse(Python)或 Dendrite(Go),matrix-rust-sdk 是客户端方向
- 做”只发明文消息的极简机器人”——直接 HTTP 调 Client-Server API 更简单
- 做完全自定义协议——SDK 强绑定 Matrix 协议本身
历史小故事(可跳过)
- 2014 年:Matrix 协议诞生于 Element 公司前身(Amdocs Unified Communications)。早期客户端只有 JS(matrix-js-sdk)。
- 2016-2018 年:Element 给 iOS(Swift)/Android(Kotlin)/JS 各做一份 SDK,三份代码各自实现状态机,bug 不一致。
- 2020 年:Element 启动”Rust 化”,把客户端核心移到 matrix-rust-sdk,先给 Element Desktop 用。
- 2022-2023 年:Element X 发布——iOS 和 Android 改成”薄壳套 Rust 核心”,启动速度大幅提升,加密 bug 在三端一次修完。
- 2024-2026 年:社区 Fractal/iamb 切到 Rust SDK。matrix-js-sdk 仍在维护但优先级下降。
之后做 Matrix 客户端的事实模板就是”Rust 核心 + 平台层壳”。
学到什么
- 共享核心 + 多语言壳是 Rust 在客户端的杀手用法——一份逻辑给三个端用,省 60-70% 维护成本
- 协议状态机和 I/O 解耦——base/crypto 都是纯函数,让测试和裁剪都方便
- UniFFI 是 Rust → 移动端的桥——比手写 JNI/Swift bridge 省一个数量级的胶水代码
- 公共 API 范围要划清楚——SDK 故意只暴露三个 crate,避免社区”误用内部细节”导致升级灾难
延伸阅读
- 仓库:matrix-org/matrix-rust-sdk(README 含 crate 关系图)
- Element X iOS 源码:element-hq/element-x-ios(看怎么吃 matrix-sdk-ui)
- Matrix 协议规范:spec.matrix.org(Client-Server API + Olm/Megolm)
- Sliding sync MSC:MSC3575
- UniFFI 入门:mozilla/uniffi-rs
- synapse —— Matrix 主流服务端实现(Python)
- dendrite —— Matrix 第二个服务端实现(Go),跟 matrix-rust-sdk 是协议对端
关联
- synapse —— Matrix 服务端,matrix-rust-sdk 客户端连的就是它
- dendrite —— 另一个 Matrix 服务端,协议另一头
- diffie-hellman —— Olm/Megolm 加密底层用的密钥交换数学
- actix-web —— Rust web 框架,sliding sync proxy 也用类似栈
- axum —— Rust web 框架,机器人/桥接器常用来做 webhook 接入
一句话总结
一份 Rust 核心,三端共享——这是 matrix-rust-sdk 留给整个 Matrix 生态最直接的工程礼物。
反向链接
- actix-web —— Actix Web — Rust 上长期占据 TechEmpower 榜首的 web 框架
- axum —— axum — 用 Rust 类型系统当『路由参数表』的 Web 框架
- dendrite —— Dendrite — Go 写的第二代 Matrix homeserver,组件可拆可合
- diffie-hellman —— Diffie-Hellman 密钥交换
- element-android —— Element Android — Matrix 协议官方 Android 客户端(Kotlin + Realm)
- element-web —— Element Web — Matrix 协议旗舰 web 客户端(React + matrix-js-sdk)
- embedded-hal —— embedded-hal — 让同一份驱动代码跑在任意芯片上
- flutter-rust-bridge —— flutter-rust-bridge — Dart 调 Rust 像调本地函数
- matrix-js-sdk —— matrix-js-sdk — Matrix Web/Node 端的”老大哥”客户端 SDK
- mumble —— Mumble — 游戏圈用了 20 年的低延迟开源语音
- signal-android —— Signal Android — 让 Android 上的每条消息都只有两端能看见
- signal-ios —— Signal iOS — 让 iPhone 上的每条消息都只有两端能看见
- signal-server —— Signal-Server — 服务端看不到任何明文的即时通信后端
- synapse —— Synapse — Matrix 协议的参考 homeserver,让聊天像电邮一样能跨服务器互通
- tauri —— Tauri — Rust 写的 Electron 替代,用系统 webview 打包桌面/移动端应用
- vodozemac —— vodozemac — Matrix 端到端加密的 Rust 内核