# 架构对比分析:读书 vs ReadViewSDK > 基于读书 v10.0.3 (Build 79) 逆向文档,与当前 ReadViewSDK 代码在 2026-06-02 的核查结果整合。 > 本文档已吸收原 [WXRead剩余问题修复计划.md](/Users/shen/Work/Code/ReadViewSDK/Doc/WXRead剩余问题修复计划.md) 的阶段方案,后续以本文档作为单一真值。 > 标注说明: > - `✅ 已实现`:当前代码已经按接近 WXRead 的路径落地 > - `⚠️ 有差异/有问题`:已经实现一部分,但仍与 WXRead 有结构差异,或仍有已知问题 > - `❌ 未实现`:当前代码中仍缺失 > - `❌ 明确不实现`:经确认不纳入当前 EPUB 阅读器复刻范围 --- ## 核心结论 ReadViewSDK 当前已经不是“旧 UITextView 阅读器”了,文本主链路已经收口到: - CoreText 页面直绘 - `RDEPUBTextLayouter` 分页 - 5 层 CSS 级联 - `` 样式表内联 - 页面级 hit test / 选区 / 高亮 / 批注 - 字符锚点与 `fileIndex/row/column` 语义的完整位置模型 核查结论:ReadViewSDK 已经完成 EPUB 阅读器主链路的大部分复刻,但当前代码里仍有少量“能力面已接入、实现路径未完全等价”的差异。和 2026-05-24 版本文档相比,当前最需要重新标注的是: 1. 文本分页主路径现已真正消费多栏 path,并补上 `avoidOrphans` / `avoidWidows` / `hyphenation` 行为 2. 代码仍保留若干 fallback / degrade 路径,与 WXRead 的单一主链路实现方式不同 3. `replaceForMPChapter.css`、繁简转换、TTS / DRM / Pencil 仍属于不适用或明确不实现范围 --- ## 核查摘要 ### ✅ 已实现 - 文本页已经改成页面级 CoreText 直绘。 - `RDEPUBTextLayouter` 已接入 `RDEPUBTextBookBuilder` / `RDPlainTextBookBuilder`。 - 4 级语义断页、`avoidPageBreakInside` 页尾回退、分页缓存都已经落地。 - 5 层 CSS 级联和 EPUB `` 外部样式表内联都已经落地。 - 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`,并已接入分页入口与缓存键。 - CoreText 分页路径现已消费多栏 layout path,不再把 `numberOfColumns` 只停留在配置层。 - `avoidOrphans`、`avoidWidows`、`hyphenation` 现已接入实际排版/分页行为,而不是仅存在于配置模型。 - `RDEPUBChapterData` 已统一承载章节分页结果、位置查询、搜索/高亮回查与目录语义,章节模型主链路已经收口。 ### ⚠️ 有差异/有问题 - 仍保留降级链路:`RDEPUBDTCoreTextRenderer` 在 `DTCoreText` 不可用或构建失败时会退回 HTML 纯文本渲染;`RDURLReaderController` 在纯文本分页失败时会退回 `UITextView` 展示。这说明 ReadViewSDK 仍不是 WXRead 那种完全单一路径的生产态实现。 - `RDReaderGestureController` 仍是未接入的占位组件,实际点击分区逻辑直接落在 `RDReaderView`,与 WXRead 更完整的翻页/手势控制器拆分相比,宿主层职责仍稍偏重。 ### ❌ 未实现 - 繁简转换(明确不实现) - TTS / DRM / Pencil(明确不实现) --- ## 1. 渲染路径对比 | 维度 | 读书 | ReadViewSDK | 核查 | |------|---------|-------------|------| | EPUB 文本渲染 | `WRPageView.drawRect:` → `CTFrameDraw` 到 CGContext | `RDEPUBTextContentView` → `RDEPUBDirectCoreTextPageView.draw(_:)` + `DTCoreTextLayoutFrame.draw(in:)` 页面级直绘 | ✅ 已实现 | | WebView 路径 | WKWebView(公众号/文集文章) | WKWebView(interactive/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` 已补齐同级参数,并已接入多栏 path、孤行/寡行保护与 hyphenation 行为 | ✅ 已实现 | | 缓存 | 按书籍 + 排版设置缓存 | 已有 `RDEPUBTextBookCache` 磁盘缓存 | ✅ 已实现 | **结论:** 分页主链路已经按 WXRead 的主要思路收口;当前剩余差异不再集中在分页配置或分页算法本身,而更多落在 fallback 路径和宿主层实现细节。 --- ## 3. CSS 处理对比 | 维度 | 读书 | ReadViewSDK | 核查 | |------|---------|-------------|------| | CSS 级联层级 | 5 级:`default < replace < dark < epub < user` | `RDEPUBTextStyleSheetPackage` 已实际生成并注入 5 层 | ✅ 已实现 | | EPUB `` 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 资源层完整接回 SDK,JS 侧职责也已按 WXRead 思路收口。 --- ## 8. 缺失能力清单 | 能力 | 核查 | 当前优先级 | |------|------|-----------| | 页面几何模型完全等价 `WRCoreTextLayoutFrame` | ✅ 已实现 | - | | `WRBookmark` 统一标注模型 | ✅ 已实现 | - | | 多栏排版 | ✅ 已实现 | - | | `avoidOrphans / avoidWidows / hyphenation` 行为落地 | ✅ 已实现 | - | | 纯文本/渲染失败 fallback 清理 | ⚠️ 仍保留纯文本 fallback 路径 | 低 | | 字体动态加载 | ✅ 已实现 | - | | 繁简转换 | ❌ 明确不实现 | - | | 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 明确不实现,不纳入收口范围 当前状态:`✅ 范围内已实现` --- ## 补充说明:本次复核新增结论(2026-06-02) 和上一篇版本相比,当前最重要的修正不是“新增缺很多能力”,而是把原先写得过满的结论收回来: - `RDEPUBTextLayoutConfig` 这一轮已经从“配置面补齐”推进到“行为面落地”,`avoidOrphans`、`avoidWidows`、`hyphenation` 不再只是模型字段。 - 多栏能力这一轮已经接到文本 `CoreText` 分页主路径,`numberOfColumns` 不再只影响 Web/CSS 与设置入口。 - 文本阅读主链路虽然已经不再依赖旧 `UITextView`,但仓库中仍保留 `DTCoreText` 不可用时的纯文本 fallback,以及纯文本分页失败时的 `UITextView` fallback,应视作与 WXRead 的实现差异,而不是主链路能力。 - 公众号文章专用 `replaceForMPChapter.css` 仍不属于当前 EPUB 主链路缺口,应继续按“不适用”记录,而不是“待补齐”。 --- ## 10. 读书关键类职责速查 | 类名 | 职责 | ReadViewSDK 对应 | 核查 | |------|------|-----------------|------| | `WRReaderViewController` | 阅读器主控制器 | `RDEPUBReaderController` | ✅ 已有对应 | | `WRPageViewController` | 翻页控制器 + crash patch | `RDReaderView` | ✅ 已实现 | | `WRPageView` | CoreText 直接绘制页面 | `RDEPUBTextContentView` + `RDEPUBDirectCoreTextPageView` | ✅ 已实现 | | `WREpubTypesetter` | HTML → NSAttributedString(CSS 级联) | `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 级联 -> 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*