docs: add codebase map

This commit is contained in:
shen 2026-05-21 20:36:12 +08:00
parent faa069ec99
commit 4daa3a6ed4
7 changed files with 764 additions and 0 deletions

View File

@ -0,0 +1,154 @@
<!-- refreshed: 2026-05-21 -->
# 架构概览
**分析日期:** 2026-05-21
## 系统概述
本仓库包含一个 iOS **阅读 SDK**`RDReaderView`)以及一个用于演示集成的 **Demo App**`ReadViewDemo`。Demo 通过 CocoaPods 以本地 `:path` 方式引入 SDK。
```text
┌─────────────────────────────────────────────────────────────────────────┐
│ Demo App │
`ReadViewDemo/ReadViewDemo`
│ - 列表展示内置 .epub/.txt → push `RDURLReaderController`
└───────────────────────────────┬─────────────────────────────────────────┘
│ uses
┌─────────────────────────────────────────────────────────────────────────┐
│ Public SDK │
`Sources/RDReaderView`
│ 入口控制器: │
│ - `RDURLReaderController`(基于 URLepub/txt
│ - `RDEPUBReaderController`EPUB + 外部 TextBook
│ 核心视图: │
│ - `RDReaderView`(仿真翻页 / 横向 / 纵向模式) │
└───────────────┬───────────────────────────┬─────────────────────────────┘
│ │
▼ ▼
┌───────────────────────────┐ ┌─────────────────────────────────────────┐
│ EPUBCore │ │ EPUBTextRendering │
`Sources/RDReaderView/ │ │ `Sources/RDReaderView/EPUBTextRendering`│
│ EPUBCore` │ │ - 从 .txt 构建 `RDEPUBTextBook`
│ - 解析/解压 EPUB │ │ - 文本章节渲染/搜索 │
│ - spine/TOC/location 模型 │ └─────────────────────────────────────────┘
│ - 基于 WKWebView 分页 │
│ - 资源解析/寻址 │
└───────────────┬───────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ EPUBUI │
`Sources/RDReaderView/EPUBUI`
│ - 阅读器 UX工具栏/主题/设置 │
│ - 默认持久化UserDefaults
│ - 协调 parser + paginator + RDReaderView │
└─────────────────────────────────────────────────────────────────────────┘
```
## 组件职责
| 组件 | 职责 | 文件 |
|---|---|---|
| `RDURLReaderController` | 面向“URL 打开”的顶层入口;根据后缀路由 epub vs txt当分页失败时回退为纯文本展示 | `Sources/RDReaderView/RDURLReaderController.swift` |
| `RDEPUBReaderController` | 主阅读器控制器;协调解析/分页,连接 `RDReaderView`;管理阅读状态、选择/高亮/书签、工具视图等 | `Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift` |
| `RDReaderView` | 分页容器视图,支持仿真翻页与滚动模式;通过 data source 获取页面视图并回调当前页变化 | `Sources/RDReaderView/RDReaderView.swift` |
| `RDEPUBParser` | 负责解析 `.epub`container.xml + OPF构建 manifest/spine/TOC产出 `RDEPUBPublication` | `Sources/RDReaderView/EPUBCore/RDEPUBParser.swift` |
| `RDEPUBPublication` | 对解析后的 publication 做只读封装metadata/spine/TOC/资源解析、fixed-layout 判定等) | `Sources/RDReaderView/EPUBCore/RDEPUBPublication.swift` |
| `RDEPUBPaginator` | 以 `WKWebView` 测量并生成分页信息章节页范围、CFI 映射等) | `Sources/RDReaderView/EPUBCore/RDEPUBPaginator.swift` |
| `RDEPUBReadingSession` | 阅读会话状态(当前章节/页、分页缓存、交互状态等),为 UI 层提供数据 | `Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift` |
| `RDEPUBReaderPersistence` | 阅读器持久化协议(位置/设置/书签/高亮等),默认实现使用 UserDefaults | `Sources/RDReaderView/EPUBUI/RDEPUBReaderPersistence.swift` |
> 备注:实际类型与职责以代码为准;上表按文件职责做抽象总结。
## 分层结构
**Demo App 层:**
- 目的:展示集成方式与最小化书籍选择 UX。
- 位置:`ReadViewDemo/ReadViewDemo`
- 依赖:本地 path 的 `RDReaderView` pod、UIKit。
**SDK UI 层Reader UX**
- 目的:阅读器控制器 UX + 设置持久化 + 工具视图。
- 位置:`Sources/RDReaderView/EPUBUI`
- 依赖:`EPUBCore`、`EPUBTextRendering`、`RDReaderView`。
**SDK View 层(分页容器):**
- 目的:页面呈现模式(翻页/滚动)与手势/工具栏显示控制。
- 位置:`Sources/RDReaderView/RDReaderView.swift`、`Sources/RDReaderView/RDReaderFlowLayout.swift`
- 依赖UIKit。
**SDK Core 层EPUB 解析/分页/状态):**
- 目的:解析 EPUB 结构、资源寻址、分页计算、导航状态。
- 位置:`Sources/RDReaderView/EPUBCore`
- 依赖Foundation、WebKit分页/导航、ZIPFoundation解压通过 Podspec 依赖)。
**SDK 文本渲染层:**
- 目的:为纯文本输入构建分页结构并提供渲染/搜索能力。
- 位置:`Sources/RDReaderView/EPUBTextRendering`
- 依赖UIKit/Foundation以及通过 Podspec 依赖的 DTCoreText 相关能力)。
## 数据流
### 主路径(通过 URL 打开书籍)
1. Demo 选择文件并 push reader`ReadViewDemo/ReadViewDemo/ViewController.swift`)。
2. `RDURLReaderController` 根据扩展名分发(`Sources/RDReaderView/RDURLReaderController.swift`)。
3. 对 EPUB`RDEPUBReaderController` 开始加载,解析 publication并为当前视口执行分页`Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`)。
4. 分页由 `RDEPUBPaginator``WKWebView` 测量)生成 `EPUBPage` / `EPUBChapterInfo` 等快照,供 `RDReaderView` 渲染(`Sources/RDReaderView/EPUBCore/RDEPUBPaginator.swift`、`Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift`)。
5. `RDReaderView` 展示页面并输出页切换回调(`Sources/RDReaderView/RDReaderView.swift`)。
### 次路径(打开纯文本文件)
1. `RDURLReaderController` 使用 `RDPlainTextBookBuilder` 构建 `RDEPUBTextBook`,分页尺寸/样式来自 `RDEPUBReaderConfiguration``Sources/RDReaderView/RDURLReaderController.swift`、`Sources/RDReaderView/EPUBTextRendering/RDPlainTextBookBuilder.swift`)。
2. `RDEPUBReaderController` 以 “external TextBook” 模式运行,复用相同的阅读器 UX 与持久化链路(`Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`)。
**状态管理:**
- 内存态主要由 `RDEPUBReadingSession``RDEPUBReaderController` 维护。
- 默认持久化为 UserDefaults`RDEPUBUserDefaultsPersistence`,见 `Sources/RDReaderView/EPUBUI/RDEPUBReaderPersistence.swift`)。
## 入口点
**SDK**
- `RDURLReaderController`URL 入口,封装 epub/txt 分支(`Sources/RDReaderView/RDURLReaderController.swift`)。
- `RDEPUBReaderController`:可直接打开 epub URL或读取已构建的 `RDEPUBTextBook``Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`)。
- `RDReaderView`:可复用的分页视图(`Sources/RDReaderView/RDReaderView.swift`)。
**Demo**
- UIKit 生命周期(`ReadViewDemo/ReadViewDemo/AppDelegate.swift`、`ReadViewDemo/ReadViewDemo/SceneDelegate.swift`)。
## 架构约束
- **平台:** iOS 15+`RDReaderView.podspec` 中 `s.platform = :ios, "15.0"`)。
- **视口耦合:** 分页与视口大小/insets 强耦合,视口变化会触发重新分页(`Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`)。
- **WebKit 依赖:** 可重排 EPUB 的分页使用离屏、非持久化的 `WKWebView``Sources/RDReaderView/EPUBCore/RDEPUBPaginator.swift`)。
## 错误处理
**策略:** URL 入口采用“尽量可用”的 fail-soft 体验Reader Controller 提供可见的 loading/error UI。
**模式:**
- URL 入口在文本分页失败时回退为 `UITextView``Sources/RDReaderView/RDURLReaderController.swift`)。
- Parser 通过 `RDEPUBParserError` 抛出类型化错误(`Sources/RDReaderView/EPUBCore/RDEPUBModels.swift`)。
## Evidence关键证据
检查过的关键文件:
- `RDReaderView.podspec`
- `Podfile`
- `ReadViewDemo/ReadViewDemo.xcworkspace/contents.xcworkspacedata`
- `ReadViewDemo/ReadViewDemo.xcodeproj/project.pbxproj`
- `ReadViewDemo/ReadViewDemo/AppDelegate.swift`
- `ReadViewDemo/ReadViewDemo/SceneDelegate.swift`
- `ReadViewDemo/ReadViewDemo/ViewController.swift`
- `Sources/RDReaderView/RDURLReaderController.swift`
- `Sources/RDReaderView/RDReaderView.swift`
- `Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBParser.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBPaginator.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBPublication.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift`
---
*架构分析2026-05-21*

