445 lines
34 KiB
Markdown
445 lines
34 KiB
Markdown
# 读书 EPUB 阅读器 — 核心架构与数据流图
|
|
|
|
> 目标: WeRead v10.0.3 (Build 79)
|
|
|
|
---
|
|
|
|
## 一、模块拓扑与依赖关系图
|
|
|
|
### 1.1 App 整体模块拓扑
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ WeRead.app (iOS/macOS Catalyst) │ │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────────────┐ │
|
|
│ │ WeRead │ │
|
|
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ │
|
|
│ │ │ 阅读器模块 │ │ 书架模块 │ │ 其他业务模块 │ │ │
|
|
│ │ │ WRReader* │ │ WRBookshelf* │ │ WRDiscover/WRMarket │ │ │
|
|
│ │ │ WREpub* │ │ WRBook* │ │ WRAccount/WRSetting │ │ │
|
|
│ │ │ DTCoreText* │ │ │ │ WRCommunity/WRChat │ │ │
|
|
│ │ │ WRPage* │ │ │ │ WRActivity/WRAI │ │ │
|
|
│ │ │ WRChapter* │ │ │ │ ... │ │ │
|
|
│ │ └──────────────┘ └──────────────┘ └──────────────────────┘ │ │
|
|
│ │ ┌──────────────────────────────────────────────────────────┐│ │
|
|
│ │ │ ObjC 元数据 (未剥离): ││ │
|
|
│ │ │ __objc_classlist: 0xb230 (类列表) ││ │
|
|
│ │ │ __objc_classname: 0x25a35 (~154KB, 17584 个类名) ││ │
|
|
│ │ │ __objc_methname: 0x24ba5a (~2.4MB 方法名) ││ │
|
|
│ │ │ __objc_methtype: 0x382bc (~226KB 类型编码) ││ │
|
|
│ │ └──────────────────────────────────────────────────────────┘│ │
|
|
│ └──────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────── Frameworks ────────────────────────────┐ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
|
|
│ │ │ hermes.framework│ │QMUIKit.fwk │ │WRSharedMod* │ │ │
|
|
│ │ │ (RN JS 引擎) │ │(腾讯UI组件库) │ │(共享业务模块) │ │ │
|
|
│ │ │ v0.12.0 │ │ │ │ │ │ │
|
|
│ │ │ Facebook Hermes │ │ QMUI 配色/ │ │ 书架/发现/ │ │ │
|
|
│ │ │ 替代 JSC │ │ 主题/组件 │ │ 社区/活动 │ │ │
|
|
│ │ └─────────────────┘ └──────────────┘ └──────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────┐ ┌──────────────┐ │ │
|
|
│ │ │ WRUICore.fwk │ │CocoaMarkdown │ │ │
|
|
│ │ │ (UI核心+字体) │ │(Markdown渲染)│ │ │
|
|
│ │ │ 含 WeReadLS 系列│ │ │ │ │
|
|
│ │ │ 含 SharpGrotesk │ │ │ │ │
|
|
│ │ └─────────────────┘ └──────────────┘ │ │
|
|
│ └────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────── RNBundles (39个 .hbc) ─────────────────┐ │
|
|
│ │ aiSearch bookDetail browse community discoverV2 market │ │
|
|
│ │ account medals memberDetail gameCenterHome freeBooks ... │ │
|
|
│ │ (Hermes 编译的 HBC 字节码, 业务动态化) │ │
|
|
│ └────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────── Bundles ────────────────────────────────┐ │
|
|
│ │ OnePatch.bundle (ObjC热修复, JS驱动) │ │
|
|
│ │ MidasIAPSDK.bundle (腾讯米大师支付) │ │
|
|
│ │ Sentry.bundle (崩溃监控) │ │
|
|
│ │ QCloudCOSXML.bundle (腾讯云COS存储) │ │
|
|
│ │ MJRefresh.bundle (下拉刷新) │ │
|
|
│ │ mathFonts.bundle (数学字体: Latin Modern/XITS/TeX Gyre) │ │
|
|
│ └────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────── App Extensions ─────────────────────────┐ │
|
|
│ │ ActionExtension.appex (操作扩展) │ │
|
|
│ │ ModernWidgetExtension.appex (新版小组件 WidgetKit) │ │
|
|
│ │ NotificationService.appex (通知服务) │ │
|
|
│ │ ShareExtension.appex (分享扩展) │ │
|
|
│ │ Widget.appex (旧版小组件) │ │
|
|
│ └────────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
系统框架依赖:
|
|
┌────────────────────────────────────────────────────────────┐
|
|
│ CoreText CTTypesetter / CTFramesetter / CTFrame │
|
|
│ CTLine / CTRun / CTFontCreatePathForGlyph │
|
|
│ CoreGraphics CGContext / CGPath / CGAffineTransform │
|
|
│ UIKit UIView / UIPageViewController / Gesture │
|
|
│ WebKit WKWebView (仅公众号/文集路径) │
|
|
│ Foundation NSAttributedString / NSXMLParser │
|
|
│ Security Keychain (加密密钥存储) │
|
|
│ AVFoundation TTS 朗读音频播放 │
|
|
│ PencilKit Apple Pencil 手写笔记 │
|
|
│ ImageIO 图片解码与缓存 │
|
|
└────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 1.2 EPUB 渲染模块内部依赖图
|
|
|
|
```
|
|
WRReaderViewController (431 methods, 阅读器主控制器)
|
|
│
|
|
├─→ WRPageViewController (80 methods, 翻页控制器)
|
|
│ │ 基于 UIPageViewController 封装
|
|
│ │ 支持 UIPageCurl (仿真翻页) / Scroll (左右滑动)
|
|
│ │ 包含 4 个故障修复补丁
|
|
│ │
|
|
│ └─→ WRPageView (105 methods, 页面渲染视图)
|
|
│ │ 继承 UIView, drawRect: 中直接 CGContext 绘制
|
|
│ │ 不使用 UILabel / UITextView
|
|
│ │
|
|
│ ├─→ WRCoreTextLayoutFrame (4 methods, 单页排版帧)
|
|
│ │ │ drawInContext:image:size:inRect:position:
|
|
│ │ │ avoidPageBreakInsideByRemovingLastLinesIfNeeded
|
|
│ │ │ getRenderHeight / lines
|
|
│ │ │
|
|
│ │ └─→ DTCoreTextLayoutFrame (56 methods, DTCoreText 排版帧)
|
|
│ │ │ 封装 CTFrame, 提取 CTLine 列表
|
|
│ │ │ hitTestWithPoint: (文本选择)
|
|
│ │ │
|
|
│ │ └─→ DTCoreTextLayoutLine (61 methods, 排版行)
|
|
│ │ │ 封装 CTLine, 提取 CTRun 列表
|
|
│ │ │ typographicBounds / trailingWhitespaceWidth
|
|
│ │ │
|
|
│ │ └─→ DTCoreTextGlyphRun (23 methods, 字形渲染)
|
|
│ │ │ 封装 CTRun
|
|
│ │ └─→ newPathWithGlyphs (CTFontCreatePathForGlyph)
|
|
│ │
|
|
│ └─→ 文本选择 (CoreText hit test)
|
|
│ CTLineGetStringIndexForPosition (坐标→字符索引)
|
|
│ CTLineGetOffsetForStringIndex (字符索引→坐标)
|
|
│
|
|
├─→ WRChapterData (125 methods, 章节数据模型)
|
|
│ │ 存储排版后的 NSAttributedString
|
|
│ │ 管理高亮/下划线/书评标注
|
|
│ │
|
|
│ ├─→ WRCoreTextLayouter (20 methods, WeRead CoreText 封装)
|
|
│ │ │ 管理 CTTypesetter / CTFramesetter
|
|
│ │ │ pageBackgroundImageAtRange:themeBgColor:
|
|
│ │ │ resizedImageForImagePath:rect:position:sizePattern:darkMode:themeBgColor:
|
|
│ │ │
|
|
│ │ └─→ DTCoreTextLayouter (12 methods, DTCoreText 排版器)
|
|
│ │ │ 封装 CTTypesetter, 缓存 DTCoreTextLayoutFrame
|
|
│ │ │
|
|
│ │ └─→ CTTypesetter / CTFramesetter (系统 CoreText)
|
|
│ │
|
|
│ └─→ WRChapterPageCount (40 methods, 分页计算)
|
|
│ rangeValueWithPageInfo: (计算每页 NSRange)
|
|
│ currentCacheKeyWithBookId: (缓存键)
|
|
│
|
|
├─→ WREpubTypesetter (9 methods, EPUB 排版器入口)
|
|
│ │ attributeStringWithFilePath:... (核心类方法)
|
|
│ │
|
|
│ └─→ DTHTMLAttributedStringBuilder (25 methods, HTML→NSAttributedString)
|
|
│ │ _buildString (核心构建)
|
|
│ │ parser:didStartElement:attributes:position: (SAX 回调)
|
|
│ │ parser:foundCharacters:position:
|
|
│ │ parserDidEndDocument:
|
|
│ │
|
|
│ ├─→ DTHTMLParser (19 methods, HTML SAX 解析器)
|
|
│ │ 基于 libxml2 封装
|
|
│ │
|
|
│ ├─→ DTHTMLElement (168 methods, HTML 元素模型)
|
|
│ │ │ applyStyleDictionary:isLatinLanguageBook: (CSS 应用)
|
|
│ │ │ attributedString (生成富文本)
|
|
│ │ │ interpretAttributes (属性解析)
|
|
│ │ │
|
|
│ │ ├─→ DTCoreTextFontDescriptor (字体描述)
|
|
│ │ ├─→ DTCoreTextParagraphStyle (段落样式)
|
|
│ │ ├─→ DTCSSStylesheet (CSS 样式表)
|
|
│ │ └─→ DTTextAttachment (附件: 图片/视频/iframe)
|
|
│ │
|
|
│ └─→ CSS 级联: default.css → replace.css → dark.css → epub内嵌 → 用户设置
|
|
│
|
|
├─→ WREpubParser (12 methods, EPUB 文件解析)
|
|
│ │ 解析 container.xml / content.opf / toc.ncx
|
|
│ │ 输出: 章节列表 + 资源映射
|
|
│ └─→ WREpubPositionConverter (22 methods, 位置转换)
|
|
│ 文件位置 ↔ 字符位置 映射
|
|
│
|
|
├─→ WRChapterDownloadManger (47 methods, 章节下载)
|
|
│ │ RAC 任务队列 + 并发控制
|
|
│ │
|
|
│ ├─→ WRBookNetwork (155 methods, 网络层)
|
|
│ │ │ loadTarForEpubBookId:chapter:isPreload: (下载加密 ZIP)
|
|
│ │ │ handleUnzipWithBookId:zipPath:encryptKey:plainBookDirectory: (解密解压)
|
|
│ │ │ processEncryptedBookFileAtPath:encryptKey:book:chapterUid: (文件处理)
|
|
│ │ │ fileContentWithChapter:book:shouldRemoveHtmlTags: (读取内容)
|
|
│ │ │
|
|
│ │ └─→ WREncryptedFileManager (7 methods, DRM 管理)
|
|
│ │ decryptContentsOfFile:forBookId:isFileLost: (AES 解密)
|
|
│ │ encryptFileForBookId:originalEncryptKey:atPath:toPath: (本地加密)
|
|
│ │ keyForBookId: (密钥管理)
|
|
│ │
|
|
│ └─→ WRPreloadBookManager (76 methods, 预加载管理)
|
|
│ saveEncryptKey:forPath:bookId: (密钥缓存)
|
|
│ _preloadWholeBook:scene: (整书预加载)
|
|
│
|
|
├─→ 标注系统
|
|
│ ├─→ WRPageHighlight (3 methods, 高亮)
|
|
│ ├─→ WRPageUnderline (10 methods, 下划线: solid/dashed/wavy/dotted)
|
|
│ ├─→ WRPageMark (25 methods, 书签标注)
|
|
│ ├─→ WRBookmark (58 methods, 书签模型)
|
|
│ └─→ WRReaderPencilNoteManager (11 class methods, Pencil 笔记)
|
|
│
|
|
└─→ 附件系统 (WRPageAttachments)
|
|
├─→ WRPageImageAttachment (27 methods, 图片附件)
|
|
├─→ WRPageHyperlinksAttachment (超链接)
|
|
├─→ WRPageChapterToolAttachment (章节工具)
|
|
├─→ WRPageFlyleafAttachment (扉页)
|
|
├─→ WRPageCodeView (代码块)
|
|
├─→ WRPageVideoView (视频)
|
|
└─→ WRPageTableAttachment (表格)
|
|
```
|
|
|
|
---
|
|
|
|
## 二、核心业务数据流图 (DFD)
|
|
|
|
### 2.1 EPUB 内容数据流 (服务器 → 屏幕像素)
|
|
|
|
```
|
|
┌──────────┐ HTTPS ┌──────────────────────────────────────────────────┐
|
|
│ 读书 │─────────────→│ ① WRBookNetwork.loadTarForEpubBookId:chapter: │
|
|
│ 服务器 │ 加密 ZIP │ isPreload: │
|
|
│ │ {bookId}_ │ ↓ │
|
|
│ │ DECRYPT.zip │ ② WRBookNetwork.handleUnzipWithBookId: │
|
|
│ │ │ zipPath:encryptKey:plainBookDirectory: │
|
|
│ │ │ ↓ │
|
|
│ │ │ ③ WREncryptedFileManager │
|
|
│ │ │ decryptContentsOfFile:forBookId:isFileLost: │
|
|
│ │ │ 密钥来源: keyForBookId: (Keychain) │
|
|
│ │ │ ↓ 解密后 XHTML 文件 │
|
|
│ │ │ │
|
|
│ │ │ ④ WRBookNetwork.fileContentWithChapter: │
|
|
│ │ │ book:shouldRemoveHtmlTags:filterTranslate: │
|
|
│ │ │ ↓ 读取 XHTML 内容 │
|
|
│ │ │ │
|
|
│ │ │ ⑤ WREpubTypesetter.attributeStringWithFilePath: │
|
|
│ │ │ ↓ CSS 级联 (5层) │
|
|
│ │ │ ↓ DTHTMLAttributedStringBuilder._buildString │
|
|
│ │ │ ↓ DTHTMLParser (SAX) → DTHTMLElement (DOM) │
|
|
│ │ │ ↓ DTHTMLElement.attributedString │
|
|
│ │ │ ↓ 输出: NSAttributedString │
|
|
│ │ │ │
|
|
│ │ │ ⑥ WRCoreTextLayouter (CTTypesetter 分页) │
|
|
│ │ │ ↓ CTTypesetterSuggestLineBreak (逐行排版) │
|
|
│ │ │ ↓ 每页一个 CTFrame │
|
|
│ │ │ ↓ WRChapterPageCount (NSRange 映射) │
|
|
│ │ │ │
|
|
│ │ │ ⑦ WRCoreTextLayoutFrame (单页排版帧) │
|
|
│ │ │ ↓ CTFrameGetLines → CTLine 列表 │
|
|
│ │ │ ↓ avoidPageBreakInside (截断保护) │
|
|
│ │ │ │
|
|
│ │ │ ⑧ WRPageView.drawRect: │
|
|
│ │ │ CGContextTranslateCTM (坐标翻转) │
|
|
│ │ │ CTFrameDraw (绘制文字) │
|
|
│ │ │ 绘制图片/高亮/下划线/选择 │
|
|
│ │ │ ↓ │
|
|
└──────────┘ └──────────────────────────────────────────────────┘
|
|
↓
|
|
屏幕像素渲染
|
|
```
|
|
|
|
### 2.2 加密密钥数据流 (DRM 保护链)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ DRM 密钥生命周期 │
|
|
├─────────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌──────────┐ │
|
|
│ │ 服务器 │─── encryptKey (每章独立) ───┐ │
|
|
│ └──────────┘ │ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
|
│ │ WRPreloadBookManager │ │
|
|
│ │ saveEncryptKey:forPath:bookId: │ │
|
|
│ │ ↓ 存储到: NSUserDefaults (临时) │ │
|
|
│ │ encryptKeyForPath:bookId: (读取) │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
|
│ │ WREncryptedFileManager │ │
|
|
│ │ keyForBookId: │ │
|
|
│ │ ↓ 优先级: Keychain > NSUserDefaults > 内存缓存 │ │
|
|
│ │ │ │
|
|
│ │ decryptContentsOfFile:forBookId:isFileLost: │ │
|
|
│ │ ↓ 算法: AES-128-CBC │ │
|
|
│ │ ↓ 输入: 加密的 XHTML 数据 │ │
|
|
│ │ ↓ 输出: 明文 XHTML │ │
|
|
│ │ ↓ 检测: "REWD" 自定义头部标识 │ │
|
|
│ │ │ │
|
|
│ │ encryptFileForBookId:originalEncryptKey:atPath:toPath: │ │
|
|
│ │ ↓ 解密后立即重新加密存储 (本地 DRM) │ │
|
|
│ │ ↓ 防止直接拷贝文件读取 │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
|
│ │ 本地存储 │ │
|
|
│ │ Documents/{bookId}/plainBookDirectory/ (解密后的 EPUB) │ │
|
|
│ │ Documents/{bookId}/epubImage/ (书籍图片缓存) │ │
|
|
│ │ Library/{cachePath}/epubImage/ (SDWebImage 缓存) │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ 密钥安全机制: │
|
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
|
│ │ 1. 传输层: HTTPS + 加密 ZIP │ │
|
|
│ │ 2. 解密层: 逐章解密 (WREncryptedFileManager) │ │
|
|
│ │ 3. 存储层: 本地二次加密 (encryptFileForBookId) │ │
|
|
│ │ 4. 密钥层: 每本书独立密钥 + Keychain 安全存储 │ │
|
|
│ │ 5. 设备层: 密钥与设备绑定 │ │
|
|
│ │ 6. 试读层: freeTrialChapterCutOffStringLocaion (服务端控制) │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.3 用户标注数据流
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ 用户触摸/长按 │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ WRPageView 手势识别 (UITapGestureRecognizer / UILongPressGestureRecognizer)
|
|
│ │ │
|
|
│ ▼ │
|
|
│ CoreText Hit Test │
|
|
│ touchPoint = WRSFlipPointForCoreText(touch, viewHeight) // 坐标翻转
|
|
│ CTLineGetStringIndexForPosition(line, touchPoint) // 坐标→字符索引
|
|
│ CTLineGetOffsetForStringIndex(line, charIndex, NULL) // 字符索引→坐标
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 选择范围确定 (selectionStartIndex .. selectionEndIndex) │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ UIMenuController 弹出操作菜单 │
|
|
│ ├─ 划线/高亮 ─→ WRChapterData.addHighlightInRange:key:itemId:color:│
|
|
│ ├─ 写想法 ─→ WRBookNetwork.addReview:shareToWechat:... │
|
|
│ ├─ 复制 ─→ UIPasteboard │
|
|
│ ├─ 查询/翻译 ─→ WRReaderDictionaryViewController │
|
|
│ └─ 分享 ─→ WRShareManager │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ WRChapterData 标注存储 │
|
|
│ NSAttributedString 注入自定义属性: │
|
|
│ "com.weread.highlight" → 高亮数据 │
|
|
│ "com.weread.underline" → 下划线数据 │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 服务器同步 │
|
|
│ WRBookNetwork.addReview:shareToWechat:audioArticleId:... │
|
|
│ WRBookNetwork.loadBookmarkListWithBookId:syncKey:callback: │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 重新排版 │
|
|
│ WRReaderViewController.recomposeCurrentPageViewWithSource: │
|
|
│ → WRPageView.setNeedsDisplay → drawRect: 重绘 │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.4 阅读进度数据流
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ 本地进度持久化 │
|
|
│ WRReaderViewController._saveReadingProgressAndIsAsync: │
|
|
│ ↓ NSUserDefaults 存储: │
|
|
│ - bookId / chapterUid / chapterIdx │
|
|
│ - filePosition / stringLocation │
|
|
│ - pageOfChapter / pageOfFlyleaf │
|
|
│ - lastReadDate / readingTime │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 云端同步 │
|
|
│ WRBookNetwork.uploadBookProgressAndReadingTime: │
|
|
│ ↓ POST /api/book/progress │
|
|
│ ↓ 参数: bookId, chapterUid, progress, readingTime │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 启动恢复 │
|
|
│ WRReaderViewController.initWithBook:progress:... │
|
|
│ ↓ loadBookReadInfoWithBookId: (从服务器获取最新进度) │
|
|
│ ↓ gotoChapterIdx:position:positionOfFile: (跳转到上次位置) │
|
|
│ ↓ scrollToLastReadingProgressIfNeeded │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.5 预加载数据流
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ 预测触发 │
|
|
│ WRForecastUtils.shouldPreloadChapterUidsForBook: │
|
|
│ type:bookRank:archiveRank: │
|
|
│ ↓ 根据书籍排名 + 用户行为预测 │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 预加载执行 │
|
|
│ WRChapterDownloadManger._preloadChapterContentWithBook: │
|
|
│ type:bookRank: │
|
|
│ ↓ 后台线程下载相邻章节 │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 下载 + 解密 + 缓存 │
|
|
│ WRBookNetwork.loadTarForEpubBookId:chapters:isPreload: │
|
|
│ → handleUnzipWithBookId → WREncryptedFileManager │
|
|
│ → 存储到 Documents/{bookId}/plainBookDirectory/ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 图片预缓存 │
|
|
│ WRBookNetwork.storeTarEpubImageToDiskWithBookId: │
|
|
│ chapterUid:untarDirectory: │
|
|
│ → SDWebImage → com.hackemist.SDWebImageCache.epubImage │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 密钥预缓存 │
|
|
│ WRPreloadBookManager.saveEncryptKey:forPath:bookId: │
|
|
│ → NSUserDefaults / Keychain │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.6 JS Bridge 数据流 (WebView 路径 — 公众号/文集文章)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ JS → 原生 │
|
|
│ window.webkit.messageHandlers.MPReader.postMessage(data) │
|
|
│ wereadBridge.execMPReaderMethod('MPReader', data) │
|
|
│ ↓ WKScriptMessageHandler │
|
|
│ ↓ WRMPReadingViewModel 解析 JSON │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 原生 → JS │
|
|
│ [webView evaluateJavaScript:@"..." completionHandler:nil] │
|
|
│ ↓ WKUserScript 注入脚本 │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 高亮系统 (weread-highlighter.js) │
|
|
│ rangy.init() → 创建 Highlighter (TextRange 模式) │
|
|
│ 注册 ClassApplier: "highlight"/"review"/"reference"/"tts" │
|
|
│ 监听 selectionchange 事件 │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ 通信协议: wereadapijs://dispatch_message/ │
|
|
│ URL Scheme 编码消息, iframe 触发 │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|