Files
ReadViewSDK/Sources/RDPDFReaderView
shenlei 95cead5863 修复 PDF 阅读交互稳定性并统一项目技能管理
PDF 阅读器在慢速双指缩放、竖向滚动页高异步更新、页面请求超时和绘画橡皮擦等场景中,存在视口跳动、迟到结果被错误丢弃、缓存边界不明确及笔迹显示与持久化不同步的问题;同一本书的标注读取和并发写入也会产生不必要的磁盘访问或覆盖风险。\n\n调整缩放 inset 计算和竖向阅读锚点恢复,避免缩放变换被重复计入、真实页高到达时改变当前阅读位置。页面请求改为带 token 的超时重试机制,可在缓存窗口内接收有效迟到结果并提供失败重试入口;页面大图、OCR、笔迹和描述缓存统一按当前页前后两页收敛,PDF 标识改为完整内容 SHA-256,避免同名或相近文件复用错误阅读状态。\n\n绘画会话内按路径实时重绘,退出会话后使用按图层派生的位图缓存,确保橡皮擦即时作用于已提交笔迹;同时为笔迹持久化增加版本控制、为标注读写增加同步保护和内存快照,降低复用与并发场景下的状态错乱。\n\n将项目技能统一迁入 .agents/skills,并以 .claude/skills 相对软链接供 Claude Code 读取;新增详细 Git 提交技能,自动审查改动、生成中文提交说明并约束安全推送。

验证:所有项目技能通过 quick_validate;执行 xcodebuild -workspace ReadViewDemo/ReadViewDemo.xcworkspace -scheme ReadViewDemo -configuration Debug -sdk iphonesimulator CODE_SIGNING_ALLOWED=NO build,构建成功。
2026-07-24 14:40:02 +09:00
..

RDPDFReaderView

独立的 UIKit PDF 阅读交互 SDK。当前第一阶段只包含与业务无关的部分:分页、双指缩放、双击缩放、放大后拖动,以及画笔模式下的手势隔离。

主工程的下载、解密、缓存、链接、标注和持久化仍由现有 PDF Feature 管理;后续通过适配层逐步迁移,避免把业务问题和手势问题混在一起。

PDF 数据来源

普通 PDF 可以由 SDK 使用 PDFKit 直接解析:

let reader = try RDPDFReaderViewController(
    pdfURL: fileURL,
    bookIdentifier: stableBookID,
    password: standardPDFPassword,
    persistence: persistence,
    annotationPersistence: annotationStore
)

自定义加密 PDF 继续由宿主解密并提供页面图片,不需要把原始文件交给 SDK:

let reader = RDPDFReaderViewController(
    pageProvider: encryptedImageProvider,
    persistence: persistence,
    annotationPersistence: annotationStore
)

两种入口最终都转换为 RDPDFReaderPageProvider,共用翻页、缩放、目录、书签、OCR、标注和画笔功能。内置 PDFKit 数据源按需渲染页面、限制最大图片尺寸并使用内存缓存;能够读取的原生 PDF 文字会直接用于选择和标注,图片扫描页则按配置回退到 OCR。

调试入口

在任意测试宿主中 push RDPDFReaderDebugViewController()

navigationController?.pushViewController(RDPDFReaderDebugViewController(), animated: true)

验证顺序:

  1. 双指捏合能连续放大和缩小。
  2. 双击能在适配尺寸与两倍缩放之间切换。
  3. 放大后单指只能拖动内容,不能翻页。
  4. 切到“画笔模式”后,单指不再翻页,双指仍能缩放和拖动。

如果这个独立页面工作正常,而主阅读页仍失效,问题就能确定在主工程的页面层/覆盖层,而不是缩放内核。

图片型 PDF 的文本、复制与标注

主程序即使只能提供每页图片,也可以接入文字功能:

  1. 若主程序已有 PDF 解析结果,在 RDPDFReaderPageDescriptor.textRuns 中传入文字和相对图片的 0...1 坐标;这条路径提供最准确的复制和高亮。
  2. 若没有文字坐标,使用 RDPDFReaderImageTextRecognizer 对当前页图片按需 OCR,再把结果赋给 RDPDFReaderImageTextLayerView.textRuns
  3. OCR 也不可用时,文字层会提供区域框选;区域标注只显示“高亮、注释”,不会错误地提供复制。

高亮与注释统一使用 RDPDFReaderAnnotation,坐标同样是相对图片的 0...1 比例,缩放、旋转或重新渲染页面后仍能对齐。使用 RDPDFReaderPersistenceStore 保存时,请传入宿主稳定的书籍 ID(可附账号和内容版本)对应的目录,并对 addAnnotationupdateAnnotationdeleteAnnotationthrows 结果做错误提示;文件损坏或版本不兼容时 SDK 会拒绝覆盖原数据。