zhixi-document-runtime/docs/ios-ffi-integration-guide.md
wangdl 8968858211 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>
2026-06-18 14:34:59 +08:00

222 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)