View File

@ -0,0 +1,130 @@
# 代码库风险与关注点
**分析日期:** 2026-05-21
## 高风险:安全与隐私
### 1) CocoaPods 构建关闭了 User Script Sandboxing
- **问题:** `post_install` hook 将 Pods *以及* 用户工程的 `ENABLE_USER_SCRIPT_SANDBOXING` 强制设置为 `NO`
- **影响:** 削弱对内嵌 Web 内容的纵深防御;增加 `WKWebView` 相关功能的风险面,并可能不符合组织/审核(含 App Store安全基线。
- **建议缓解:**
- 移除全局覆盖,保持系统默认的 sandboxing。
- 如确有依赖需要 workaround仅对具体 Pod target 做最小范围的设置,并记录原因。
- 在 CI 中增加校验:出现 `ENABLE_USER_SCRIPT_SANDBOXING=NO` 时告警/失败。
### 2) 外链打开未做 allowlistscheme/host
- **问题:** EPUB 内容中的外部 URL 通过 `UIApplication.shared.open(...)` 打开时,未对 scheme/host 做校验,也未强制用户二次确认。
- **影响:** 恶意 EPUB 可能触发钓鱼、隐私泄露,或打开意外的 URL scheme包含跳转到其他 App 的 deep link
- **建议缓解:**
- 强制 allowlist默认仅允许 `https`;如需 `mailto`/`tel` 等应在明确 UI 提示后允许)。
- 弹出确认对话框,展示目标 host。
- 对 bridge 消息与导航行为中的非 HTTP(S) scheme 做拒绝/过滤。
### 3) EPUB 解压未显式做 Zip Slip路径穿越加固
- **问题:** 解压逻辑构造 `destinationURL = extractionURL.appendingPathComponent(entry.path)` 并解压 entry但未显式验证标准化后的目标路径是否仍在 `extractionURL` 之内。
- **影响:** 构造的 EPUB 可能尝试通过 `../...` 路径穿越覆盖目标目录外的文件(实际危害与 ZIPFoundation 行为及权限有关,但建议显式防护)。
- **建议缓解:**
- 解压前计算 `standardizedDestination = destinationURL.standardizedFileURL`,并确保其前缀位于 `extractionURL.standardizedFileURL.path + "/"` 之下。
- 拒绝包含 `..`、绝对路径、或异常路径分隔符形式的 entry。
- 考虑先解压到新的随机 UUID 目录,仅将校验通过的内容移动到最终目录。
### 4) 选中文本/高亮内容明文写入 UserDefaults
- **问题:** 选中文本与高亮 payload 以 JSON 编码写入 `UserDefaults`(包含“新”持久化与 legacy 路径)。
- **影响:** 可能将书籍敏感内容(高亮、选择文本)存入默认不加密的持久化位置,可能进入备份;同时数据量可能无限增长(性能与隐私风险)。
- **建议缓解:**
- 仅持久化稳定标识/范围(例如 CFI / rangeInfo运行时再派生文本。
- 如必须持久化文本,存入加密存储(例如 Keychain 或使用 `NSFileProtectionComplete` 的加密文件)并设置大小上限。
- 增加数据保留策略,并提供 “Clear reading data” API。
## 性能与稳定性风险
### 5) Scheme handler 将整文件一次性读入内存(无流式)
- **问题:** `WKURLSchemeHandler` 使用 `Data(contentsOf:)` 读取资源并一次性返回。
- **影响:** EPUB 内的大图/字体/媒体资源可能导致内存峰值、加载变慢,甚至在内存压力下被系统终止。
- **建议缓解:**
- 尽可能改为基于 `InputStream` 的流式传输,并使用增量 `didReceive(...)`
- 对单个资源增加大小上限,超过则优雅失败并提示。
### 6) 隐藏的分页 WKWebView 可能加载外部资源
- **问题:** `RDEPUBPaginator` 使用 `loadFileURL(...allowingReadAccessTo:)`,但未看到对 `navigationAction` 的 allowlist例如仅允许 `file://` 或自定义 `ss-reader://`)。
- **影响:** 分页测量阶段可能产生意外网络请求,引发隐私泄露与不可控性能波动。
- **建议缓解:**
- 在 paginator 场景加入导航策略:默认仅允许 `file://`(以及必要的自定义 scheme`http(s)` 直接取消。
- 视需求考虑内容拦截规则或禁用分页阶段的网络加载。
### 7) EPUB 解压缓存目录可能无限累积
- **问题:** 解压路径基于文件名/大小/mtime 的确定性签名;若目录已存在则直接复用,且无清理策略。
- **影响:** 书籍数量多或频繁更新时磁盘占用持续增长,造成存储压力与潜在卡顿。
- **建议缓解:**
- 为 `ssreaderview-epub` 缓存目录实现淘汰策略LRU/按时间)。
- 提供显式清理 API并在低存储信号时触发清理。
## 可维护性与技术债
### 8) Legacy 与新实现并存(潜在双栈维护)
- **问题:** SDK 同时存在 `LegacyRDReaderController/*` 与较新的 `EPUBCore`/`EPUBUI` 实现,且存在体量很大的 controller 文件。
- **影响:** 行为重复、修复分叉、上手成本上升,长期维护成本更高。
- **建议缓解:**
- 明确弃用/冻结计划:哪些 API 仍受支持,哪些仅做兼容不再演进。
- 抽取共用原语models、persistence、navigation到统一位置逐步移除重复实现。
- 提供兼容 shim推动调用方迁移离开 legacy API。
### 9) DEBUG 下日志与 Web Inspector 可能泄露内容
- **问题:** Debug 辅助会打印导航/消息体selection payload 可能包含用户选中文本;且 DEBUG 下可能默认开启 inspectable。
- **影响:** 在 debug 构建(含内部测试/QA日志可能包含敏感内容并被导出/分享。
- **建议缓解:**
- 默认对消息体做脱敏(仅记录类型/大小),需要时再显式 opt-in 输出内容。
- 将 `isInspectable` 受控于 app 级 debug 开关,而不是在 DEBUG 下默认启用。
## 构建与依赖脆弱性
### 10) 仓库中包含 vendored 的 `Pods/` 目录
- **问题:** 仓库根目录有 `Pods/`,示例工程内也有 `ReadViewDemo/Pods/`
- **影响:** diff 体积大、clone 慢、易产生 merge 冲突,也容易出现依赖陈旧导致的构建不一致。
- **建议缓解:**
- 通常建议不要提交 Pods仅提交 `Podfile.lock`,在 CI 中执行 `pod install`
- 如确有 vendoring 政策,需文档化并提供同步/校验工具,避免漂移。
### 11) Podfile 与 podspec 的部署版本不一致
- **问题:** `Podfile` 设为 `platform :ios, '15.6'`,而 podspec 声明 `s.platform = :ios, "15.0"`
- **影响:** 对外承诺与本地构建基线不一致,容易造成集成方预期偏差。
- **建议缓解:**
- 对齐 `Podfile`、`*.podspec`、Xcode project 的 deployment target。
- 在 CI 中增加漂移检查,防止版本被无意改动。
### 12) podspec 将 Swift 版本钉死为 5.10
- **问题:** `s.swift_versions = ["5.10"]` 将 pod 与特定 Swift 版本强绑定。
- **影响:** 旧工具链的集成方无法使用;未来升级可能出现“突然不兼容”,尤其当依赖未同步时。
- **建议缓解:**
- 如兼容性允许,可声明更多支持版本(或范围),并在 CI 中覆盖多个 Xcode/Swift 版本构建验证。
- 在文档中明确最低支持的 Xcode/Swift 版本。
## 不清晰/容易踩坑的契约
### 13) 默认的持久化协议实现可能静默丢失数据
- **问题:** `RDEPUBReaderPersistence` 通过 protocol extension 提供了 bookmarks/settings 的默认 no-op 实现。
- **影响:** 集成方可能误以为这些能力默认会持久化,但实际数据会被静默丢弃,且不易排查。
- **建议缓解:**
- 将关键方法改为必须实现(移除 no-op 默认实现);或在未实现且功能启用时输出日志/assert。
- 提供并文档化 “最小持久化” 与 “完整持久化” 的参考实现。
---
## Evidence仓库路径
- Build flags`Podfile`
- Pod metadata/toolchain`RDReaderView.podspec`
- Archive extraction`Sources/RDReaderView/EPUBCore/RDEPUBParser+Archive.swift`
- Resource path validationpost-extraction`Sources/RDReaderView/EPUBCore/RDEPUBParser+Resources.swift`
- Scheme handler reads full file bytes`Sources/RDReaderView/EPUBCore/RDEPUBResourceURLSchemeHandler.swift`
- WebView bridge + message handling`Sources/RDReaderView/EPUBCore/RDEPUBWebView+JavaScriptBridge.swift`
- External link openingnew UI`Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`
- External link opening + selection persistencelegacy`Sources/RDReaderView/LegacyRDReaderController/RDReaderController.swift`
- UserDefaults persistence implementation`Sources/RDReaderView/EPUBUI/RDEPUBReaderPersistence.swift`
- Hidden paginator web view`Sources/RDReaderView/EPUBCore/RDEPUBPaginator.swift`
- Debug logging`Sources/RDReaderView/EPUBCore/RDEPUBWebViewDebug.swift`
- Vendored dependencies`Pods/`、`ReadViewDemo/Pods/`
---
*风险与关注点审计2026-05-21*

View File

@ -0,0 +1,88 @@
# 编码规范
**分析日期:** 2026-05-21
> 说明:本仓库以 iOS/Swift 为主,未检测到统一的 lint/format 工具配置;代码风格在不同模块/年代间存在差异。`.planning/` 下的文档按项目规则使用中文描述,但代码标识符保持英文。
## 语言与工程约束
- **主要语言**SwiftPodspec 声明 `s.swift_versions = ["5.10"]`,见 `RDReaderView.podspec`
- **最低系统版本**Podspec `iOS 15.0``RDReaderView.podspec`),示例工程 Podfile/构建设置里常见为 `iOS 15.6``Podfile`
- **依赖管理**CocoaPods`Podfile`、`ReadViewDemo/Podfile`、`Podfile.lock`
## 命名约定
**文件/类型命名Swift**
- 以类型名为文件名的单文件组织较常见:`Sources/RDReaderView/EPUBCore/RDEPUBParser.swift`
- 大量使用前缀区分模块域:
- `RD...`:阅读器 UI/控制器相关(如 `Sources/RDReaderView/RDReaderView.swift`、`Sources/RDReaderView/RDURLReaderController.swift`
- `RDEPUB...`EPUB Core/UI/渲染相关(如 `Sources/RDReaderView/EPUBCore/RDEPUBModels.swift`
- Extension 文件使用 `+` 命名:`Sources/RDReaderView/LegacyRDReaderController/RDReaderController+EPUBText.swift`
**变量/函数命名:**
- 基本遵循 Swift lowerCamelCase`parse(epubURL:)``Sources/RDReaderView/EPUBCore/RDEPUBParser.swift`
- UI 代码中常见简写:`imageV``Sources/RDReaderView/LegacyRDReaderController/RDReaderCoverView.swift`
- 常量多用 `static let``epubPaginationCacheStorageKey``Sources/RDReaderView/LegacyRDReaderController/RDReaderController.swift`
## 代码风格与排版(从现有代码归纳)
**缩进与换行:**
- 多数文件使用 4 空格缩进(示例:`ReadViewDemo/ReadViewDemo/ViewController.swift`、`Sources/RDReaderView/EPUBCore/RDEPUBModels.swift`
- 历史代码中更常见“强制换行/多行括号”风格(示例:`Sources/RDReaderView/LegacyRDReaderController/RDReaderController.swift` 的 `CGRect(...)`
**空行与分组:**
- UI 相关文件常用空行分隔属性/初始化/布局段落(示例:`Sources/RDReaderView/LegacyRDReaderController/RDReaderCoverView.swift`
- `// MARK:` 用于分区组织(示例:`Sources/RDReaderView/RDReaderGestureController.swift`、`Sources/RDReaderView/LegacyRDReaderController/RDReaderController.swift`、`Sources/RDReaderView/EPUBTextRendering/RDPlainTextBookBuilder.swift`
**类型组织:**
- 偏好用 `extension` 拆分职责/协议实现(示例:`ReadViewDemo/ReadViewDemo/ViewController.swift` 的 `UITableViewDataSource/Delegate`
- API 暴露处使用 `public`、`public final class`、`public enum/struct`(示例:`Sources/RDReaderView/EPUBCore/RDEPUBModels.swift`
- “对外只读、内部可写”常用 `public internal(set)`(示例:`Sources/RDReaderView/EPUBCore/RDEPUBParser.swift`
## 导入与依赖使用
**import**
- UIKit/UI 文件:`import UIKit`(大量文件)
- Core/模型文件:`import Foundation`(如 `Sources/RDReaderView/EPUBCore/RDEPUBModels.swift`
- 三方依赖按需引入:
- `SnapKit`:布局(如 `Sources/RDReaderView/LegacyRDReaderController/RDReaderCoverView.swift`
- `SSAlertSwift`:弹窗/提示(如 `Sources/RDReaderView/LegacyRDReaderController/RDReaderController.swift`
**Pods 目录说明:**
- `ReadViewDemo/Pods/**` 为依赖源码/生成配置,通常不作为本仓库代码风格的“标准样式”参考。
## 错误处理与日志
- Core 解析层倾向用 `throws` + 自定义 `Error`(示例:`Sources/RDReaderView/EPUBCore/RDEPUBParser.swift`、`Sources/RDReaderView/EPUBCore/RDEPUBModels.swift` 的 `RDEPUBParserError`
- UI/控制器层常见 `guard` 早返回(示例:`ReadViewDemo/ReadViewDemo/ViewController.swift`
- 未检测到统一日志框架(未发现专用 logging package/config出现时以系统 API/局部输出为主(需按具体文件核对)。
## 注释与文档
- **项目规则(强约束)**:代码标识符保持英文,但**代码注释/文档/提交信息使用中文**(见 `CONTEXT.md`)。
- 历史文件常带 Xcode 头部注释块(示例:`Sources/RDReaderView/RDReaderView.swift`、`Sources/RDReaderView/LegacyRDReaderController/RDReaderCoverView.swift`)。
- 公共 API 处存在少量三斜线文档注释(示例:`Sources/RDReaderView/RDReaderView.swift` 的中文说明)。
## Lint / Formatter / 静态检查
**未检测到(仓库根与常见位置):**
- SwiftLint 配置:`.swiftlint.yml` / `swiftlint.yml`
- SwiftFormat 配置:`.swiftformat`
- 通用格式化配置:`.editorconfig`
- 其他ESLint/Prettier/Biome 等(本仓库非 JS/TS 主体)
**可执行的工程级格式化/检查:**
- 主要依赖 Xcode或 Swift 编译器)自身检查;如需引入 SwiftLint/SwiftFormat应先新增对应配置文件并在 CI/构建脚本中接入。
## Evidence关键证据文件
- `CONTEXT.md`
- `Podfile`
- `RDReaderView.podspec`
- `ReadViewDemo/ReadViewDemo/ViewController.swift`
- `Sources/RDReaderView/RDReaderView.swift`
- `Sources/RDReaderView/LegacyRDReaderController/RDReaderController.swift`
- `Sources/RDReaderView/LegacyRDReaderController/RDReaderCoverView.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBParser.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBModels.swift`
- `ReadViewDemo/ReadViewDemo.xcodeproj/project.pbxproj`

View File

@ -0,0 +1,90 @@
# 外部集成
**分析日期:** 2026-05-21
## API 与外部服务
**网络 / Web 服务:**
- 在 SDK 源码(`Sources/RDReaderView/**`)中未检测到:未发现 `URLSession` 使用,也未发现常见第三方网络 SDK。
**托管服务 SDK统计/崩溃/广告/支付):**
- 在仓库源码中未检测到:未发现 Firebase、Sentry、Mixpanel/Segment/Amplitude、AppCenter 等。
## 数据存储
**数据库:**
- 未检测到(`Sources/RDReaderView/**` 中未发现 Core Data / SQLite / Realm / GRDB 使用)。
**文件存储(本地文件系统):**
- EPUB 解压使用 `FileManager`,将解压内容存放在 app caches 或临时目录下,并使用“确定性签名”目录名 — `Sources/RDReaderView/EPUBCore/RDEPUBParser+Archive.swift`
**偏好 / 轻量持久化:**
- 使用 `UserDefaults` 保存设置/状态(例如 debug 开关、阅读器状态快照)— `Sources/RDReaderView/EPUBCore/RDEPUBWebViewDebug.swift`、`Sources/RDReaderView/EPUBUI/RDEPUBReaderPersistence.swift`、`Sources/RDReaderView/LegacyRDReaderController/RDReaderController.swift`。
## 认证与身份
- 不适用(未检测到认证提供方或身份流程)。
## 监控与可观测性
**错误追踪 / 崩溃上报:**
- 未检测到(无 Crashlytics/Sentry 等)。
**日志:**
- 存在用于 EPUB WebView 调试的本地 debug 日志工具 — `Sources/RDReaderView/EPUBCore/RDEPUBWebViewDebug.swift`
## 构建期集成
**CocoaPods**
- SDK 作为 CocoaPod 发布并声明外部依赖 — `RDReaderView.podspec`
- 示例 App 通过本地 `:path => '..'` 引用该 Pod — `ReadViewDemo/Podfile`
- 仓库根 `Podfile` 也声明了 `RDReaderView` 的本地 path 依赖,并设置共享构建参数覆盖 — `Podfile`
**构建设置覆盖:**
- 在 `post_install` 中统一设置 `ENABLE_USER_SCRIPT_SANDBOXING = NO`、`IPHONEOS_DEPLOYMENT_TARGET = 15.6` — `Podfile`、`ReadViewDemo/Podfile`。
## 渲染 / 内嵌 Web 内容
**WKWebView 集成:**
- 使用 `WKWebViewConfiguration` 并设置 `websiteDataStore = .nonPersistent()`;注册自定义 URL scheme handler 以服务 EPUB 资源 — `Sources/RDReaderView/EPUBCore/RDEPUBWebView+Configuration.swift`
- 注入 user script并注册 script message handler 实现 JavaScript bridge — `Sources/RDReaderView/EPUBCore/RDEPUBWebView+Configuration.swift`、`Sources/RDReaderView/EPUBCore/RDEPUBJavaScriptBridge.swift`。
## CI/CD 与部署
**CI 流水线:**
- 未检测到(未发现 `.github/` 或常见 CI 配置文件)。
**部署:**
- 未检测到 App 部署流水线;仓库形态为 iOS SDK + Demo App`RDReaderView.podspec`、`ReadViewDemo/`)。
## 环境配置
**必须的环境变量:**
- 未检测到(未发现 `.env*` 使用,也未发现 `Sources/RDReaderView/**` 中读取环境变量的代码)。
**密钥存放:**
- 基于当前仓库内容检查结果:不适用。
## Webhooks 与回调
**入站:**
- 未检测到。
**出站:**
- 未检测到。
## Evidence关键证据
检查过的关键文件:
- `RDReaderView.podspec`
- `ReadViewDemo/Podfile`
- `ReadViewDemo/Podfile.lock`
- `Podfile`
- `Sources/RDReaderView/EPUBCore/RDEPUBParser+Archive.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBWebView+Configuration.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBJavaScriptBridge.swift`
- `Sources/RDReaderView/LegacyRDReaderController/RDReaderController.swift`
---
*外部集成审计2026-05-21*

View File

@ -0,0 +1,82 @@
# 技术栈
**分析日期:** 2026-05-21
## 语言
**主要语言:**
- SwiftPodspec 声明 Swift 5.10)— SDK 实现在 `Sources/RDReaderView/**/*.swift`,示例 App 在 `ReadViewDemo/ReadViewDemo/*.swift`
**次要语言:**
- Objective-C — 主要来自示例工程 vendored 的 CocoaPods 依赖源码 `ReadViewDemo/Pods/**`(例如 DTFoundation/DTCoreText
## 运行环境
**平台:**
- iOS — 最低 iOS 15.xSDK 声明 iOS 15.0Demo/Podfile 常见为 15.6)。
**使用到的 Apple Framework不完全列举**
- UIKit — `Sources/RDReaderView/**` 内的 UI 与控制器实现。
- WebKit — EPUB Web 渲染相关配置见 `Sources/RDReaderView/EPUBCore/RDEPUBWebView+Configuration.swift`
- CoreText — 文本分页/渲染支持(`Sources/RDReaderView/EPUBTextRendering/**`)。
- Foundation — 文件系统/持久化等基础能力(`Sources/RDReaderView/**`)。
## 依赖管理
**CocoaPods**
- SDK 以 Podspec 形式发布:`RDReaderView.podspec`。
- 示例工程通过 CocoaPods 集成:`ReadViewDemo/Podfile`、`ReadViewDemo/Podfile.lock`。
- Lockfile 记录的 CocoaPods 版本1.16.2`ReadViewDemo/Podfile.lock`)。
**未检测到:**
- Swift Package Manager未发现 `Package.swift`
- Carthage未发现 `Cartfile`
## 框架与第三方库
**核心库(本仓库):**
- `RDReaderView`(阅读器 UI + EPUB/TXT 阅读能力)— `Sources/RDReaderView/**`
**Pod 声明的第三方依赖:**
- `ZIPFoundation (~> 0.9)` — EPUB 压缩包读取/解压与解析。
- `DTCoreText` — HTML → NSAttributedString 渲染(在 `#if canImport(DTCoreText)` 条件下使用)。
- `SnapKit` — Auto Layout 约束封装。
- `SSAlertSwift` — 弹窗/提示 UI 工具。
## 构建与开发工具
**Xcode 工程(示例 App**
- Workspace/Project`ReadViewDemo/ReadViewDemo.xcworkspace`、`ReadViewDemo/ReadViewDemo.xcodeproj`。
**CocoaPods post_install 构建设置(仓库内配置):**
- 在 Pods 与用户工程上统一设置 `IPHONEOS_DEPLOYMENT_TARGET = 15.6``ENABLE_USER_SCRIPT_SANDBOXING = NO` — 见 `Podfile`、`ReadViewDemo/Podfile`。
## 资源与素材
**资源 bundle**
- Podspec 声明了 `RDReaderViewAssets` 资源 bundle来源为 `Sources/RDReaderView/Resources/**``RDReaderView.podspec`)。
## 平台要求
**开发:**
- 需要 macOS + XcodeiOS SDK构建 Demo workspace/project`ReadViewDemo/ReadViewDemo.xcworkspace`)。
- 需要 CocoaPods 安装 Demo 依赖(`ReadViewDemo/Podfile.lock` 体现了 CocoaPods 使用)。
**发布/分发:**
- 以 CocoaPod 形式分发(`RDReaderView.podspec`)。
## Evidence关键证据
检查过的关键文件:
- `RDReaderView.podspec`
- `Podfile`
- `ReadViewDemo/Podfile`
- `ReadViewDemo/Podfile.lock`
- `ReadViewDemo/ReadViewDemo.xcodeproj/project.pbxproj`
- `Sources/RDReaderView/EPUBCore/RDEPUBWebView+Configuration.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBParser+Archive.swift`
- `Sources/RDReaderView/EPUBTextRendering/RDEPUBDTCoreTextRenderer.swift`
---
*技术栈分析2026-05-21*

View File

@ -0,0 +1,149 @@
# 代码库结构
**分析日期:** 2026-05-21
## 目录布局
```text
ReadViewSDK/
├── Sources/
│ └── RDReaderView/ # SDK 实现Swift
│ ├── EPUBCore/ # EPUB 解压/解析/模型/分页/状态Foundation/WebKit
│ ├── EPUBTextRendering/ # TXT/TextBook 构建 + 文本渲染/搜索
│ ├── EPUBUI/ # 阅读器控制器 UX、设置、持久化、工具视图
│ ├── LegacyRDReaderController/# 旧版阅读器控制器 + 工具视图
│ ├── Resources/ # 资源pod resource bundle
│ ├── RDReaderView.swift # 核心分页视图 + DS/delegate 协议
│ ├── RDReaderFlowLayout.swift # 滚动模式的 CollectionView 分页布局
│ └── RDURLReaderController.swift # 基于 URL 的入口控制器
├── ReadViewDemo/
│ ├── ReadViewDemo/ # Demo App 源码/资源UIKit
│ ├── ReadViewDemo.xcodeproj/ # Demo target 的 Xcode project
│ ├── ReadViewDemo.xcworkspace/ # 集成 Pods 工程的 workspace
│ ├── Podfile # Demo 的 Pods 集成(本地 path
│ └── Podfile.lock # Demo 的锁定依赖版本
├── Pods/ # 仓库根目录的 CocoaPods 产物(本地开发)
├── Podfile # 仓库级 Pods 集成脚本(见说明)
├── RDReaderView.podspec # SDK 的 Podspec分发与依赖声明
├── Doc/ # 参考资料/分析产物
└── .planning/codebase/ # 生成的代码库地图(本目录)
```
## 目录职责
**`Sources/RDReaderView/EPUBCore`**
- 目的EPUB 解压 + 解析 + 核心模型 + 分页 + 导航状态。
- 关键文件:
- `Sources/RDReaderView/EPUBCore/RDEPUBParser.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBPaginator.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBPublication.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBReadingSession.swift`
**`Sources/RDReaderView/EPUBUI`**
- 目的:阅读器 UX 协调与对外 reader controller API。
- 关键文件:
- `Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`
- `Sources/RDReaderView/EPUBUI/RDEPUBReaderConfiguration.swift`
- `Sources/RDReaderView/EPUBUI/RDEPUBReaderPersistence.swift`
**`Sources/RDReaderView/EPUBTextRendering`**
- 目的:从 `.txt` 构建 `RDEPUBTextBook`,并提供渲染/搜索等能力。
- 关键文件:
- `Sources/RDReaderView/EPUBTextRendering/RDPlainTextBookBuilder.swift`
- `Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift`
- `Sources/RDReaderView/EPUBTextRendering/RDEPUBTextRenderer.swift`
**`Sources/RDReaderView`(顶层文件):**
- 目的SDK 的对外入口与核心分页视图/布局基础设施。
- 关键文件:
- `Sources/RDReaderView/RDURLReaderController.swift`
- `Sources/RDReaderView/RDReaderView.swift`
- `Sources/RDReaderView/RDReaderFlowLayout.swift`
**`ReadViewDemo/ReadViewDemo`**
- 目的Demo App用于发现内置书籍并打开 SDK。
- 关键文件:
- `ReadViewDemo/ReadViewDemo/ViewController.swift`
- `ReadViewDemo/ReadViewDemo/AppDelegate.swift`
- `ReadViewDemo/ReadViewDemo/SceneDelegate.swift`
## 关键文件位置
**SDK 入口点:**
- `Sources/RDReaderView/RDURLReaderController.swift`URL 入口epub/txt 路由)。
- `Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`主阅读器控制器EPUB + external TextBook
- `Sources/RDReaderView/RDReaderView.swift`:分页视图与 data source/delegate 协议。
**Demo 入口点:**
- `ReadViewDemo/ReadViewDemo/AppDelegate.swift`App 生命周期入口(`@main`)。
- `ReadViewDemo/ReadViewDemo/SceneDelegate.swift`Window 与 root navigation controller 配置。
- `ReadViewDemo/ReadViewDemo/ViewController.swift`:书籍列表 → 打开 reader。
**配置/打包:**
- `RDReaderView.podspec`SDK 打包(源码 + 资源 + 依赖)。
- `ReadViewDemo/Podfile`Demo 的 Pods 集成(`pod 'RDReaderView', :path => '..'`)。
- `ReadViewDemo/ReadViewDemo.xcworkspace/contents.xcworkspacedata`workspace 结构。
## 命名约定
**模块(目录)划分:**
- `EPUBCore`、`EPUBUI`、`EPUBTextRendering`:按职责分层拆分于 `Sources/RDReaderView/` 下。
**类型前缀:**
- `RD*`:阅读器容器视图与 legacy controller/tooling例如 `RDReaderView`、`RDURLReaderController`)。
- `RDEPUB*`EPUB 解析/分页/阅读器 UI 域(例如 `RDEPUBParser`、`RDEPUBPaginator`、`RDEPUBReaderController` 及相关模型)。
## 组件关系(从入口到渲染)
- `RDURLReaderController` 根据文件类型选择实现:
- `.epub``RDEPUBReaderController(epubURL:configuration:persistence:)`
- `.txt``RDPlainTextBookBuilder``RDEPUBReaderController(textBook:...)`
- 回退路径:分页失败时使用 `UITextView` 展示原始文本
- 入口文件:`Sources/RDReaderView/RDURLReaderController.swift`
- `RDEPUBReaderController` 负责阅读器生命周期:
- parse`RDEPUBParser`)→ publication`RDEPUBPublication`)→ paginate`RDEPUBPaginator`)→ display`RDReaderView`
- 通过 `RDEPUBReaderPersistence` 持久化设置/位置/书签/高亮等
- 入口文件:`Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`
## 新代码应放在哪里
**新增面向读者的 UI 功能(工具视图/菜单/手势):**
- 主要:`Sources/RDReaderView/EPUBUI/`
- 若影响分页呈现:`Sources/RDReaderView/RDReaderView.swift` 或 `Sources/RDReaderView/RDReaderFlowLayout.swift`
**新增 EPUB 解析/模型支持:**
- 主要:`Sources/RDReaderView/EPUBCore/`parser/models/resolver
**新增纯文本导入/渲染行为:**
- 主要:`Sources/RDReaderView/EPUBTextRendering/`
**更新 Demo / 复现步骤:**
- 主要:`ReadViewDemo/ReadViewDemo/`
## 特殊目录说明
**`Pods/` 与 `ReadViewDemo/Pods/`**
- 用途CocoaPods 生成产物,服务本地开发/示例工程。
- 是否生成:是。
- 是否提交:当前工作区中存在(通常按生成目录对待)。
**`Doc/`**
- 用途:文档/分析资料(不属于 SDK 运行时的一部分)。
## Evidence关键证据
检查过的关键文件:
- `RDReaderView.podspec`
- `Podfile`
- `ReadViewDemo/Podfile`
- `ReadViewDemo/ReadViewDemo.xcodeproj/project.pbxproj`
- `ReadViewDemo/ReadViewDemo.xcworkspace/contents.xcworkspacedata`
- `ReadViewDemo/ReadViewDemo/ViewController.swift`
- `Sources/RDReaderView/RDURLReaderController.swift`
- `Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBParser.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBPaginator.swift`
---
*结构分析2026-05-21*

View File

@ -0,0 +1,71 @@
# 测试说明
**分析日期:** 2026-05-21
## 测试框架与现状
**Runner**
- XCTestiOS/Xcode 默认测试框架)
- **当前仓库状态**:未检测到任何 XCTest 测试文件或测试 Target未发现 `import XCTest`/`XCTestCase`,且示例工程 `ReadViewDemo``project.pbxproj` 仅声明应用 Target
**断言库:**
- XCTest 内建断言(当前仓库未见使用案例)
## 测试文件组织
**位置:**
- 未检测到 `*Tests*` 目录或 `*.test.*` / `*.spec.*` 文件(排除 `ReadViewDemo/Pods/**` 第三方依赖源码)。
**命名:**
- 未检测到(无测试用例)
## 如何运行(在当前仓库结构下)
### CocoaPods 依赖准备
> 仓库包含示例工程 `ReadViewDemo`,并已提交 `Pods/``Podfile.lock`。如本地环境未同步,可在仓库根或示例工程目录运行:
```bash
pod install
```
(依赖入口:`Podfile`、`ReadViewDemo/Podfile`
### 运行/构建示例工程
- Xcode 打开:`ReadViewDemo/ReadViewDemo.xcworkspace`
- Scheme/Target 名称从工程文件可见为 `ReadViewDemo`(见 `ReadViewDemo/ReadViewDemo.xcodeproj/project.pbxproj`
### 运行测试
**当前无测试可运行。** 若未来添加 `ReadViewDemoTests`(或为 SDK 增加独立测试工程/SwiftPM 包),可用 Xcode 或 `xcodebuild test` 运行。
示例(需要存在测试 Scheme/Target 后才有效):
```bash
xcodebuild test \
-workspace ReadViewDemo/ReadViewDemo.xcworkspace \
-scheme ReadViewDemo \
-destination 'platform=iOS Simulator,name=iPhone 15'
```
> 注:本环境中执行 `xcodebuild -list` 发生过 CoreSimulator/日志权限相关错误,属于运行环境限制;测试命令以项目结构为依据给出,实际执行以本机 Xcode/Simulator 可用性为准。
## 覆盖率Coverage
- 未检测到覆盖率配置或现有覆盖率报告产物(例如 `.xcresult` 固化路径或 CI 输出)。
- 若新增 XCTest Target可在 Xcode Scheme 的 Test 设置中启用 Coverage或通过 `xcodebuild test` 生成 `.xcresult` 后用 Xcode 查看。
## Mocking / Fixtures
- 未检测到统一 mocking 框架或 fixtures 目录(无测试用例)。
## Evidence关键证据文件
- `ReadViewDemo/ReadViewDemo.xcodeproj/project.pbxproj`
- `Podfile`
- `ReadViewDemo/Podfile`
- `ReadViewDemo/Podfile.lock`
- `RDReaderView.podspec`
- `ReadViewDemo/ReadViewDemo/ViewController.swift`
- `Sources/RDReaderView/EPUBCore/RDEPUBParser.swift`