From 8b27430ed12a0de097ba9401f1b63ffa75a64bb2 Mon Sep 17 00:00:00 2001 From: wangdl Date: Thu, 18 Jun 2026 14:25:15 +0800 Subject: [PATCH] docs: add iOS ops docs + CI config (IOS-INFO-028~031) - rust-ffi-update.md: FFI binding update workflow - app-store-submission-checklist.md: 9-section App Store review - ios-ci.yml: GitHub Actions build + test on macos-15 - firebase-crashlytics-integration.md: Crashlytics setup guide Co-Authored-By: Claude Opus 4.7 --- .github/workflows/ios-ci.yml | 48 ++++++++ docs/app-store-submission-checklist.md | 78 ++++++++++++ docs/firebase-crashlytics-integration.md | 150 +++++++++++++++++++++++ docs/rust-ffi-update.md | 144 ++++++++++++++++++++++ 4 files changed, 420 insertions(+) create mode 100644 .github/workflows/ios-ci.yml create mode 100644 docs/app-store-submission-checklist.md create mode 100644 docs/firebase-crashlytics-integration.md create mode 100644 docs/rust-ffi-update.md diff --git a/.github/workflows/ios-ci.yml b/.github/workflows/ios-ci.yml new file mode 100644 index 0000000..d968d27 --- /dev/null +++ b/.github/workflows/ios-ci.yml @@ -0,0 +1,48 @@ +name: iOS CI/CD + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +jobs: + build-and-test: + name: Build & Test + runs-on: macos-15 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode.app + + - name: Build Rust xcframework (arm64 sim) + working-directory: ../zhixi-document-runtime + run: | + rustup target add aarch64-apple-ios-sim + cargo build --release -p zx_document_ffi --target aarch64-apple-ios-sim + + - name: Build for iOS Simulator + run: | + xcodebuild build \ + -project AIStudyApp/AIStudyApp.xcodeproj \ + -scheme AIStudyApp \ + -destination 'platform=iOS Simulator,name=iPhone 16' \ + CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO + + - name: Run Tests + run: | + xcodebuild test \ + -project AIStudyApp/AIStudyApp.xcodeproj \ + -scheme AIStudyApp \ + -destination 'platform=iOS Simulator,name=iPhone 16' \ + CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO \ + 2>&1 | tee xcode-test.log + + - name: Upload test log + if: always() + uses: actions/upload-artifact@v4 + with: + name: xcode-test-log + path: xcode-test.log diff --git a/docs/app-store-submission-checklist.md b/docs/app-store-submission-checklist.md new file mode 100644 index 0000000..faea5eb --- /dev/null +++ b/docs/app-store-submission-checklist.md @@ -0,0 +1,78 @@ +# App Store 提审 Checklist + +## 1. 代码与构建 + +- [ ] `Build Configuration = Release` +- [ ] 所有 Scheme 编译通过(iOS + Simulator) +- [ ] SwiftLint / ESLint 无 warning +- [ ] 单元测试全部通过 +- [ ] `ENABLE_BITCODE = NO`(Xcode 15+) +- [ ] Deployment Target >= iOS 16.0 + +## 2. 隐私与权限 + +- [ ] `Info.plist` 无未声明的隐私权限 +- [ ] 隐私清单(PrivacyInfo.xcprivacy)包含所有使用的 API + - [ ] UserDefaults + - [ ] FileTimestamp + - [ ] SystemBootTime +- [ ] App Tracking Transparency 弹窗(如使用 IDFA) +- [ ] 数据收集声明在 App Store Connect 中填写 + +## 3. 网络与安全 + +- [ ] 所有 API 调用使用 HTTPS +- [ ] ATS(App Transport Security)无例外域名(或已声明) +- [ ] API Key / Token 不硬编码在源码中 +- [ ] Keychain 用于存储敏感凭证 +- [ ] 证书和 Provisioning Profile 有效(≥30 天) + +## 4. Rust xcframework + +- [ ] `ZxDocumentRuntime.xcframework` 包含所需架构 + - [ ] `ios-arm64`(真机) + - [ ] `ios-arm64-sim`(Apple Silicon 模拟器) + - [ ] `ios-x86_64-sim`(Intel 模拟器,可选) +- [ ] xcframework 已正确嵌入(Embed & Sign) +- [ ] `zx_document.swift` uniffi 绑定与 xcframework 版本一致 +- [ ] 加密导出合规(如适用,提交 EAR 分类) + +## 5. UI 与体验 + +- [ ] 启动图/Launch Screen 正确显示 +- [ ] 无空白页面或崩溃路径 +- [ ] iPad 适配(如声明支持) +- [ ] 深色模式适配 +- [ ] 多语言文本无截断 +- [ ] VoiceOver 可用(基础无障碍) + +## 6. App Store Connect 元数据 + +- [ ] 应用名称、副标题、描述 +- [ ] 关键词(100 字符内) +- [ ] 截图(6.7" + 6.5" + 5.5" 各 1-3 张,或仅 6.7") +- [ ] 应用图标(1024×1024) +- [ ] 分级(Rating) +- [ ] 版权信息 +- [ ] 技术支持 URL +- [ ] 隐私政策 URL + +## 7. 测试 + +- [ ] TestFlight 内部测试已通过 +- [ ] 主要流程回归测试:登录→阅读→标记→分析 +- [ ] 网络异常场景:飞行模式、弱网、超时 +- [ ] App 切换(后台→前台)无数据丢失 +- [ ] 低存储空间场景 + +## 8. 版本管理 + +- [ ] `CFBundleShortVersionString` 递增(如 1.0.0 → 1.1.0) +- [ ] `CFBundleVersion` 递增(Build Number) +- [ ] Git tag 对应版本号 + +## 9. 紧急回滚准备 + +- [ ] 上一版本 ipa 已归档 +- [ ] 知道如何取消审核(App Store Connect → 移除提交) +- [ ] Release 分支保护已启用 diff --git a/docs/firebase-crashlytics-integration.md b/docs/firebase-crashlytics-integration.md new file mode 100644 index 0000000..47c3d69 --- /dev/null +++ b/docs/firebase-crashlytics-integration.md @@ -0,0 +1,150 @@ +# 崩溃监控集成(Firebase Crashlytics) + +## 1. 概述 + +Firebase Crashlytics 用于收集 iOS 应用崩溃日志,支持 Swift 层和 Rust FFI 层的崩溃追踪。 + +## 2. 集成步骤 + +### 2.1 添加依赖 + +```swift +// Package.swift 或 Xcode SPM +.package(url: "https://github.com/firebase/firebase-ios-sdk", from: "11.0.0") + +// Target dependencies +.product(name: "FirebaseCrashlytics", package: "firebase-ios-sdk"), +``` + +### 2.2 初始化 + +```swift +// AppDelegate.swift 或 AIStudyApp.swift +import Firebase + +func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + FirebaseApp.configure() + return true +} +``` + +### 2.3 GoogleService-Info.plist + +从 Firebase Console 下载 `GoogleService-Info.plist`,放入 Xcode 项目根目录(不要加入 git,加入 .gitignore)。 + +```bash +# .gitignore +GoogleService-Info.plist +``` + +### 2.4 dSYM 上传 + +```bash +# Build Phase: Run Script +"${BUILD_DIR%/Build/Products}/${CONFIGURATION}-${PLATFORM_NAME}/AIStudyApp.app/dSYMs" +${PODS_ROOT}/FirebaseCrashlytics/upload-symbols \ + -gsp "${PROJECT_DIR}/GoogleService-Info.plist" \ + -p ios "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}" +``` + +--- + +## 3. 自定义日志 + +### 3.1 Swift 层 + +```swift +import FirebaseCrashlytics + +// 记录关键路径 +Crashlytics.crashlytics().log("Reading session opened: \(materialId)") + +// 设置用户标识 +Crashlytics.crashlytics().setUserID(userId) + +// 自定义 key +Crashlytics.crashlytics().setCustomValue(materialId, forKey: "last_material_id") +Crashlytics.crashlytics().setCustomValue(sessionState, forKey: "session_state") +``` + +### 3.2 Rust FFI 层 + +Rust panic 通过 `std::panic::catch_unwind` 捕获后,通过 FFI 回调通知 Swift: + +```swift +// zx_document.swift (uniffi generated) +// Rust panics are caught and returned as errors; +// Swift layer logs them to Crashlytics +do { + try documentRuntime.openMaterial(materialId) +} catch { + Crashlytics.crashlytics().record(error: error) +} +``` + +--- + +## 4. 关键监控点 + +| 位置 | 监控内容 | +|------|----------| +| `AppDelegate.didFinishLaunching` | 启动崩溃 | +| `MaterialReaderView.onAppear` | 阅读器打开 | +| `UploadScheduler.flush()` | 批量上传 | +| `RuntimeRecoveryService.recover()` | 会话恢复 | +| `FFI 调用点` | Rust panic | +| `sceneDidEnterBackground` | 后台切换 | + +--- + +## 5. 符号化 + +### 5.1 Swift 符号 + +Xcode Archive 自动包含 dSYM。Crashlytics 通过 upload-symbols 脚本自动符号化。 + +### 5.2 Rust 符号 + +Rust xcframework 的 dSYM 需手动生成: + +```bash +# 构建带调试符号的 Rust 库 +cargo build --release -p zx_document_ffi --target aarch64-apple-ios + +# 提取 dSYM +dsymutil target/aarch64-apple-ios/release/libzx_document_ffi.a \ + -o ZxDocumentRuntime.dSYM + +# 上传到 Crashlytics +${PODS_ROOT}/FirebaseCrashlytics/upload-symbols \ + -gsp GoogleService-Info.plist \ + -p ios ZxDocumentRuntime.dSYM +``` + +--- + +## 6. 告警阈值 + +| 指标 | 阈值 | 响应 | +|------|:--:|------| +| Crash-free rate | < 99% | 紧急修复 | +| Crash-free rate | < 99.5% | P1 调查 | +| 新 crash 类型 | ≥ 1 | 24h 内分类 | +| 回归 crash | ≥ 1 | 立即回滚 | + +--- + +## 7. 隐私合规 + +- Crashlytics 不采集 PII(个人身份信息) +- 用户 ID 使用匿名化标识符(UUID),不关联登录邮箱 +- 崩溃日志保留 90 天 +- 在隐私政策中声明使用 Firebase Crashlytics + +--- + +## 8. 相关文档 + +- [App Store 提审 Checklist](./app-store-submission-checklist.md) +- [iOS CI/CD](./ios-ci.yml) (.github/workflows/) diff --git a/docs/rust-ffi-update.md b/docs/rust-ffi-update.md new file mode 100644 index 0000000..b709bf3 --- /dev/null +++ b/docs/rust-ffi-update.md @@ -0,0 +1,144 @@ +# Rust FFI 绑定更新流程 + +## 1. 概述 + +iOS 通过 uniffi 生成的 Swift 绑定调用 Rust Document Runtime(zx_document_core)。 + +更新流程:修改 Rust 代码 → 重新生成 bindings → Xcode 重新编译 + +--- + +## 2. 文件结构 + +``` +zhixi-document-runtime/ +├── crates/ +│ ├── zx_document_core/ # 核心 Rust 库 +│ │ ├── src/ +│ │ │ ├── document.rs # DocumentInfo + build_document_info +│ │ │ ├── material_type.rs +│ │ │ ├── markdown.rs # Markdown 解析 +│ │ │ ├── pdf.rs # PDF 元数据/文本提取 +│ │ │ ├── epub.rs # EPUB 元数据/章节/文本 +│ │ │ ├── search.rs # 全文搜索 +│ │ │ ├── anchors.rs # NoteAnchor +│ │ │ ├── events_v2.rs # V2 事件 buffer +│ │ │ ├── session_v2.rs # V2 Session 管理 +│ │ │ └── image_meta.rs # 图片元数据 +│ │ └── Cargo.toml +│ └── zx_document_ffi/ # FFI 绑定层 +│ ├── src/ +│ │ └── lib.rs # uniffi 导出定义 +│ ├── src/zx_document.udl # UDL 接口定义 +│ └── Cargo.toml +└── Cargo.toml # Workspace root + +ios-projects/ +└── AIStudyApp/ + └── AIStudyApp/ + └── Core/ + ├── ZxDocumentRuntime.xcframework/ # 预编译 Rust 库 + └── zx_document.swift # uniffi 生成的 Swift 绑定 +``` + +--- + +## 3. 更新流程 + +### 3.1 修改 Rust 接口 + +1. 在 `zx_document_core/src/` 中修改或新增函数/类型 +2. 在 `zx_document_ffi/src/lib.rs` 中导出新接口 +3. 如需新增 UDL 定义,更新 `zx_document.udl` + +### 3.2 重新生成 Swift 绑定 + +```bash +cd zhixi-document-runtime +cargo build --release -p zx_document_ffi + +# 生成 Swift 绑定 +uniffi-bindgen generate \ + crates/zx_document_ffi/src/zx_document.udl \ + --language swift \ + --out-dir ../ios-projects/AIStudyApp/AIStudyApp/Core/ +``` + +### 3.3 构建 xcframework + +```bash +# iOS arm64 +cargo build --release -p zx_document_ffi --target aarch64-apple-ios + +# iOS Simulator arm64 (Apple Silicon Mac) +cargo build --release -p zx_document_ffi --target aarch64-apple-ios-sim + +# iOS Simulator x86_64 (Intel Mac) +cargo build --release -p zx_document_ffi --target x86_64-apple-ios + +# 打包 xcframework +xcodebuild -create-xcframework \ + -library target/aarch64-apple-ios/release/libzx_document_ffi.a \ + -library target/aarch64-apple-ios-sim/release/libzx_document_ffi.a \ + -output ZxDocumentRuntime.xcframework +``` + +### 3.4 更新 Xcode 项目 + +1. 替换 `AIStudyApp/Core/ZxDocumentRuntime.xcframework` +2. 替换 `AIStudyApp/Core/zx_document.swift` +3. 在 Xcode 中 Clean Build Folder(Cmd+Shift+K) +4. 重新编译 + +--- + +## 4. 新增接口 checklist + +- [ ] Rust 类型实现 `Serialize + Deserialize + uniffi::Record/Enum` +- [ ] FFI 层 `pub extern "C"` 导出函数 +- [ ] UDL 文件声明接口 +- [ ] Swift 绑定重新生成 +- [ ] xcframework 重新编译(至少 arm64 + sim) +- [ ] iOS 编译通过 +- [ ] 单元测试通过(`cargo test -p zx_document_core`) + +--- + +## 5. 常见问题 + +### 5.1 xcframework 架构缺失 + +**症状**:`While building for macOS, no library for this platform was found` + +**原因**:xcframework 仅包含 iOS 架构,Mac Catalyst 构建试图链入 + +**处理**:确保 Scheme 仅勾选 iOS target,或为 Mac Catalyst 添加 `aarch64-apple-ios-macabi` 目标 + +### 5.2 uniffi 版本不匹配 + +**症状**:`uniffi::ffi::foreigncallbacks` not found + +**处理**:确保 `Cargo.toml` 中 uniffi 版本与 `uniffi-bindgen` CLI 版本一致 + +### 5.3 Swift 类型不匹配 + +**症状**:`Cannot convert value of type 'X' to expected argument type 'Y'` + +**处理**:重新生成 `zx_document.swift`(uniffi-bindgen 输出),确保与 xcframework 版本对应 + +--- + +## 6. 版本管理 + +| Rust crate | 当前版本 | FFI 接口数 | +|------------|:--:|:--:| +| zx_document_core | 0.1.0 | — | +| zx_document_ffi | 0.1.0 | 12 | +| uniffi | 0.28 | — | + +--- + +## 7. 相关文档 + +- [V2 事件 Pipeline 架构](./v2-event-pipeline.md) +- [阅读信息采集接入文档](./reading-info-integration.md)