# FFI Troubleshooting ## UniFFI 版本 本项目使用 UniFFI 0.31,采用 **UDL + proc-macro 混合模式**: - UDL(`zx_document.udl`):定义类型和函数签名 - `#[uniffi::export]` proc-macro:生成 C ABI 分发符号 - `uniffi-bindgen`:生成 Swift/Kotlin 绑定代码 ## 常见问题 ### `No such module 'ZxDocumentRuntime'` **原因**:XCFramework 未正确添加到 Xcode 项目。 **解决**: 1. 确认 `bindings/ios/ZxDocumentRuntime.xcframework` 已生成 2. 在 Xcode → Target → General → Frameworks 中添加 3. 确保 Embed 设置为 `Do Not Embed`(静态库) ### `Undefined symbol: _ffi_zx_document_ffi_*` **原因**:C ABI 符号未导出。proc-macro 生成的符号名称可能与链接器期望不一致。 **解决**: 1. 确认 `crates/zx_document_ffi/src/lib.rs` 中 `#[no_mangle] pub extern "C"` 函数存在 2. 检查 Cargo.toml `crate-type = ["lib", "staticlib", "cdylib"]` 3. 运行 `nm target/aarch64-apple-ios/release/libzx_document_ffi.a | grep ffi_` 验证符号 4. 确认 UDL 中声明的函数与 `#[uniffi::export]` 函数名称一致 ### `Library not found for -lzx_document_ffi` **原因**:Library Search Paths 未设置。 **解决**: 1. Build Settings → Library Search Paths → 添加 `$(PROJECT_DIR)/bindings/ios` 2. 或使用绝对路径指向 `.xcframework` 所在目录 ### UniFFI checksum mismatch **原因**:UDL 文件更新后未重新生成 Swift binding。 **解决**: ```bash uniffi-bindgen generate \ --language swift \ --out-dir bindings/ios/generated \ crates/zx_document_ffi/src/zx_document.udl ``` ### `setup_scaffolding!()` not called **原因**:`uniffi::setup_scaffolding!()` 必须在 lib.rs 的第一行调用。 **解决**:确认 `crates/zx_document_core/src/lib.rs` 第一行是 `uniffi::setup_scaffolding!();` ### 新增类型/函数后 Swift 不可见 **原因**:只在 Rust 侧添加了类型/函数,但未更新: 1. UDL 文件声明 2. FFI crate `pub use` 重导出 3. Swift binding 重新生成 **完整的 FFI 接入步骤**: ```bash # 1. Rust 侧添加类型 + 函数 + UDL 声明 # 2. FFI crate: pub use 重导出 + #[uniffi::export] 包装 # 3. 重新生成 Swift uniffi-bindgen generate --language swift \ --out-dir bindings/ios/generated \ crates/zx_document_ffi/src/zx_document.udl # 4. 验证编译 cargo build --release --target aarch64-apple-ios -p zx_document_ffi ``` ### `cargo build` 目标平台不匹配 **原因**:macOS 上构建 iOS 目标需要 Apple Silicon target。 **解决**: ```bash rustup target add aarch64-apple-ios aarch64-apple-ios-sim ``` ### `infer` / `comrak` / `zip` crate 编译失败 **原因**:某些 crate 在 iOS target 下有 C 依赖。 **解决**: - `comrak`:需要启用 `--features` 中的 `onig` 或使用 `syntect` 后端 - `zip`:纯 Rust,无特殊要求 - 确保 `CC` 环境变量指向 Xcode toolchain ### XCFramework 构建注意事项 1. 必须分别编译 device 和 simulator 目标 2. `lipo` 不需要(两个 .a 文件各自是 fat binary) 3. header 文件由 `uniffi-bindgen` 生成:`bindings/ios/generated/zx_documentFFI.h` 4. modulemap 文件创建: ``` framework module ZxDocumentRuntime { header "zx_documentFFI.h" export * } ``` ### UDL 类型不支持 **问题类型**: - `Vec<(String, &str)>` — 不支持 tuple - 泛型函数 — 不支持 - 生命周期参数 — 不支持 **解决**:在 FFI 层创建包装类型。例如 `search_pdf_text(&[(u32, &str)])` → FFI 包装为 `search_pdf_pages(Vec, Vec)`。 ### Rust 与 iOS 持有引用 UniFFI 生成的对象是 **值类型**(序列化跨 FFI 边界传递),不是引用类型。Rust 侧的 `Mutex` 保护全局状态,iOS 侧通过函数调用读写状态。 ### 验证清单 - [ ] `cargo build --release --target aarch64-apple-ios` 通过 - [ ] `cargo build --release --target aarch64-apple-ios-sim` 通过 - [ ] `nm` 验证 C ABI 符号存在 - [ ] Swift binding 生成并编译通过 - [ ] XCFramework 包含 device + simulator slices - [ ] header + modulemap 正确 - [ ] demo App 链接成功