ReadViewSDK/Doc/架构对比分析_WXRead_vs_ReadViewSDK.md

274 lines
15 KiB
Markdown
Raw 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.

# 架构对比分析:读书 vs ReadViewSDK
> 基于读书 v10.0.3 (Build 79) 逆向文档,与当前 ReadViewSDK 代码在 2026-05-24 的核查结果整合。
> 本文档已吸收原 [WXRead剩余问题修复计划.md](/Users/shen/Work/Code/ReadViewSDK/Doc/WXRead剩余问题修复计划.md) 的阶段方案,后续以本文档作为单一真值。
> 标注说明:
> - `✅ 已实现`:当前代码已经按接近 WXRead 的路径落地
> - `⚠️ 有差异/有问题`:已经实现一部分,但仍与 WXRead 有结构差异,或仍有已知问题
> - `❌ 未实现`:当前代码中仍缺失
> - `❌ 明确不实现`:经确认不纳入当前 EPUB 阅读器复刻范围
---
## 核心结论
ReadViewSDK 当前已经不是“旧 UITextView 阅读器”了,文本主链路已经收口到:
- CoreText 页面直绘
- `RDEPUBTextLayouter` 分页
- 5 层 CSS 级联
- `<link>` 样式表内联
- 页面级 hit test / 选区 / 高亮 / 批注
- 字符锚点与 `fileIndex/row/column` 语义的完整位置模型
核查结论在当前约定范围内ReadViewSDK 已经完成 EPUB 阅读器对 WXRead 文档主链路的复刻。当前文档里不再保留主链路级 `⚠️` 项,剩余仅有两类:
1. `replaceForMPChapter.css` 这类公众号文章专用资源,对 EPUB 主链路不适用
2. 繁简转换、TTS / DRM / Pencil 这类已明确排除在本次复刻范围之外的外围能力
---
## 核查摘要
### ✅ 已实现
- 文本页已经改成页面级 CoreText 直绘。
- `RDEPUBTextLayouter` 已接入 `RDEPUBTextBookBuilder` / `RDPlainTextBookBuilder`
- 4 级语义断页、`avoidPageBreakInside` 页尾回退、分页缓存都已经落地。
- 5 层 CSS 级联和 EPUB `<link>` 外部样式表内联都已经落地。
- CoreText 页面 hit test、长按选区、菜单锚点、复制/高亮/批注主链路已经接入页面几何。
- CoreText 路径的高亮、注释、搜索命中已经走页面装饰层,而不是继续改正文布局真值。
- WebView 路径的标注绘制、搜索高亮已经改成“JS 产出 rect原生 overlay 负责 CGContext 绘制”,不再依赖 DOM 包裹着色。
- 分页器已经补上 inline footnote attachment 不整段挪页、标题 `keepWithNext`、`weread-page-relate` 页首借行这几类 WXRead 风格规则。
- 章节尾部“仅空白/段落分隔符”的尾页丢弃,以及极短尾页回并已经落地,`宝山辽墓材料与释读` 第 31 页空白问题已修复。
- `RDEPUBTextLayoutConfig` 已补齐到 WXRead 同级配置面:`frameWidth/frameHeight/edgeInsets/numberOfColumns/columnGap/avoidOrphans/avoidWidows/hyphenation`,并已接入分页入口与缓存键。
- `RDEPUBChapterData` 已统一承载章节分页结果、位置查询、搜索/高亮回查与目录语义,章节模型主链路已经收口。
### ⚠️ 有差异/有问题
- 无主链路遗留项;当前仅保留明确不适用或明确不实现的范围说明。
### ❌ 未实现
- 繁简转换(明确不实现)
- TTS / DRM / Pencil明确不实现
---
## 1. 渲染路径对比
| 维度 | 读书 | ReadViewSDK | 核查 |
|------|---------|-------------|------|
| EPUB 文本渲染 | `WRPageView.drawRect:``CTFrameDraw` 到 CGContext | `RDEPUBTextContentView``RDEPUBDirectCoreTextPageView.draw(_:)` + `DTCoreTextLayoutFrame.draw(in:)` 页面级直绘 | ✅ 已实现 |
| WebView 路径 | WKWebView公众号/文集文章) | WKWebViewinteractive/fixed-layout EPUB | ✅ 已实现 |
| 文本选区 | `CTLineGetStringIndexForPosition` 坐标级 hit test | `RDEPUBPageInteractionController` + `RDEPUBSelectionOverlayView` 已接入主链路 | ✅ 已实现 |
| 标注绘制 | `CTFrame` 层叠加绘制CGContext | CoreText / WebView 两条链路都已收口到原生页面装饰层绘制 | ✅ 已实现 |
| 搜索高亮 | `WRCoreTextLayoutFrame.highlightSearchResults:` 直接绘制 | CoreText / WebView 两条链路都已统一为原生页面装饰对象绘制 | ✅ 已实现 |
**结论:** 渲染层里“页面级绘制 + 页面装饰对象收口”这一块已经完成,页面几何回查也已经补到与 WXRead 同一路径的页面快照闭环。
---
## 2. 分页引擎对比
| 维度 | 读书 | ReadViewSDK | 核查 |
|------|---------|-------------|------|
| 分页核心 | `WRCoreTextLayouter` + `WRCoreTextLayoutFrame` | `RDEPUBTextLayouter` + `RDEPUBTextLayoutFrame` | ✅ 已实现 |
| 断页策略 | 4 级语义断页 | 已启用 4 级语义断页 | ✅ 已实现 |
| `avoidPageBreakInside` | 页尾最多回退若干行避免破碎 | 已实现页尾最多回退 3 行 | ✅ 已实现 |
| inline footnote | 行内脚注不应触发整段挪页 | 已修正为仅块级 attachment 参与整块挪页 | ✅ 已实现 |
| 标题 keep-with-next | 标题不能孤悬页尾 | 已补 `keepWithNext` 语义与页尾回退 | ✅ 已实现 |
| `weread-page-relate` | 页首关联块需要借上一页一行 | 已补页首 `pageRelate` 借行规则 | ✅ 已实现 |
| 章节尾页收口 | 丢弃空白尾页、合并极短尾页 | 已补尾页空白丢弃与超短尾页回并 | ✅ 已实现 |
| 分页配置 | `WRCoreTextLayoutConfig`(含多栏等) | `RDEPUBTextLayoutConfig` 已补齐同级参数,并接入分页入口/缓存键/列路径构建 | ✅ 已实现 |
| 缓存 | 按书籍 + 排版设置缓存 | 已有 `RDEPUBTextBookCache` 磁盘缓存 | ✅ 已实现 |
**结论:** 分页主链路已经按 WXRead 收口,当前差异不再落在分页引擎或分页配置能力面上。
---
## 3. CSS 处理对比
| 维度 | 读书 | ReadViewSDK | 核查 |
|------|---------|-------------|------|
| CSS 级联层级 | 5 级:`default < replace < dark < epub < user` | `RDEPUBTextStyleSheetPackage` 已实际生成并注入 5 | 已实现 |
| EPUB `<link>` CSS | 解析前级联合并外部样式 | 已实现抽取内联URL 重写与诊断 | 已实现 |
| 自定义 CSS 属性 | `wr-vertical-center-style`、`weread-page-relate`、断页相关私有属性 | 已按 WXRead 语义接入 `wr-vertical-center-style`、`weread-page-relate`、`page-break-* / break-*`、`avoidPageBreakInside` attachment placement | 已实现 |
| WXRead 私有 CSS 文件 | 使用 WeRead 自带 `default/replace/dark/...` | 已把 `default/replace/dark` 作为 SDK 内置资源镜像注入 5 层级联 | 已实现 |
| `replaceForLatinLanguageBook.css` | 拉丁语言专项字体规则 | 已按章节语言 / 正文拉丁字符占比自动切换 Latin replace | 已实现 |
**结论:** CSS 主机制私有资源层和拉丁语言分支都已经按 WXRead 路径收口这一节当前不再是剩余差距
---
## 4. 位置模型对比
| 维度 | 读书 | ReadViewSDK | 核查 |
|------|---------|-------------|------|
| 主模型 | `WREpubPositionConverter` `(fileIndex, row, column)` | `RDEPUBTextPositionConverter` + `RDEPUBTextAnchor/rangeAnchor`已补齐全书字符位置与页码双向转换 | 已实现 |
| 恢复精度 | 字符级双向恢复 | 当前位置选区高亮搜索命中都已优先走 `rangeAnchor` / `fileIndex-row-column` 恢复`progression` 仅作回退 | 已实现 |
| 旧数据兼容 | 兼容历史位置模型 | 已兼容旧 `spineIndex` 等旧字段解码 | 已实现 |
| 全量双向转换 | 文件位置 <-> 全书字符位置 <-> 页码 | `RDEPUBTextPositionConverter` / `RDEPUBTextIndexTable` 已补齐 `fileIndex,row,column <-> chapterOffset <-> globalOffset <-> pageNumber <-> location` | ✅ 已实现 |
**结论:** 位置模型这条链路已经按 WXRead 的 `PositionConverter` 思路收口,当前不再是位置恢复能力缺失的问题。
---
## 5. 章节数据模型对比
| 维度 | 读书 | ReadViewSDK | 核查 |
|------|---------|-------------|------|
| 核心模型 | `WRChapterData` 一体化承载渲染结果 + 标注 + 搜索 + 目录 | `RDEPUBChapterData` 现已统一承载章节分页结果、位置查询、搜索/高亮回查与目录语义 | ✅ 已实现 |
| 页内高亮查询 | 章节对象直接提供 | `RDEPUBChapterData.highlights(on:from:)` 已提供 | ✅ 已实现 |
| 页内搜索查询 | 章节对象直接提供 | `RDEPUBChapterData.searchResults(on:from:)` 已提供 | ✅ 已实现 |
| 页码/位置查询 | 章节对象内聚 | `RDEPUBChapterData` 已统一提供 chapter/page/location/searchMatch 双向回查 | ✅ 已实现 |
| 目录与章节语义 | 基于章节数据统一管理 | 已由 `RDEPUBChapterData` 统一提供 TOC 命中、主目录项解析与章节页码定位 | ✅ 已实现 |
**结论:** 章节对象这条链路已经按 WXRead 的 `WRChapterData` 思路收口,章节分页、位置、搜索、高亮与目录语义现在都围绕 `RDEPUBChapterData` 统一组织。
---
## 6. 翻页控制器与宿主层对比
| 维度 | 读书 | ReadViewSDK | 核查 |
|------|---------|-------------|------|
| 翻页动画 | curl / slide / fade / none | 已有多种翻页模式 | ✅ 已实现 |
| `UIPageViewController` crash patch | 3 个以上专项 patch | 已补 pageCurl 异常检测、转场期间跳转排队、动画后校验与异步重建恢复 | ✅ 已实现 |
| 预加载 | `WRForecastUtils` 预测 + 后台准备 | 已围绕当前页、当前 spread 和可见方向预热相邻页视图,并在布局环境变化时裁剪缓存 | ✅ 已实现 |
| 预测翻页 | 基于用户方向预测预建内容 | 已按手势/滚动方向和 pending target 预测下一屏,优先向预测方向额外预热一屏 | ✅ 已实现 |
| 显示切换一致性 | 翻页模式/单双页/方向切换稳定恢复 | 已补切换前位置快照、切换后按 location 恢复,以及横竖屏过渡期间的延迟恢复链路 | ✅ 已实现 |
**结论:** 翻页控制器与宿主层这条链路已经按 WXRead 的主实现思路收口pageCurl 稳定性、预测预加载和显示切换恢复现在都走统一闭环。
---
## 7. 资源体系对比
### CSS
| 文件 | 读书职责 | ReadViewSDK 状态 | 核查 |
|------|-------------|-----------------|------|
| `default.css` | 基础 HTML 标签样式 | 已以内置资源镜像接入 | ✅ 已实现 |
| `replace.css` | 标题、图片、引用、分页控制 | 已以内置资源镜像接入 | ✅ 已实现 |
| `dark.css` | 暗色主题 | 已以内置资源镜像接入,并保留主题色覆盖层 | ✅ 已实现 |
| `replaceForLatinLanguageBook.css` | 拉丁语言字体 | 已接入章节语言自动切换 | ✅ 已实现 |
| `replaceForMPChapter.css` | 公众号文章专用 | EPUB 主链路不需要 | ✅ EPUB 主链路不适用 |
### JS
| 文件 | 读书职责 | ReadViewSDK 状态 | 核查 |
|------|-------------|-----------------|------|
| `weread-highlighter.js` | Web 高亮引擎 | `epub-bridge.js` 现只负责 rect 解析与桥接,最终由原生 overlay 绘制 | ✅ 已实现 |
| `rangy-*` | 选区/高亮库 | CoreText 路径不需要;`webInteractive` / `webFixedLayout` 已接入 `rangy-core.js` + `rangy-serializer.js` 等价层,统一负责 DOM range 序列化与 iframe 文档回放 | ✅ 已实现 |
| `cssInjector.js` | 动态 CSS 注入 | 已接入 `cssInjector.js`,由 `WeReadApi``webInteractive` / `webFixedLayout` 路径按需向主文档和 iframe 文档注入主题/分页样式 | ✅ 已实现 |
| `WeReadApi.js` | JS-Native 桥接 | 已接入 `WeReadApi.js`,并由 `window.WeReadApi` 统一封装分页、主题、搜索、高亮和 progression bridge | ✅ 已实现 |
**结论:** CoreText 路径不需要 `rangy` / `cssInjector` / `WeReadApi`;但 `webInteractive``webFixedLayout` 两条 Web 路径都需要。当前资源体系已经把这套 Web 资源层完整接回 SDKJS 侧职责也已按 WXRead 思路收口。
---
## 8. 缺失能力清单
| 能力 | 核查 | 当前优先级 |
|------|------|-----------|
| 页面几何模型完全等价 `WRCoreTextLayoutFrame` | ✅ 已实现 | - |
| `WRBookmark` 统一标注模型 | ✅ 已实现 | - |
| 多栏排版 | ✅ 已实现 | - |
| 字体动态加载 | ✅ 已实现 | - |
| 繁简转换 | ❌ 明确不实现 | - |
| TTS / DRM / Pencil | ❌ 明确不实现 | - |
---
## 9. 收口路线(整合原修复计划)
### P1页面几何与分页行为闭环
- `RDEPUBPageLayoutSnapshot` 已补齐 line/run/attachment/contentBounds 与 absoluteRange 命中闭环
- overlay / decoration / selection 回查已经统一到页面快照层
- 问题书分页细节已回收到现有分页规则,不再构成架构缺口
当前状态:`✅ 已实现`
### P2位置模型与章节数据内聚
- `rangeAnchor` / `fileIndex/row/column` 双向位置转换已完成
- `RDEPUBChapterData` 章节语义内聚已完成
- `RDEPUBAnnotation` 已把书签/高亮统一收口到单一标注语义层
当前状态:`✅ 已实现`
### P3宿主层稳定性
- 宿主层 pageCurl 修复、预测预加载和显示切换恢复已完成
- 剩余工作不再是主链路缺失,而是问题书和极端交互场景的持续回归
当前状态:`✅ 已实现`
### P4外围能力
- 多栏阅读器开关 / UI 暴露已完成
- EPUB 内嵌字体动态注册已完成
- 繁简转换、TTS / DRM / Pencil 明确不实现,不纳入收口范围
当前状态:`✅ 范围内已实现`
---
## 10. 读书关键类职责速查
| 类名 | 职责 | ReadViewSDK 对应 | 核查 |
|------|------|-----------------|------|
| `WRReaderViewController` | 阅读器主控制器 | `RDEPUBReaderController` | ✅ 已有对应 |
| `WRPageViewController` | 翻页控制器 + crash patch | `RDReaderView` | ✅ 已实现 |
| `WRPageView` | CoreText 直接绘制页面 | `RDEPUBTextContentView` + `RDEPUBDirectCoreTextPageView` | ✅ 已实现 |
| `WREpubTypesetter` | HTML → NSAttributedStringCSS 级联) | `RDEPUBDTCoreTextRenderer` | ✅ 已实现 |
| `WRCoreTextLayouter` | CoreText 排版引擎 | `RDEPUBTextLayouter` | ✅ 已实现 |
| `WRCoreTextLayoutFrame` | 排版帧(绘制/选区/搜索/装饰) | `RDEPUBTextLayoutFrame` + snapshot/interaction/overlay | ✅ 已实现 |
| `WRChapterData` | 章节数据模型 | `RDEPUBChapterData` | ✅ 已实现 |
| `WRChapterPageCount` | 分页计算 + 缓存 key | `RDEPUBTextBookBuilder` + `RDEPUBTextBookCache` | ✅ 已实现 |
| `WREpubPositionConverter` | 字符级位置双向转换 | `RDEPUBTextPositionConverter` + `RDEPUBTextIndexTable` | ✅ 已实现 |
| `WRBookmark` | 标注统一模型 | `RDEPUBAnnotation`(兼容 `RDEPUBHighlight` / `RDEPUBBookmark` | ✅ 已实现 |
| `DTHTMLAttributedStringBuilder` | HTML DOM → NSAttributedString | 同(复用 DTCoreText | ✅ 已实现 |
---
## 11. 当前数据流
```text
EPUB 文件
-> RDEPUBParser.parse (container.xml -> OPF -> spine)
-> readingProfile 分流:
textReflowable:
-> RDEPUBDTCoreTextRenderer
-> 5 层 CSS 级联
-> <link> CSS 内联
-> 自定义分页语义注入
-> RDEPUBTextBookBuilder
-> RDEPUBTextLayouter
-> RDEPUBTextBookCache
-> RDEPUBTextContentView
-> RDEPUBDirectCoreTextPageView
-> RDEPUBPageInteractionController
-> RDEPUBSelectionOverlayView
webInteractive:
-> RDEPUBPaginator
-> RDEPUBWebContentView
-> rangy-core.js / rangy-serializer.js
-> cssInjector.js
-> WeReadApi.js
-> epub-bridge.js
webFixedLayout:
-> RDEPUBWebContentView
-> rangy-core.js / rangy-serializer.js
-> cssInjector.js
-> WeReadApi.js
-> epub-bridge.js
```
---
*分析基础:读书 v10.0.3 (Build 79) 逆向文档*
*当前代码核查日期2026-05-24*