docs: add iOS FFI integration guide (DOC-FULL-027)

- Architecture: Swift→uniffi C-ABI→Rust FFI→core
- Type mapping: Rust struct/enum ↔ Swift Record/Enum
- Core API reference: document parsing, search, anchors, V2 sessions
- Error handling, thread safety, performance recommendations

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
wangdl 2026-06-18 14:34:59 +08:00
parent 433b1ad7c0
commit 4badf86953

View File

@ -0,0 +1,221 @@
# Document Runtime iOS FFI 调用指南
## 1. 概述
Document Runtimezx_document_core通过 UniFFI 生成 C-ABI 兼容的 Swift 绑定,嵌入 iOS 应用作为 `ZxDocumentRuntime.xcframework`
Swift 层通过 uniffi 生成的 `zx_document.swift` 调用所有 Rust 功能。
---
## 2. 架构
```
┌──────────────────────────────────────┐
│ iOS Swift │
│ zx_document.swift (uniffi 生成) │
│ ├─ buildDocumentInfo() │
│ ├─ parseMarkdown() │
│ ├─ extractPdfText() │
│ ├─ extractEpubChapterTexts() │
│ ├─ searchBlocks() / searchText() │
│ ├─ resolveNoteAnchors() │
│ ├─ startReadingSessionV2() │
│ ├─ pushHeartbeatV2() │
│ ├─ exportPending() / ackExported() │
│ └─ ... │
└──────────────┬───────────────────────┘
│ C-ABI (uniffi)
┌──────────────▼───────────────────────┐
│ Rust: zx_document_ffi │
│ lib.rs — #[uniffi::export] fns │
└──────────────┬───────────────────────┘
┌──────────────▼───────────────────────┐
│ Rust: zx_document_core │
│ document / markdown / pdf / epub / │
│ search / anchors / events_v2 / ... │
└──────────────────────────────────────┘
```
---
## 3. 类型映射
### 3.1 基础类型
| Rust | Swift |
|------|-------|
| `String` | `String` |
| `u32` / `u64` | `UInt32` / `UInt64` |
| `i64` | `Int64` |
| `bool` | `Bool` |
| `Vec<T>` | `[T]` |
| `Option<T>` | `T?` |
| `Result<T, E>` | `throws` |
### 3.2 结构体 → Record
```rust
#[derive(uniffi::Record)]
pub struct DocumentInfo { ... }
```
```swift
// uniffi 生成
public struct DocumentInfo {
public var materialId: String
public var title: String
public var materialType: MaterialType
// ...
}
```
### 3.3 枚举 → Enum
```rust
#[derive(uniffi::Enum)]
pub enum MaterialType { Markdown, Text, Pdf, Image, Epub, Word, Excel, PowerPoint, Unknown }
```
```swift
public enum MaterialType {
case markdown, text, pdf, image, epub, word, excel, powerPoint, unknown
}
```
---
## 4. 核心 API
### 4.1 文档解析
```swift
// 构建文档信息(文件类型检测 + 元数据提取)
let info = try buildDocumentInfo(
filePath: "/path/to/file.md",
materialId: "mat-001",
title: "My Document"
)
// → DocumentInfo { materialType, pageCount, wordCount, epubChapterCount, ... }
// Markdown 解析为块
let blocks = try parseMarkdown(markdown: "# Title\n\nContent")
// → [DocumentBlock]
// PDF 元数据
let pdfMeta = try readPdfMetadata(filePath: "/path/to/book.pdf")
// → PdfMetadata { pageCount, title, author }
// PDF 文本提取
let pages = try extractPdfText(filePath: "/path/to/book.pdf")
// → [PdfPageText { pageNumber, text }]
// EPUB 元数据
let epubMeta = try readEpubMetadata(filePath: "/path/to/book.epub")
// → EpubMetadata { title, author, chapterCount }
// EPUB 章节文本提取HTML strip
let chapters = try extractEpubChapterTexts(filePath: "/path/to/book.epub")
// → [EpubChapterText { chapterId, text }]
```
### 4.2 搜索
```swift
// 搜索 Markdown 块
let results = searchBlocks(blocks: blocks, query: "keyword")
// → [SearchResult { blockId, snippet, matchStart, matchEnd }]
// 搜索纯文本
let textResults = searchText(content: text, query: "keyword")
// → [SearchResult { lineNumber, ... }]
```
### 4.3 锚点
```swift
let anchors = try resolveNoteAnchors(
blocks: blocks,
anchorHints: ["#heading-1", "#paragraph-2"]
)
// → [NoteAnchor { anchorId, blockId, ... }]
```
### 4.4 V2 阅读会话
```swift
// 开始会话
let sessionId = try startReadingSessionV2(
material: ReadingMaterialRefV2(materialId: "mat-001"),
timestampMs: Int64(Date().timeIntervalSince1970 * 1000)
)
// 推送位置变更事件
try pushPositionChangedV2(
sessionId: sessionId,
position: ReadingPosition.markdown(
blockId: "b1",
scrollProgress: 0.5
),
timestampMs: nowMs()
)
// 导出待上传事件
let (events, state) = exportPendingV2()
// → ([BufferedReadingEventV2], EventBufferStateV2)
// ACK 已上传事件
ackExportedV2(count: UInt32(events.count))
// 关闭会话
try closeReadingSessionV2(sessionId: sessionId, timestampMs: nowMs())
```
---
## 5. 错误处理
所有 FFI 函数返回 `Result<T, String>`UniFFI 映射为 Swift `throws`
```swift
do {
let info = try buildDocumentInfo(filePath: path, materialId: id, title: title)
// 使用 info
} catch {
print("Document Runtime error: \(error)")
// error 是 Rust DocumentError 的 Display 字符串
}
```
常见错误:
- `IoError` — 文件不存在/无权限
- `ParseError` — 格式损坏/不支持的格式
- `MarkdownParseError` — Markdown 语法错误
---
## 6. 线程安全
- Rust 层使用 `Mutex<Vec<T>>` 保护全局状态EventBuffer
- 所有 FFI 函数可从任意线程调用
- Swift 层应在主线程调用 UI 更新,后台线程调用 FFI
---
## 7. 性能建议
| 操作 | 建议 |
|------|------|
| `buildDocumentInfo` | 主线程调用(< 50ms缓存结果 |
| `extractPdfText` | 后台线程(可能耗时数秒) |
| `parseMarkdown` | 任意线程(< 10ms |
| `searchBlocks` | 任意线程(< 10ms |
| `exportPendingV2` | 后台定时器30s主线程调用也可 |
---
## 8. 相关文档
- [V2 事件 Pipeline 架构](../ios-projects/docs/v2-event-pipeline.md)ios-projects 仓库)
- [Rust FFI 绑定更新流程](../ios-projects/docs/rust-ffi-update.md)ios-projects 仓库)
- [UniFFI UDL 编写规范](./uniffi-udl-spec.md)
- [文件格式支持矩阵](./file-format-support-matrix.md)