ReadViewSDK/Doc/架构对比分析_WXRead_vs_ReadViewSDK.md
shenlei 488350d956 docs: 大书优化方案文档与架构分析更新
新增大书优化实施方案(内存与主线程、快速进入阅读器)和 WXRead 内存策略分析文档,
更新架构对比分析文档,完善章节级缓存运行时、串行加载、轻量磁盘摘要等设计细节。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 21:16:50 +08:00

17 KiB
Raw Blame History

架构对比分析:读书 vs ReadViewSDK

基于读书 v10.0.3 (Build 79) 逆向文档,与当前 ReadViewSDK 代码在 2026-06-02 的核查结果整合。 本文档已吸收原 WXRead剩余问题修复计划.md 的阶段方案,后续以本文档作为单一真值。

标注说明:

  • ✅ 已实现:当前代码已经按接近 WXRead 的路径落地
  • ⚠️ 有差异/有问题:已经实现一部分,但仍与 WXRead 有结构差异,或仍有已知问题
  • ❌ 未实现:当前代码中仍缺失
  • ❌ 明确不实现:经确认不纳入当前 EPUB 阅读器复刻范围

核心结论

ReadViewSDK 当前已经不是“旧 UITextView 阅读器”了,文本主链路已经收口到:

  • CoreText 页面直绘
  • RDEPUBTextLayouter 分页
  • 5 层 CSS 级联
  • <link> 样式表内联
  • 页面级 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 <link> 外部样式表内联都已经落地。
  • CoreText 页面 hit test、长按选区、菜单锚点、复制/高亮/批注主链路已经接入页面几何。
  • CoreText 路径的高亮、注释、搜索命中已经走页面装饰层,而不是继续改正文布局真值。
  • WebView 路径的标注绘制、搜索高亮已经改成“JS 产出 rect原生 overlay 负责 CGContext 绘制”,不再依赖 DOM 包裹着色。
  • 分页器已经补上 inline footnote attachment 不整段挪页、标题 keepWithNextweread-page-relate 页首借行这几类 WXRead 风格规则。
  • 章节尾部“仅空白/段落分隔符”的尾页丢弃,以及极短尾页回并已经落地,宝山辽墓材料与释读 第 31 页空白问题已修复。
  • RDEPUBTextLayoutConfig 已补齐到 WXRead 同级配置面:frameWidth/frameHeight/edgeInsets/numberOfColumns/columnGap/avoidOrphans/avoidWidows/hyphenation,并已接入分页入口与缓存键。
  • CoreText 分页路径现已消费多栏 layout path不再把 numberOfColumns 只停留在配置层。
  • avoidOrphansavoidWidowshyphenation 现已接入实际排版/分页行为,而不是仅存在于配置模型。
  • RDEPUBChapterData 已统一承载章节分页结果、位置查询、搜索/高亮回查与目录语义,章节模型主链路已经收口。

⚠️ 有差异/有问题

  • 仍保留降级链路:RDEPUBDTCoreTextRendererDTCoreText 不可用或构建失败时会退回 HTML 纯文本渲染;RDURLReaderController 在纯文本分页失败时会退回 UITextView 展示。这说明 ReadViewSDK 仍不是 WXRead 那种完全单一路径的生产态实现。
  • RDReaderGestureController 仍是未接入的占位组件,实际点击分区逻辑直接落在 RDReaderView,与 WXRead 更完整的翻页/手势控制器拆分相比,宿主层职责仍稍偏重。

未实现

  • 繁简转换(明确不实现)
  • TTS / DRM / Pencil明确不实现

1. 渲染路径对比

维度 读书 ReadViewSDK 核查
EPUB 文本渲染 WRPageView.drawRect:CTFrameDraw 到 CGContext RDEPUBTextContentViewRDEPUBDirectCoreTextPageView.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 已补齐同级参数,并已接入多栏 path、孤行/寡行保护与 hyphenation 行为 已实现
缓存 按书籍 + 排版设置缓存 已有 RDEPUBTextBookCache 磁盘缓存 已实现

结论: 分页主链路已经按 WXRead 的主要思路收口;当前剩余差异不再集中在分页配置或分页算法本身,而更多落在 fallback 路径和宿主层实现细节。


3. CSS 处理对比

维度 读书 ReadViewSDK 核查
CSS 级联层级 5 级:default < replace < dark < epub < user RDEPUBTextStyleSheetPackage 已实际生成并注入 5 层 已实现
EPUB <link> CSS 解析前级联合并外部样式 已实现抽取、内联、URL 重写与诊断 已实现
自定义 CSS 属性 wr-vertical-center-styleweread-page-relate、断页相关私有属性 已按 WXRead 语义接入 wr-vertical-center-styleweread-page-relatepage-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,由 WeReadApiwebInteractive / webFixedLayout 路径按需向主文档和 iframe 文档注入主题/分页样式 已实现
WeReadApi.js JS-Native 桥接 已接入 WeReadApi.js,并由 window.WeReadApi 统一封装分页、主题、搜索、高亮和 progression bridge 已实现

结论: CoreText 路径不需要 rangy / cssInjector / WeReadApi;但 webInteractivewebFixedLayout 两条 Web 路径都需要。当前资源体系已经把这套 Web 资源层完整接回 SDKJS 侧职责也已按 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 这一轮已经从“配置面补齐”推进到“行为面落地”,avoidOrphansavoidWidowshyphenation 不再只是模型字段。
  • 多栏能力这一轮已经接到文本 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 → 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. 当前数据流

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