zhixi-document-runtime/docs/app-rust-bridge.md
wangdl dd360c88e2 fix: RagChatModule 导入 AiModule,修复 AiGatewayService 未注入
AiGatewayService 使用了 @Optional() 导致不报错但始终为 null,
sendMessage 永远走 fallbackReply。现在导入 AiModule 正确注入。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 13:38:57 +08:00

4.8 KiB
Raw Permalink Blame History

App ↔ Rust 调用协议

概述

本文档定义宿主 AppiOS/Android与 Rust Core 之间的全部调用边界。

核心原则:

Rust Core 是纯计算层。
不做网络请求、不保存 Token、不访问后端 API。
文件由 App 下载到本地后,把路径交给 Rust。
阅读事件由 Rust 生成App 负责上传。

调用方向

App ──调用──→ Rust Core
App ←──返回── Rust Core
App ──上传──→ Backend API

Rust 暴露给 App 的函数

所有函数通过 #[uniffi::export] proc-macro 标注,经 UDL bindgen 生成 Swift/Kotlin 绑定。

1. 文件类型识别

fn detect_material_type(file_path: String) -> Result<MaterialType, DocumentError>

输出MaterialType 枚举值 用途App 据此决定使用哪种 PreviewMode

2. 图片 Metadata

fn read_image_meta(file_path: String) -> Result<ImageMeta, DocumentError>

输出width, height, format, file_size

3. 文本统计

fn read_text_stats(file_path: String) -> Result<TextStats, DocumentError>

输出line_count, word_count

4. 解析 Markdown

fn parse_markdown(content: String) -> Result<Vec<DocumentBlock>, DocumentError>

输出DocumentBlock 列表8 种 block 类型)

5. 解析纯文本

fn parse_text(content: String) -> Result<Vec<DocumentBlock>, DocumentError>

输出:段落 block 列表

6. 搜索 Markdown Blocks

fn search_markdown_blocks(blocks: Vec<DocumentBlock>, query: String) -> Vec<SearchResult>

输出SearchResult 列表block_id, snippet, match range

7. 搜索纯文本

fn search_text_content(content: String, query: String) -> Vec<SearchResult>

输出SearchResult 列表line_number, snippet, match range

8. 创建笔记锚点

fn create_note_anchor(material_id: String, position: Option<ReadingPosition>) -> NoteAnchor

输出NoteAnchor从 ReadingPosition 自动映射)

9. 推送阅读事件

fn push_reading_event(event: ReadingEvent)

用途:将事件推入全局缓冲区

10. 更新阅读位置

fn update_reading_position(material_id: String, position: ReadingPosition)

用途:生成 PositionChanged 事件并推入缓冲区

11. 导出待上报事件

fn export_pending_events() -> Vec<ReadingEvent>

输出:所有未上报事件(不清空缓冲区)

12. 清空已上报事件

fn clear_exported_events(count: u32)

用途:确认前 count 条已成功上传,从缓冲区移除


Rust 不提供的函数(由 App 负责)

以下函数不存在于 Rust Core,完全由宿主 App 实现:

App 职责 说明
download_file(url) COS 下载 → 本地沙盒
upload_reading_events(events) POST 到 /reading/events
save_note_to_backend(note) POST 到 /notes
call_ai_chat(prompt) 调 AI API
share_file(material_id) 系统分享面板
delete_material(material_id) 调后端删除接口
get_user_token() Token 管理
open_system_preview(file_path) QuickLook / 系统预览

调用时序

打开并阅读 Markdown

1. App: download_file(cos_url) → /tmp/doc.md
2. App: detect_material_type("/tmp/doc.md") → Markdown
3. App: open_document("/tmp/doc.md", "abc123") → handle
4. App: get_document_info(handle) → DocumentInfo
5. App: get_markdown_blocks(handle) → [Block]
6. App: 渲染 blocks
7. 用户滚动 → App: update_reading_position("abc123", pos)
8. 定时器 → App: export_pending_events() → [events]
9. App: POST /reading/events
10. App: clear_exported_events(n)
11. 用户关闭 → App: export_pending_events() → last events
12. App: POST /reading/events
13. App: clear_exported_events(n)

打开 PDF平台预览

1. App: download_file(cos_url) → /tmp/doc.pdf
2. App: detect_material_type("/tmp/doc.pdf") → Pdf
3. App: 判断 PreviewMode::PlatformPreview
4. App: open_system_preview("/tmp/doc.pdf")  // QuickLook
5. App: 监听页码变化 → 转换为 PdfReadingPosition
6. App: update_reading_position("abc123", pos)
7. 同上导出事件流程

错误处理约定

所有函数返回 Result<T, DocumentError>

错误 场景 App 处理
FileNotFound 文件路径不存在 提示用户重新下载
UnsupportedFormat 无法识别的格式 显示"暂不支持"
ParseError 文件内容损坏 显示"文件异常"
InvalidEncoding 非 UTF-8 尝试其他编码或提示
IoError 磁盘错误 重试或提示

线程安全

  • Rust Core 的函数应在后台线程调用
  • App 主线程只做 UI 渲染
  • export_pending_eventsclear_exported_events 内部需要 Mutex 保护