feat(wxread): align pagination, rendering, and docs

This commit is contained in:
shen
2026-05-24 15:36:01 +08:00
parent a318c0e3d0
commit 2a94921e88
103 changed files with 6124 additions and 4623 deletions
@@ -1,6 +1,6 @@
# 微信读书 EPUB 阅读器 — 核心架构与数据流图
# 读书 EPUB 阅读器 — 核心架构与数据流图
> 逆向工程目标: WeRead v10.0.3 (Build 79), arm64, 63MB 主二进制
> 目标: WeRead v10.0.3 (Build 79)
---
@@ -10,12 +10,11 @@
```
┌─────────────────────────────────────────────────────────────────────┐
│ WeRead.app (iOS/macOS Catalyst) │
│ 主二进制: 63MB, Mach-O arm64 │
│ WeRead.app (iOS/macOS Catalyst) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 主二进制 (WeRead) │ │
│ │ WeRead │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ │
│ │ │ 阅读器模块 │ │ 书架模块 │ │ 其他业务模块 │ │ │
│ │ │ WRReader* │ │ WRBookshelf* │ │ WRDiscover/WRMarket │ │ │
@@ -216,7 +215,7 @@ WRReaderViewController (431 methods, 阅读器主控制器)
```
┌──────────┐ HTTPS ┌──────────────────────────────────────────────────┐
微信读书 │─────────────→│ ① WRBookNetwork.loadTarForEpubBookId:chapter: │
│ 读书 │─────────────→│ ① WRBookNetwork.loadTarForEpubBookId:chapter: │
│ 服务器 │ 加密 ZIP │ isPreload: │
│ │ {bookId}_ │ ↓ │
│ │ DECRYPT.zip │ ② WRBookNetwork.handleUnzipWithBookId: │
@@ -1,4 +1,4 @@
# 微信读书 EPUB 阅读器 — 符号恢复与核心算法
# 读书 EPUB 阅读器 — 符号恢复与核心算法
> 基于 WeRead v10.0.3 (Build 79) 二进制逆向
> 方法签名来源: __objc_methname 段 + binary strings
@@ -254,7 +254,7 @@ def cascade_stylesheets(default_css: str, replace_css: str, dark_css: str,
Args:
default_css: Safari 默认样式 (default.css)
replace_css: 微信读书默认替换 (replace.css)
replace_css: 读书默认替换 (replace.css)
dark_css: 暗黑主题 (dark.css)
epub_css: EPUB 书籍内嵌 CSS
user_settings_css: 用户自定义设置 (字号/行高/主题)
@@ -295,7 +295,7 @@ def cascade_stylesheets(default_css: str, replace_css: str, dark_css: str,
# 按优先级逐层合并
result = parse_css(default_css) # 层1: 基础
result = merge(result, parse_css(replace_css)) # 层2: 微信读书默认
result = merge(result, parse_css(replace_css)) # 层2: 读书默认
result = merge(result, parse_css(dark_css)) # 层3: 暗黑主题
result = merge(result, parse_css(epub_css)) # 层4: EPUB 内嵌
result = merge(result, parse_css(user_settings_css)) # 层5: 用户设置 (最高优先级)
@@ -630,7 +630,7 @@ def convert_hans_to_hant(attributed_string: str) -> str:
# OpenCC: opencc_convert("s2t", text)
# 简化实现: 使用 Unicode 码点映射表
# 微信读书内部可能使用腾讯自研的繁简转换库
# 读书内部可能使用腾讯自研的繁简转换库
conversion_table = load_hans_to_hant_table() # ~8000 个映射
result = []
@@ -1,9 +1,6 @@
# 微信读书 EPUB 阅读器 — 数据结构与 API 协议定义
> 基于 WeRead v10.0.3 (Build 79) 逆向工程
> 数据结构来源: __objc_methtype + class_ro_t ivar 段
> API 来源: WRBookNetwork 44 个 class method 签名
# 读书 EPUB 阅读器 — 数据结构与 API 协议定义
> 基于 WeRead v10.0.3 (Build 79)
---
## 一、关键数据结构定义 (Header Files)
@@ -129,7 +126,7 @@ typedef NS_ENUM(NSInteger, WRChapterFormat) {
// 表格
@property (nonatomic, strong) DTTableStyle *tableStyle; // 表格样式
// 微信读书自定义属性
// 读书自定义属性
@property (nonatomic, assign) NSInteger verticalCenterStyle; // wr-vertical-center-style
@property (nonatomic, assign) BOOL pageRelate; // weread-page-relate
@property (nonatomic, assign) BOOL avoidPageBreakInside; // 断页保护
@@ -185,7 +182,7 @@ typedef NS_ENUM(NSInteger, WRChapterFormat) {
@property (nonatomic, assign) CGFloat maximumLineHeight; // 最大行高
@property (nonatomic, assign) CGFloat lineHeightMultiple; // 行高倍数
// 微信读书扩展
// 读书扩展
@property (nonatomic, assign) CGFloat defaultTabInterval; // 默认制表位
@end
@@ -809,7 +806,7 @@ NSString *const kWRUserVidKey = @"com.weread.user.vid";
### 3.4 NSAttributedString 自定义属性键
```objc
// 微信读书在 NSAttributedString 中注入的自定义属性
// 读书在 NSAttributedString 中注入的自定义属性
// 用于在排版结果中传递页面布局元数据
NSString *const DTPageBackgroundColorAttribute = @"DTPageBackgroundColor";
+10 -10
View File
@@ -1,6 +1,6 @@
# CSS/JS/字体资源分析
本文档对微信读书 EPUB 阅读器的前端资源文件进行全面分析,涵盖 CSS 样式表、JavaScript 脚本和字体文件。
本文档对读书 EPUB 阅读器的前端资源文件进行全面分析,涵盖 CSS 样式表、JavaScript 脚本和字体文件。
---
@@ -8,7 +8,7 @@
### 1.1 样式层叠架构
微信读书的 CSS 采用分层架构:
读书的 CSS 采用分层架构:
```
default.css (基础HTML样式)
@@ -46,7 +46,7 @@ Safari 派生的基础 HTML 默认样式,为 WebView 渲染提供标准化起
**路径**: `output/resources/css/replace.css` (172行)
EPUB 内容的核心替换样式,定义了微信读书特有的排版规则。
EPUB 内容的核心替换样式,定义了读书特有的排版规则。
**字体设置**:
- 标题和版权页使用 `"SourceHanSerifCN-Medium"` 字体
@@ -62,7 +62,7 @@ EPUB 内容的核心替换样式,定义了微信读书特有的排版规则。
| `.fifthTitle` | 1.05em | normal |
| `.sixthTitle` | 1em | normal |
**微信读书自定义CSS属性**:
**读书自定义CSS属性**:
```css
/* 垂直居中样式 - 值2用于正文图片 */
@@ -545,7 +545,7 @@ getAllForwardLinks()
// 转换H5链接为原生数据属性
transferH5Link()
// 解密微信读书加密链接
// 解密读书加密链接
WRLink_decrypt(str)
// type '3' = 数字
// 其他 = 十六进制编码文本
@@ -573,7 +573,7 @@ document.addEventListener("selectionchange", debounce(function(e) {
#### 2.4.1 rangy-highlighter.js (711行)
Rangy 高亮器模块,带微信读书自定义修改。
Rangy 高亮器模块,带读书自定义修改。
**CharacterRange 类**:
```javascript
@@ -1099,7 +1099,7 @@ line-height: 30px;
## 四、关键发现与实现细节
### 4.1 微信读书自定义CSS属性
### 4.1 读书自定义CSS属性
**wr-vertical-center-style**:
-`1``.wr-vertical-center` 类,强制垂直居中
@@ -1137,7 +1137,7 @@ resultIframe.src = 'wereadapijs://private/setresult/' + scene + '&' + encodedDat
2. `rangy-textrange.js` - 字符级范围操作(支持图片文本)
3. `rangy-classapplier.js` - CSS类应用
4. `rangy-highlighter.js` - 高亮管理(序列化/反序列化)
5. `weread-highlighter.js` - 微信读书业务逻辑
5. `weread-highlighter.js` - 读书业务逻辑
**标注持久化**:
```javascript
@@ -1278,13 +1278,13 @@ RE.insertBook = function(id, title, author, cover) {
## 六、总结
微信读书的前端资源架构体现了以下设计特点:
读书的前端资源架构体现了以下设计特点:
1. **分层样式系统**:通过 default.css → replace.css/MediaPlatform.css → dark.css 的层叠,实现内容类型和主题的灵活切换
2. **原生桥接机制**WeReadApi.js 通过 iframe URL scheme 实现 JS 与原生的高效通信,支持异步回调
3. **扩展的Rangy库**:在标准 Rangy 基础上添加了图片文本支持、高亮合并、序列化等微信读书特有功能
3. **扩展的Rangy库**:在标准 Rangy 基础上添加了图片文本支持、高亮合并、序列化等读书特有功能
4. **完整的标注系统**:支持高亮、想法、好友想法、引用、TTS五种标注类型,每种有独立的样式和交互
@@ -1,6 +1,6 @@
# DTCoreText 自定义修改分析
微信读书 (WeRead) 基于开源 DTCoreText 库进行了深度定制,将其从一个通用的 HTML-to-NSAttributedString 转换库改造为一套完整的电子书分页渲染引擎。本文档详细记录所有自定义修改。
读书 (WeRead) 基于开源 DTCoreText 库进行了深度定制,将其从一个通用的 HTML-to-NSAttributedString 转换库改造为一套完整的电子书分页渲染引擎。本文档详细记录所有自定义修改。
---
@@ -1,6 +1,6 @@
# EPUB 渲染管线详解
微信读书 (WeRead) 的 EPUB 渲染管线将原始 XHTML 文件转换为可分页、可交互的阅读视图。本文档完整描述从 EPUB 文件到屏幕像素的每一步。
读书 (WeRead) 的 EPUB 渲染管线将原始 XHTML 文件转换为可分页、可交互的阅读视图。本文档完整描述从 EPUB 文件到屏幕像素的每一步。
---
+334
View File
@@ -0,0 +1,334 @@
# WXRead/decompiled 逆向代码说明
## 概述
此目录包含从读书 (WeRead) iOS 客户端二进制逆向还原的头文件和实现代码。共 44 个文件(22 对 .h/.m),分为三大模块:
1. **阅读器核心** — 阅读控制器、页面渲染、排版引擎、EPUB 解析
2. **标注系统** — 划线、高亮、书签、想法、Pencil 手写笔记
3. **DTCoreText 定制** — 基于开源 DTCoreText 库的读书私有定制
---
## 架构总览
```
WRReaderViewController (阅读器主控制器)
├── WRPageViewController (翻页控制器, 支持 curl/slide/fade/none)
│ └── WRPageView (页面渲染视图, CoreText 直接绘制)
│ └── WRCoreTextLayoutFrame (单页排版帧)
│ └── WRCoreTextLayoutLine (单行排版)
├── WREpubParser (EPUB 文件解析)
├── WREpubTypesetter (XHTML → NSAttributedString 排版)
│ └── DTHTMLAttributedStringBuilder (HTML DOM → 属性字符串)
│ └── DTHTMLElement (DOM 节点)
├── WRChapterData (章节数据模型)
├── WRChapterPageCount (分页计算器)
├── WRCoreTextLayouter (CoreText 排版器)
└── WRBookmark / WRPageHighlight / WRPageMark / WRPageUnderline (标注模型)
```
---
## 阅读器核心模块
### `WRReaderViewController`
阅读器的主入口控制器,431 个方法,管理阅读状态的完整生命周期。
**核心职责:**
- 管理 `WRReadingProgress`(阅读进度:章节索引、页码、字符偏移、滚动位置、阅读百分比)
- 章节导航:`gotoChapterIdx:position:positionOfFile:``jumpReadingToNextChapter``jumpReadingToPreChapter`
- 页面渲染:`renderPageView:progressData:source:` — 获取/计算章节数据、分页、创建/更新 WRPageView
- 排版重排:`recomposeCurrentPageViewWithSource:` — 字号/行距/主题变更后触发
- 进度持久化:`_saveReadingProgressAndIsAsync:`
- 支持涂鸦模式 (doodle mode) 和自动阅读 (auto-read)
- 通过 `WRReaderViewControllerDelegate` 回调通知外部进度变化和退出
### `WRPageViewController`
自定义的翻页控制器,支持四种翻页动画:
| 枚举值 | 样式 | 说明 |
|--------|------|------|
| `WRPageFlippingStyleCurl` | 纸张翻页 | 基于 UIPageViewController 的 curl 效果 |
| `WRPageFlippingStyleSlide` | 水平滑动 | UIScrollView 驱动的滑动翻页 |
| `WRPageFlippingStyleFade` | 淡入淡出 | 交叉渐变 |
| `WRPageFlippingStyleNone` | 无动画 | 瞬间切换 |
**关键特性:**
- 内部封装 `UIPageViewController`,提供 `WRPageViewControllerDelegate` / `WRPageViewControllerDataSource` 协议
- 包含 3 个故障修补方法,处理 Apple `UIPageViewController` 的已知崩溃:
- `detectNavigationDirectionCrashWithPageViewController:` — 检测导航方向崩溃
- `patchNavigationDirectionFault` — 修复导航方向状态不一致
- `patchNoViewControllerManagingPageViewFault` — 修复子 VC 丢失
- `patchUIPageCurlFault` — 修复快速翻页时的动画故障
### `WRPageView`
单页渲染视图,继承 `UIView`,通过 CoreText 的 `drawRect:` 直接绘制文本,不使用 `UILabel``UITextView`
**核心绘制:**
- `drawInContext:withData:size:inRect:position:` — 将文本和行内图片直接绘制到 CGContext
- 通过 `CTLineGetStringIndexForPosition` 进行 CoreText 级别的坐标点击测试
**UI 覆盖层:**
- 章节标题头 (headerLabel)、背景图片 (backgroundImageView)
- 加载指示器 (activityIndicator)、加载进度条 (loadingProgressView)
- 状态提示 (statusLabel)、重试按钮 (retryButton)
- 分享按钮、书签按钮、字号调节按钮
- 好友想法按钮 (friendReviewsButton)
**文本选区:**
- `stringIndexForPoint:` / `lineRangeForStringIndex:` — CoreText 坐标与字符索引转换
- `isSelecting` / `selectedRange` — 选区状态
- `clearSelection` — 清除选区
---
## EPUB 解析与排版
### `WREpubParser`
EPUB 文件解析器,处理完整的 EPUB 结构:
**解析流程:** `container.xml``content.opf``spine` → 章节文件
**主要 API**
- `initWithFilePath:book:` — 初始化
- `parse:` — 执行解析,返回 YES/NO
- `parseContainerXML:` — 解析 container.xml 获取 OPF 路径
- `parseOPFAtRelativePath:error:` — 解析 content.opf,填充章节列表和资源映射
- `parseNCX:` — 解析 toc.ncx 目录树
- `contentForChapterAtIndex:error:` — 读取单章 XHTML 内容
- `absolutePathForResource:` — 将相对资源路径解析为绝对路径
**错误码:**
| 错误码 | 含义 |
|--------|------|
| -1000 | 文件未找到 |
| -1001 | container.xml 解析失败 |
| -1002 | OPF 解析失败 |
| -1003 | NCX 解析失败 |
| -1004 | spine 为空 |
| -1005 | 章节加载失败 |
| -1006 | 解密失败 |
### `WREpubTypesetter`
EPUB 排版器,XHTML → `NSAttributedString` 的转换核心。全部为类方法,无需实例化。
**主入口方法:**
```objc
+ (NSAttributedString *)attributeStringWithFilePath:priority:
insertArticleToolAttachment:insertBookChapterToolAttachment:
insertRecommendView:book:chapter:pageFlippingStyle:
renderErrorReason:isStyleFileNotFound:options:
```
**处理流程:**
1. 加载并级联合并 CSS(用户设置 > EPUB 内嵌 > 默认样式)
2. 将 XHTML + 合并后的 CSS 喂入 `DTHTMLAttributedStringBuilder`
3. 遍历生成的元素树,修补图片、链接、自定义属性
4. 应用用户排版偏好(字体、行距、主题)
5. 可选截断用于免费试读预览
**自定义 CSS 属性:**
- `WREpubTypesetterVerticalCenterStyleAttribute` — 行内元素垂直居中(`wr-vertical-center-style`
- `WREpubTypesetterPageRelateAttribute` — 跨页关联标记(`weread-page-relate`
**翻译渲染错误上报:**
- `tryReportTranslationError:` — 双语(原文 + 翻译)渲染异常时上报分析
### `WREpubPositionConverter`
文件位置与字符位置的双向转换器。用于书签同步和阅读进度追踪。
**核心概念:**`(fileIndex, row, column)` 三元组映射为全局字符偏移量。
**主要 API**
- `initWithFilePaths:attributedStrings:offset:isContainIntroFlyleaf:` — 初始化
- `initIndices` — 构建内部索引表(调用前不能执行转换)
- `indicesInFile:forRowColumnPairs:stringIndices:` — 行/列 → 字符索引
- `stringRangeFromFileRange:` — 文件内范围 → 全局字符串范围
- `totalCharacterCount` — 全书总字符数
- `fileIndexForCharacterPosition:` — 全局位置 → 文件索引
- `localOffsetInFileAtIndex:forGlobalPosition:` — 全局位置 → 文件内偏移
---
## 分页与布局
### `WRChapterPageCount`
章节分页计算器。管理每页的 `NSRange`
**关键属性:**
- `pageRanges` — 每页的字符范围数组 (NSValue-wrapped NSRange)
- `totalPages` — 总页数
**关键方法:**
- `currentCacheKeyWithBookId:` — 生成缓存键(编码书 ID + 当前排版设置,设置变更则失效)
- `rangeValueWithPageInfo:` — 从服务端分页数据提取范围
- `rangeForPageAtIndex:` / `pageIndexForCharacterIndex:` — 页码 ↔ 字符位置
- `recalculatePageRangesForAttributedString:drawingSize:margins:` — 重算分页
### `WRCoreTextLayouter`
读书封装的 CoreText 排版器,创建 `CTTypesetter` / `CTFramesetter` 并产出 `WRCoreTextLayoutFrame` 页面对象。
**初始化:**
- `initWithAttributedString:` / `initWithAttributedString:config:`
- `WRCoreTextLayoutConfig` 配置:frame 宽高、内边距、栏数、栏间距、孤行/寡行控制、连字符
**排版 API**
- `createTypesetter` / `createFramesetter` / `invalidateTypesetter`
- `layoutFrameWithRange:frame:` — 单帧排版
- `layoutFramesForPageSize:` — 全文分页排版
- `numberOfPagesForPageSize:` / `rangeForPageAtIndex:pageSize:` — 分页查询
- `pageBackgroundImageAtRange:themeBgColor:` — 页面背景图
- `resizedImageForImagePath:` — 图片缩放适配
### `WRCoreTextLayoutFrame`
单页排版帧,封装 `CTFrame`,管理 `WRCoreTextLayoutLine` 行数组。
**核心功能:**
- 文本绘制:`drawInContext:image:size:inRect:position:`(含 CTFrameDraw + 图片附件 + 装饰元素)
- 分栏支持:`numberOfColumns` / `columnGap`
- 跨页避让:`avoidPageBreakInsideByRemovingLastLinesIfNeeded` — CSS `avoid-page-break-inside` 实现
- 点击测试:`characterIndexAtPoint:` / `lineIndexAtPoint:` / `rectForCharacterAtIndex:`
- 选区操作:`selectedText` / `selectedRanges` / `selectTextInRange:` / `clearSelection`
- 搜索高亮:`highlightSearchResults:` / `clearSearchHighlights`
- 装饰元素:删除线范围、下划线范围、高亮范围、链接范围
- 响应式更新:通过 `RACSubject` (ReactiveObjC) 发出布局变更通知
---
## 标注系统
### `WRBookmark`
书签/标注的数据模型,支持 5 种类型:
| 类型 | 说明 |
|------|------|
| `WRBookmarkTypeHighlight` | 彩色高亮 |
| `WRBookmarkTypeUnderline` | 下划线 |
| `WRBookmarkTypeMark` | 页面书签(折角) |
| `WRBookmarkTypeNote` | 文字笔记 |
| `WRBookmarkTypePencil` | Apple Pencil 手绘 |
**关键属性:** `bookmarkId``bookId``chapterUid``chapterOffset``markText``startPos`/`endPos``colorStyle``anchorId``rangeKey``syncKey`
**持久化:** `toDictionary` / `fromDictionary``toJSONData` / `fromJSONData`
**工厂方法:**
- `bookmarkWithBookId:chapterUid:offset:text:type:`
- `highlightWithBookId:chapterUid:startPos:endPos:text:colorStyle:`
### `WRPageHighlight`
文本高亮标注模型。5 种预设颜色:黄、蓝、红、绿、紫。
**方法:**
- `initWithBookId:chapterUid:startPos:endPos:text:color:` — 创建高亮
- `toBookmark` — 转为 WRBookmark 进行持久化/同步
- `uiColor` — 返回渲染用 UIColor
### `WRPageUnderline`
下划线标注模型。支持 4 种下划线样式:实线、虚线、波浪线、点线。
**方法:**
- `toBookmark` / `fromBookmark:` — 与 WRBookmark 双向转换
- `underlinePathForRect:` — 返回渲染用 UIBezierPath
- `containsPosition:` — 范围查询
- `mergeWithUnderline:` — 合并相邻下划线
- `setNote:` — 附加笔记
### `WRPageMark`
页面书签(折角)模型。25 个方法,功能最丰富的标注类型。
**关键特性:**
- 支持 3 种展示模式:图标、列表、行内
- 关联标注:`linkedHighlights` / `linkedUnderlines` — 书签位置上附带的高亮和下划线
- 批量操作:`marksSortedByPosition:` / `marksSortedByDate:` / `marksInChapter:fromMarks:` / `marksInRange:fromMarks:`
- 序列化:`toDictionary` / `fromDictionary``toJSONData` / `fromJSONData`
### `WRReaderPencilNoteManager`
Apple Pencil 手写笔记管理器。11 个类方法,全部为类方法调用。
**支持 9 种画笔颜色/样式:** 黑、灰、红、蓝、黄、绿、铅笔、钢笔、荧光笔
**本地存储:**
- `drawingFileDirectory` / `drawingFilePathWithReviewItemId:` — 文件路径管理
- `writeDrawingDataToLocal:` / `writeDrawingToLocal:` — 本地写入(支持 draft/published 状态)
- `checkDrawingExistsWithReviewItemId:` — 存在性检查
- `deleteDrawingWithReviewItemId:` / `deleteAllReviewDrawings` — 删除
**云端同步:**
- `uploadPencilDrawing:colorStyle:onlyUploadImage:canRetry:` — 上传绘制图片和数据到腾讯云 COS
- `uploadPencilNoteData:suffix:` — 上传 PKDrawing 序列化数据
- `downloadDrawingDataFromCosWithUrl:desPath:callback:` — 从 COS 下载
---
## DTCoreText 定制模块
读书基于开源库 [DTCoreText](https://github.com/Cocoanetics/DTCoreText) 做了大量私有定制。
### `DTHTMLAttributedStringBuilder`
HTML DOM → `NSAttributedString` 的 SAX 风格解析构建器。`WREpubTypesetter` 的底层依赖。
**WeRead 自定义属性键:**
- `DTPageBackgroundColorAttribute` / `DTPageBackgroundImageAttribute` — 页面背景
- `DTPageBreakAfterAttribute` / `DTPageBreakBeforeAttribute` — 分页控制
- `DTPageBreakInsideAvoidAttribute` — 跨页避让
- `DTPageRelateAttribute` — 跨页关联
- `DTHTMLVerticalCenterAttribute` — 垂直居中
- `DTHTMLTranslateTagAttribute` — 翻译标签
### `DTHTMLElement`
HTML 元素 DOM 节点。构建解析时的 DOM 树,每个节点可通过 `attributedString` 方法生成对应的属性字符串。
**关键属性:** `tagName``parent`/`children``styleDictionary``isBlockElement``shouldAvoidPageBreakInside`
### `DTCoreTextLayouter` / `DTCoreTextLayoutFrame` / `DTCoreTextLayoutLine` / `DTCoreTextGlyphRun`
DTCoreText 的四层排版层次结构(与 `WR` 前缀版本功能对应,是底层实现):
```
DTCoreTextLayouter (排版器, CTTypesetter 包装)
└── DTCoreTextLayoutFrame (排版帧, CTFrame 包装)
└── DTCoreTextLayoutLine (排版行, CTLine 包装)
└── DTCoreTextGlyphRun (字形运行, CTRun 包装)
```
- **Layouter** — 创建 CTTypesetter,产出 LayoutFrame,支持帧缓存
- **LayoutFrame** — 管理排版行数组,支持多栏、分页避让、点击测试、选区、搜索
- **LayoutLine** — 封装 CTLine,管理 GlyphRun 数组,提供排版指标(ascent/descent/leading/width)和点击测试
- **GlyphRun** — 封装 CTRun,管理字形(glyph)级别操作:位置、路径绘制、附件(图片)、字体属性、绘制方向
---
## 数据流
```
EPUB 文件 (.epub)
↓ WREpubParser.parse
解析 container.xml → content.opf → toc.ncx
↓ WREpubTypesetter.attributeStringWithFilePath
XHTML + CSS → DTHTMLAttributedStringBuilder → NSAttributedString
↓ WRCoreTextLayouter / WRChapterPageCount
分页排版 → [NSRange per page]
↓ WRPageView.drawInContext
CoreText 绘制到 CGContext
↓ WRPageViewController
翻页展示
```
@@ -2,7 +2,7 @@
// DTHTMLAttributedStringBuilder.h
// DTCoreText (WeRead custom fork)
//
// Reverse-engineered from WeChat Reading (微信读书) binary.
// Reverse-engineered from WeChat Reading (读书) binary.
// This class converts HTML DOM into NSAttributedString via SAX-style parsing.
//
+1 -1
View File
@@ -2,7 +2,7 @@
// DTHTMLElement.h
// DTCoreText (WeRead custom fork)
//
// Reverse-engineered from WeChat Reading (微信读书) binary.
// Reverse-engineered from WeChat Reading (读书) binary.
// Represents a single HTML element in the DOM tree built during parsing.
// Each node can produce an NSAttributedString via -attributedString.
//
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRBookmark.h
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered header
//
// Bookmark model. Stores bookId, chapterUid, and position information.
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRBookmark.m
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered implementation reconstruction
//
// Detailed pseudo-code based on binary analysis (many NSString ivars,
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRChapterData.h
// WeRead (微信读书)
// WeRead (读书)
//
// Reverse-engineered header reconstruction.
// Chapter data model. Stores the typeset NSAttributedString.
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRChapterData.m
// WeRead (微信读书)
// WeRead (读书)
//
// Detailed pseudo-code reconstruction of the chapter data model.
// Stores the typeset NSAttributedString, manages highlights, underlines,
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRChapterPageCount.h
// WeRead (微信读书)
// WeRead (读书)
//
// Reverse-engineered header reconstruction.
// Pagination calculator. Manages NSRange for each page within a chapter.
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRChapterPageCount.m
// WeRead (微信读书)
// WeRead (读书)
//
// Detailed pseudo-code reconstruction of the pagination calculator.
// Computes page breaks by simulating CoreText line layout and fitting
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WREpubParser.h
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered header
//
// EPUB file parser. Parses OPF (content.opf), NCX (toc.ncx), and XHTML chapter files.
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WREpubParser.m
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered implementation reconstruction
//
// Detailed pseudo-code based on binary analysis, ivar types, known methods,
@@ -1,6 +1,6 @@
//
// WREpubPositionConverter.h
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered header
//
// Position converter between file positions and character positions.
@@ -1,6 +1,6 @@
//
// WREpubPositionConverter.m
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered implementation reconstruction
//
// Detailed pseudo-code based on binary analysis, ivar types, known methods,
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WREpubTypesetter.h
// WeRead (微信读书) - Reverse Engineered
// WeRead (读书) - Reverse Engineered
//
// EPUB Typesetter: Converts XHTML content into NSAttributedString
// via DTHTMLAttributedStringBuilder with CSS cascade, image handling,
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WREpubTypesetter.m
// WeRead (微信读书) - Reverse Engineered Implementation Reconstruction
// WeRead (读书) - Reverse Engineered Implementation Reconstruction
//
// This is a detailed pseudo-code reconstruction based on:
// - Binary strings output (method signatures, CSS filenames, attribute names)
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageHighlight.h
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered header
//
// Annotation model for text highlights. Stores the highlighted text range,
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageHighlight.m
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered implementation reconstruction
//
// 3 methods identified from binary. WRPageHighlight is a lightweight
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageMark.h
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered header
//
// Annotation model for page bookmarks/marks (dog-ear style).
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageMark.m
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered implementation reconstruction
//
// 25 methods identified from binary. WRPageMark is the most comprehensive
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageUnderline.h
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered header
//
// Annotation model for text underlines. 10 methods identified from binary.
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageUnderline.m
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered implementation reconstruction
//
// 10 methods identified from binary. WRPageUnderline renders underline
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageView.h
// WeRead (微信读书)
// WeRead (读书)
//
// Reverse-engineered header reconstruction.
// The page rendering view. Inherits UIView. Uses CoreText direct drawing
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageView.m
// WeRead (微信读书)
// WeRead (读书)
//
// Detailed pseudo-code reconstruction of the page rendering view.
// This view draws text directly via CoreText into CGContext — no UILabel
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageViewController.h
// WeRead (微信读书)
// WeRead (读书)
//
// Reverse-engineered header reconstruction.
// Based on UIPageViewController. Supports UIPageCurl (simulation) and
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPageViewController.m
// WeRead (微信读书)
// WeRead (读书)
//
// Detailed pseudo-code reconstruction of the page view controller.
// Wraps UIPageViewController with fault detection and patching for
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPreloadBookManager.h
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered header
//
// Preload manager. Predicts which chapters to preload based on book ranking
+1 -1
View File
@@ -1,6 +1,6 @@
//
// WRPreloadBookManager.m
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered implementation reconstruction
//
// Detailed pseudo-code based on binary analysis, ivar types (NSMutableDictionary),
@@ -1,6 +1,6 @@
//
// WRReaderPencilNoteManager.h
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered header
//
// Apple Pencil note manager. 11 class methods identified from binary.
@@ -1,6 +1,6 @@
//
// WRReaderPencilNoteManager.m
// WeRead (微信读书)
// WeRead (读书)
// Reverse-engineered implementation reconstruction
//
// 11 class methods identified from binary. Manages Apple Pencil
@@ -1,6 +1,6 @@
//
// WRReaderViewController.h
// WeRead (微信读书)
// WeRead (读书)
//
// Reverse-engineered header reconstruction.
// Main reader controller. Manages reading state, progress saving,
@@ -1,6 +1,6 @@
//
// WRReaderViewController.m
// WeRead (微信读书)
// WeRead (读书)
//
// Detailed pseudo-code reconstruction of the main reader controller.
// 431 methods total. This file covers the key methods for page rendering,
@@ -1,439 +0,0 @@
+[WRBookNetwork _removeTranslateHtml:]
+[WRBookNetwork addMileStone:callback:]
+[WRBookNetwork addReview:shareToWechat:audioArticleId:outlineContent:audioColumnId:callback:]
+[WRBookNetwork automaticallyMarkFinishReadingWithBookId:callback:]
+[WRBookNetwork chaptersInfoFromFile:checkTranslate:]
+[WRBookNetwork checkFMCards:callback:]_block_invoke
+[WRBookNetwork clearPreloadKVWithBookId:chapterUid:zipPath:]
+[WRBookNetwork dislikeReviewById:isDislike:withParams:callback:]
+[WRBookNetwork fetchLockInfoWithBookId:callback:]
+[WRBookNetwork fileContentWithChapter:book:shouldRemoveHtmlTags:filterTranslateContent:]
+[WRBookNetwork fileContentWithChapter:book:shouldRemoveHtmlTags:filterTranslateContent:]_block_invoke
+[WRBookNetwork handleUnzipErrorWithPath:plainBookDirectory:]
+[WRBookNetwork handleUnzipWithBookId:zipPath:encryptKey:plainBookDirectory:]
+[WRBookNetwork handleUnzipWithBookId:zipPath:encryptKey:plainBookDirectory:]_block_invoke
+[WRBookNetwork likeReviewById:isUnlike:withParams:callback:]
+[WRBookNetwork loadArticleBookDetailWithBookId:callback:]
+[WRBookNetwork loadBookDetailPodcastsWithBookId:withSynckey:withListType:withFilterType:withMaxIdx:withCount:]
+[WRBookNetwork loadBookInfoWithBookId:source:callback:]
+[WRBookNetwork loadBookLectureAuthors:callback:]
+[WRBookNetwork loadBookReadDetailInfoWithBookId:callback:]
+[WRBookNetwork loadBookReadInfoWithBookId:callback:]
+[WRBookNetwork loadBookReadInfoWithBookIdAndVid:vid:callback:]
+[WRBookNetwork loadBookmarkListWithBookId:syncKey:callback:]
+[WRBookNetwork loadChapterContentWithParam:callback:]
+[WRBookNetwork loadChapterContentWithParam:callback:]_block_invoke
+[WRBookNetwork loadExchangeRecordListWithParams:callback:]_block_invoke
+[WRBookNetwork loadFMCardsWithBookId:withSynckey:withListType:withFilterType:withMaxIdx:withCount:]
+[WRBookNetwork loadFriendMarkWithBookId:synckey:]_block_invoke
+[WRBookNetwork loadPodcastsWithSynckey:withBookId:withCount:withMaxIdx:callback:]
+[WRBookNetwork loadReadTimeWelfareActionWithBookId:opt:secretKey:firstEnter:]
+[WRBookNetwork loadRelatedBooksForReviewDetail:callback:]
+[WRBookNetwork loadTarForEpubBookId:chapter:isPreload:]
+[WRBookNetwork loadTarForEpubBookId:chapter:isPreload:]_block_invoke
+[WRBookNetwork loadTarForEpubBookId:chapter:isPreload:]_block_invoke_2
+[WRBookNetwork loadTarForEpubBookId:chapter:isPreload:]_block_invoke_5
+[WRBookNetwork loadTarForEpubBookId:chapter:isPreload:]_block_invoke_6
+[WRBookNetwork loadTarForEpubBookId:chapter:isPreload:]_block_invoke_7
+[WRBookNetwork loadTarForEpubBookId:chapters:isPreload:]
+[WRBookNetwork loadTopicReviewlist:callback:]
+[WRBookNetwork markReadingStatus:bookIds:isCancel:callback:]
+[WRBookNetwork markReadingStatus:withBookId:isCancel:withFinishInfo:callback:]
+[WRBookNetwork pollingChapterTranslateStatusWithBookId:isFreeTrialActive:referenceLocationDict:chapterTranslations:from:]
+[WRBookNetwork postReviewHideWithBookId:hide:callback:]
+[WRBookNetwork processChapterInfosFromChapterDownload:bookId:]
+[WRBookNetwork processEncryptedBookFileAtPath:encryptKey:book:chapterUid:isFromReview:]
+[WRBookNetwork repostReview:reposted:callback:]
+[WRBookNetwork resetChapterPaidIfNeededWithBookId:chapterUid:]
+[WRBookNetwork rewardReviewForId:price:timestamp:callback:]
+[WRBookNetwork savePreloadInfoWithDownloadParam:chaptersStr:timeFlag:tmpFilePath:encryptKey:]
+[WRBookNetwork searchResultsForBook:chapterUid:searchString:posBeg:posEnd:mode:callback:]
+[WRBookNetwork searchResultsForLocalBook:chapterUid:searchString:posBeg:posEnd:mode:callback:]
+[WRBookNetwork setFinishReading:withBookId:callback:]
+[WRBookNetwork setIsStartReading:withBookId:callback:]
+[WRBookNetwork storeTarEpubImageToDiskWithBookId:chapterUid:untarDirectory:]
+[WRBookNetwork uploadBookProgressAndReadingTime:callback:offlineCallback:]
+[WRBookNetworkReporter verifyZipWithBook:zipPath:fileSize:unzippedFiles:]
+[WRChapterData addUnderLineToAttributedString:range:itemId:style:color:]
+[WRChapterData freeTrialChapterCutOffStringLocaionWithAttributedString:book:]
+[WRChapterDownloadManger imageManagerForEpubBookWithBookId:]
+[WRChapterDownloadManger loadChapterContentNetworkWithParam:callback:]
+[WRChapterPageCount currentCacheKeyWithBookId:]
+[WRChapterPageCount rangeValueWithPageInfo:]
+[WRCoreTextLayouter convertHansToHantWithAttributedString:]_block_invoke
+[WREncryptedFileManager decryptContentsOfFile:forBookId:isFileLost:]
+[WREncryptedFileManager encryptFileForBookId:originalEncryptKey:atPath:toPath:]
+[WREncryptedFileManager keyForBookId:]
+[WREpubPositionConverter transformToNumberHtmlEntitesWithOriginHtmlEitites:]_block_invoke
+[WREpubTypesetter attributeStringWithFilePath:priority:insertArticleToolAttachment:insertBookChapterToolAttachment:insertRecommendView:book:chapter:pageFlippingStyle:renderErrorReason:isStyleFileNotFound:options:]
+[WREpubTypesetter tryReportTranslationError:bookId:chapter:isTranslationStyleNotFound:isTranslationContentNotFound:isTranslateTagButNoTranslateStyle:]
+[WRMarkContentStore markContentListForBookId:chapterUid:offset:count:]
+[WRMarkContentStore syncMarkContentListForBookId:chapterUid:]
+[WRMarketNetwork loadCategoryBooks:param:callback:]
+[WRPreloadBookManager clearKV]
+[WRPreloadBookManager encryptKeyForPath:bookId:]
+[WRPreloadBookManager fileNameForKey:bookId:]
+[WRPreloadBookManager removeEncryptKeyForPath:bookId:]
+[WRPreloadBookManager removeFileNameForKey:bookId:]
+[WRPreloadBookManager removeKVWithBookId:]
+[WRPreloadBookManager saveEncryptKey:forPath:bookId:]
+[WRPreloadBookManager saveFileNameDict:bookId:]
+[WRReaderBackgroundAdapter updateDownloadedBackground]_block_invoke
+[WRReaderBackgroundAdapter updateDownloadedBackground]_block_invoke_2
+[WRReaderBitmapColorHelper checkImageShouldAddBackgound:imageUrl:completedBlock:]
+[WRReaderBitmapColorHelper checkWhiteBlackImageAndTransformToTransparent:completedBlock:]
+[WRReaderBitmapColorHelper whiteToTransparentWithImage:completedBlock:]
+[WRReaderBookBorrowUtils redeemShortTimeReadWithTargetView:bookId:successBlock:]
+[WRReaderBookBorrowUtils redeemShortTimeReadWithTargetView:bookId:successBlock:]_block_invoke
+[WRReaderBookBorrowUtils showBorrowConfirmationPanelWithBorrowInfo:confirmBlock:cancelBlock:willShowBlock:]
+[WRReaderBookBorrowUtils showBorrowConfirmationPanelWithBorrowInfo:confirmBlock:cancelBlock:willShowBlock:]_block_invoke
+[WRReaderBookBorrowUtils showBorrowConfirmationPanelWithBorrowInfo:confirmBlock:cancelBlock:willShowBlock:]_block_invoke_3
+[WRReaderCatalogSearchManager appendSearchHistoryWithBookId:keyword:]
+[WRReaderCatalogSearchManager purgeSearchHistoryWithBookId:]
+[WRReaderCatalogSearchManager searchHistoryWithBookId:]
+[WRReaderCht2sManager autoConvertToCht2sStatusWithBook:dataTranslateMode:scene:hasRights:]
+[WRReaderCht2sManager canConvertCht2sWithBookId:]
+[WRReaderCht2sManager checkCht2sBookShouldSwitchLanguageForBookId:chapterUid:]
+[WRReaderContentNavigationManager addRangeValueToOutlineItem:]
+[WRReaderContentNavigationManager findParentNodesFromChapterOutlineLeafItems:]_block_invoke
+[WRReaderContentNavigationManager rangeForOutlineItem:]
+[WRReaderPencilNoteManager authCosForPencilDataWithSuffix:]_block_invoke
+[WRReaderPencilNoteManager checkDrawingExistsWithReviewItemId:reviewId:isDraft:]
+[WRReaderPencilNoteManager deleteAllReviewDrawings]
+[WRReaderPencilNoteManager deleteDrawingWithReviewItemId:reviewId:isDraft:]
+[WRReaderPencilNoteManager downloadDrawingDataFromCosWithUrl:desPath:callback:]
+[WRReaderPencilNoteManager downloadDrawingDataFromCosWithUrl:desPath:callback:]_block_invoke
+[WRReaderPencilNoteManager downloadDrawingWithReviewItemId:reviewId:drawingUrl:dataBlock:]_block_invoke_2
+[WRReaderPencilNoteManager downloadDrawingWithReviewItemId:reviewId:drawingUrl:dataBlock:]_block_invoke_3
+[WRReaderPencilNoteManager drawingFileDirectory]
+[WRReaderPencilNoteManager drawingFilePathWithReviewItemId:reviewId:isDraft:]
+[WRReaderPencilNoteManager imageFilePathWithReviewItemId:reviewId:]
+[WRReaderPencilNoteManager readDrawingWithReview:dataBlock:drawingUrlBlock:]_block_invoke
+[WRReaderPencilNoteManager readDrawingWithReview:dataBlock:drawingUrlBlock:]_block_invoke_2
+[WRReaderPencilNoteManager readDrawingWithReview:dataBlock:drawingUrlBlock:]_block_invoke_3
+[WRReaderPencilNoteManager uploadPencilDrawing:colorStyle:onlyUploadImage:canRetry:]
+[WRReaderPencilNoteManager uploadPencilDrawing:colorStyle:onlyUploadImage:canRetry:]_block_invoke
+[WRReaderPencilNoteManager uploadPencilNoteData:suffix:]
+[WRReaderPencilNoteManager uploadPencilNoteData:suffix:]_block_invoke
+[WRReaderPencilNoteManager uploadPencilNoteData:suffix:]_block_invoke_3
+[WRReaderPencilNoteManager writeDrawingDataToLocal:reviewItemId:reviewId:isDraft:]
+[WRReaderPencilNoteManager writeDrawingToLocal:reviewItemId:reviewId:isDraft:]
+[WRReaderProgress localProgressForBook:]
+[WRReaderTranslationManager canSwitchTranslationWithBookId:]
+[WRReaderTranslationManager chapterDataCacheKeyWithBookId:chapterUid:]
+[WRReaderTranslationManager isPlayChineseWithBookId:chapterUid:]
+[WRReaderTranslationManager tryPollingConvertStatusWithBook:isForTranslate:referenceLocationDict:isFreeTrialActive:chapterTranslations:updateTipsBlock:chapterTranslateCompletion:stopPollingBlock:errorBlock:isBatch:from:]_block_invoke
+[WRReaderTranslationManager updatePlayTranslation:forBookId:]
+[WRReaderTranslationManager wordCountWithBookId:chapterUid:]
+[WRReaderUnderlineStyleButtonManager bookmarkColorForColorStyle:underlineStyle:]
-[DTCoreTextGlyphRun newPathWithGlyphs]
-[DTHTMLAttributedStringBuilder _buildString]
-[DTHTMLAttributedStringBuilder _registerTagEndHandlers]_block_invoke_5
-[DTHTMLAttributedStringBuilder _registerTagStartHandlers]_block_invoke_11
-[DTHTMLAttributedStringBuilder parser:didStartElement:attributes:position:]
-[DTHTMLAttributedStringBuilder parser:foundCDATA:]
-[DTHTMLAttributedStringBuilder parser:foundCharacters:position:]
-[DTHTMLAttributedStringBuilder parserDidEndDocument:]
-[DTHTMLElement applyStyleDictionary:isLatinLanguageBook:]
-[DTHTMLElement attributedString]
-[DTHTMLElement interpretAttributes]
-[WRChapter isChapterContentDownloaded]
-[WRChapterData addAutoReadUnderLineInRange:style:color:]
-[WRChapterData addHighlightInRange:key:itemId:color:]
-[WRChapterData addReviewUnderlineInRange:itemId:type:]
-[WRChapterData addTempReviewHighlightInRange:itemId:]
-[WRChapterData addTempReviewHighlightInRange:itemId:color:]
-[WRChapterData deleteReviewUnderlineInRange:type:]
-[WRChapterData freeTrialChapterCutOffRealStringLocation]
-[WRChapterData generateOutlineContents]
-[WRChapterData markFreeTrialChapterCutOffStringLocation:]
-[WRChapterData rangeOfPage:]
-[WRChapterDownloadManger _preloadChapterContentWithBook:type:bookRank:]
-[WRChapterDownloadManger addDownloadTaskCount]
-[WRChapterDownloadManger createDownloadTaskSignalWithParam:callback:]_block_invoke
-[WRChapterDownloadManger createDownloadTaskSignalWithParam:callback:]_block_invoke_3
-[WRChapterDownloadManger downloadComicsChaptersIfNotExistWithParam:withCallback:]
-[WRChapterDownloadManger loadChapterContentWithParam:callback:]
-[WRChapterDownloadManger networkChanged]
-[WRChapterDownloadManger preloadShelfBooksForType:]
-[WRChapterDownloadManger removeDownloadTaskCount]
-[WRChapterDownloadManger resetChapterDownloadTaskCount]
-[WRChapterRecommendAlbumsView handleTouchAlbum:]
-[WRChapterRecommendAlbumsView handleTouchAlbum:]_block_invoke
-[WRChapterRecommendAlbumsView handleTouchAlbum:]_block_invoke_2
-[WRChapterRecommendAlbumsView initWithDataChangeSignal:]_block_invoke
-[WRCoreTextLayoutFrame avoidPageBreakInsideByRemovingLastLinesIfNeeded]
-[WRCoreTextLayoutFrame drawInContext:image:size:inRect:position:]
-[WRCoreTextLayoutFrame getRenderHeight]
-[WRCoreTextLayoutFrame lines]
-[WRCoreTextLayouter pageBackgroundImageAtRange:themeBgColor:]
-[WRCoreTextLayouter resizedImageForImagePath:rect:position:sizePattern:darkMode:themeBgColor:]
-[WREpubParser epubController:didFailWithError:]
-[WREpubPositionConverter indicesInFile:forRowColumnPairs:stringIndices:string:fileIndexOffset:stringIndexOffset:]
-[WREpubPositionConverter initIndices]
-[WREpubPositionConverter initWithFilePaths:attributedStrings:offset:isContainIntroFlyleaf:]
-[WREpubPositionConverter stringRangeFromFileRange:]
-[WRMarketPopToBookShelfTransition animateTransition:]_block_invoke_2
-[WRPreloadBookManager _preloadWholeBook:scene:]
-[WRPreloadBookManager _preloadWholeBook:scene:]_block_invoke
-[WRPreloadBookManager booksDirectoryInfoForNonVIPWithOnlyCalc:]
-[WRPreloadBookManager booksDirectoryInfoForVIPWithOnlyCalc:]
-[WRPreloadBookManager calcAndClearPreloadBookWithCompletion:onlyCalc:]
-[WRPreloadBookManager cleanUpPreloadBook]
-[WRPreloadBookManager cleanUpPreloadBook]_block_invoke
-[WRPreloadBookManager cleanUpPreloadBook]_block_invoke_2
-[WRPreloadBookManager downloadBook:uids:]
-[WRPreloadBookManager downloadBook:uids:]_block_invoke
-[WRPreloadBookManager downloadingUidsWithBookId:allChapters:fromChapterIdx:]
-[WRPreloadBookManager isBookCanPreloadForNonPayingVIP:]
-[WRPreloadBookManager isBookCanPreloadForPayingVIP:outReasons:]
-[WRPreloadBookManager preloadWithBook:fromChapterIdx:]
-[WRPreloadBookManager preloadWithBook:fromChapterIdx:]_block_invoke
-[WRPreloadBookManager refreshSetting]
-[WRPreloadBookManager remainingDiskSizeInMB]
-[WRPreloadBookManager resetBookDataWithBookId:]
-[WRPreloadBookManager stopCleanUpPreloadBookTask]
-[WRPreloadBookManager unzipBookCacheContentWithBookId:]
-[WRPreloadBookManager unzipBookCacheContentWithBookId:]_block_invoke
-[WRReaderAIKnowledgeViewController observeValueForKeyPath:ofObject:change:context:]
-[WRReaderAuthorReviewDetailViewController handleCommentButtonEvent:]
-[WRReaderAuthorReviewDetailViewController handleComposeButtonEvent:]_block_invoke
-[WRReaderAuthorReviewDetailViewController handleDeleteComment:]_block_invoke_2
-[WRReaderAuthorReviewDetailViewController handlePraiseButtonEvent:]
-[WRReaderAuthorReviewDetailViewController handlePraiseButtonEvent:]_block_invoke
-[WRReaderAuthorReviewDetailViewController handlePraiseButtonEvent:]_block_invoke_3
-[WRReaderAuthorReviewDetailViewController keyboardWillChangeFrameWithUserInfo:]_block_invoke
-[WRReaderAuthorReviewDetailViewController tableView:cellForRowAtIndexPath:]
-[WRReaderAuthorReviewListViewController handleAvatarButtonEvent:]
-[WRReaderAuthorReviewListViewController handlePraiseButtonEvent:]
-[WRReaderAuthorReviewListViewController handlePraiseButtonEvent:]_block_invoke
-[WRReaderAuthorReviewListViewController handlePraiseButtonEvent:]_block_invoke_3
-[WRReaderAuthorReviewListViewController tableView:cellForRowAtIndexPath:]
-[WRReaderAutoPlayer calcPageDuration]
-[WRReaderAutoPlayer clauseFinished:]
-[WRReaderAutoPlayer didBecomeActive]
-[WRReaderAutoPlayer initWithDelegate:chapterData:forVerticalReader:]
-[WRReaderAutoPlayer pause]
-[WRReaderAutoPlayer play]
-[WRReaderAutoPlayer setCurrentClauseIndex:]
-[WRReaderAutoPlayer setCurrentLocation:]
-[WRReaderAutoPlayer setSpeed:]
-[WRReaderAutoPlayer setStatus:]
-[WRReaderAutoPlayer setTmpClauseIndex:]
-[WRReaderAutoPlayer setTmpLocation:]
-[WRReaderAutoPlayer setupTimer]
-[WRReaderAutoPlayer stop]
-[WRReaderAutoPlayer willResignActive]
-[WRReaderBackground(WRReaderBackgroundAdapter_Private) downloadWithProgressHandler:completionHandler:]_block_invoke
-[WRReaderBookmarkViewController addBookmarkInCurrentReferenceArea]
-[WRReaderBookmarkViewController deleteBookmarkWithItemId:callback:]
-[WRReaderBrightnessChangeView brightSliderChanged:]
-[WRReaderBrightnessChangeView initReaderBackgroundViewUI]_block_invoke
-[WRReaderBrightnessChangeView initReaderBackgroundViewUI]_block_invoke_2
-[WRReaderBrightnessChangeView sizeThatFits:]
-[WRReaderCatalogContainerViewController pageController:didShowPageAtIndex:]_block_invoke
-[WRReaderCatalogContainerViewController pageController:titleConfigurationAtIndex:]
-[WRReaderCatalogContainerViewController pageController:viewControllerAtIndex:]
-[WRReaderCatalogContainerViewController selectCatalogViewController]
-[WRReaderCatalogContainerViewController selectOutlineViewController]
-[WRReaderCatalogContainerViewController selectSearchContentViewController]
-[WRReaderCatalogDataSource initWithBookId:type:delegate:]_block_invoke
-[WRReaderCatalogViewController shouldRefreshCurrentAndBackupIndexPathCell]
-[WRReaderChangeFirstIndentTableViewCell handleTapItemView:]
-[WRReaderChangeOrientationView tableView:cellForRowAtIndexPath:]
-[WRReaderChangePageTurningStyleView tableView:cellForRowAtIndexPath:]
-[WRReaderCht2sManager updatePlayCht2s:forBookId:]
-[WRReaderComicsViewModel chapterReviewForReviewId:]
-[WRReaderComicsViewModel contentForChapterUid:]
-[WRReaderComicsViewModel imageForURL:]_block_invoke_2
-[WRReaderComicsViewModel markAsLiked:forChapterUid:]
-[WRReaderComicsViewModel markAsLiked:forReview:]
-[WRReaderComicsViewModel preloadNextChapterIfNeededWithCurrentChapterUid:]_block_invoke
-[WRReaderComicsViewModel refreshAvailableRangeWithVisibleSectionRange:]
-[WRReaderContentNavigationManager didLoadDataWithSusseed:]_block_invoke
-[WRReaderContentNavigationManager findCurrentOutlineItemWithUniqId:chapterUid:]
-[WRReaderContentNavigationManager findNextOutlineItemInRanges:loadMoreChapterUids:]
-[WRReaderContentNavigationManager findPrevOutlineItemInRanges:loadMoreChapterUids:]
-[WRReaderContentNavigationManager hasNextOutlineItemInRanges:]
-[WRReaderContentNavigationManager hasNextOutlineItem]
-[WRReaderContentNavigationManager hasPrevOutlineItemInRanges:]
-[WRReaderContentNavigationManager hasPrevOutlineItem]
-[WRReaderContentNavigationManager initSearchDataSourceWithBook:]
-[WRReaderContentNavigationManager isCurrentOutlineItemVisible]
-[WRReaderContentNavigationManager jumpToNextOutlineItemWithPreviousLoadMoreChapterUids:]
-[WRReaderContentNavigationManager jumpToNextSearchItem]
-[WRReaderContentNavigationManager jumpToOutlineItem:]
-[WRReaderContentNavigationManager jumpToOutlineItemWithUniqId:chapterUid:highlight:]
-[WRReaderContentNavigationManager jumpToPrevOutlineItemWithPreviousLoadMoreChapterUids:]
-[WRReaderContentNavigationManager jumpToPrevSearchItem]
-[WRReaderContentNavigationManager jumpToSearchItem:]
-[WRReaderContentNavigationManager nextOutlineItemFromMemoryWithLoadMoreChapterUids:]
-[WRReaderContentNavigationManager prevOutlineItemFromMemoryWithLoadMoreChapterUids:]
-[WRReaderContentNavigationManager searchFrontAndBehindWithKeyword:chapterUid:position:addCurrentItem:callback:]
-[WRReaderContentNavigationManager searchFrontAndBehindWithKeyword:chapterUid:position:addCurrentItem:callback:]_block_invoke
-[WRReaderContentNavigationManager setCurrentSearchItem:]
-[WRReaderContentNavigationManager setupOutlineWithInitialDict:]
-[WRReaderContentNavigationManager updateOutlineDataWithBookId:]
-[WRReaderDictionaryViewController collectionView:cellForItemAtIndexPath:]
-[WRReaderDictionaryViewController observeValueForKeyPath:ofObject:change:context:]
-[WRReaderDictionaryViewController refreshData]_block_invoke_4
-[WRReaderEndOfTrialButton renderWithLabelDictionary:]
-[WRReaderEndOfTrialView handleCampaignButtonTapWithItem:]
-[WRReaderEndOfTrialView handleCampaignButtonTapWithItem:]_block_invoke
-[WRReaderEndOfTrialView parseRightsViewData]
-[WRReaderFloatReviewsViewController initHeaderToolViewIfNeeded]_block_invoke_2
-[WRReaderFloatReviewsViewController renderWithHyperlinksInfo:]
-[WRReaderFloatReviewsViewController setSelectedText:hyperlinksInfo:]
-[WRReaderFontSizeChangeView autoTestHandleChangeValueWithSlider:index:]
-[WRReaderFontSizeChangeView sizeThatFits:]
-[WRReaderFontSizeChangeView updateFontFamilyChangeButtonFont]
-[WRReaderHotUnderlinesViewController updateAppearanceForSectionHeaderView:inTableView:section:isPinned:]
-[WRReaderLastPageActionButtonContainerView createFontViewWithFinishIndex:iterationBlock:]
-[WRReaderLastPageBadgeView handleCheckButtonDownEvent:]
-[WRReaderLastPageBadgeView handleCheckButtonUpEvent:]
-[WRReaderLastPageBadgeView handleCheckButtonUpEvent:]_block_invoke_3
-[WRReaderLastPageBadgeView handleCheckButtonUpOutSideEvent:]
-[WRReaderLastPageViewController refreshFinishedBookInfo]_block_invoke
-[WRReaderLastPageViewController rootViewDidChangeIntrinsicSize:]
-[WRReaderLastPageViewController showing]
-[WRReaderMilestoneLabelView renderWithAttributedStrings:]
-[WRReaderMistakeViewController viewDidLoad]_block_invoke
-[WRReaderMistakeViewController viewDidLoad]_block_invoke_2
-[WRReaderModalView headerViewHeight]
-[WRReaderMoreOperationController renderWithBook:scene:]
-[WRReaderNoteViewModel initWithBookId:]
-[WRReaderOutlineViewController handleJumpToClickContentWithParams:]
-[WRReaderOutlineViewController initWithBookId:chapterUid:]_block_invoke
-[WRReaderOutlineViewController initWithBookId:chapterUid:]_block_invoke_2
-[WRReaderOutlineViewController viewDidLoad]
-[WRReaderPanelSelectionView panelHeaderHeight]
-[WRReaderPanelSelectionView panelTitle]
-[WRReaderPanelSelectionView tableView:cellForRowAtIndexPath:]
-[WRReaderPanelSelectionView tableView:didSelectRowAtIndexPath:]
-[WRReaderPanelSelectionView tableView:numberOfRowsInSection:]
-[WRReaderPencilNoteBaseView handleCanvasViewDrawingDidChange:]
-[WRReaderPencilNoteReviewManager editPencilReview:secretMode:imageDict:drawingUrl:didEditBlock:]_block_invoke
-[WRReaderPencilNoteReviewManager tryResendAllDraftDrawingReviews]_block_invoke
-[WRReaderPencilNoteReviewManager tryResendAllDraftDrawingReviews]_block_invoke_2
-[WRReaderPencilNoteReviewManager tryResendAllDraftDrawingReviews]_block_invoke_4
-[WRReaderPencilNoteReviewManager tryResendAllDraftDrawingReviews]_block_invoke_5
-[WRReaderPencilNoteReviewManager tryResendAllDraftDrawingReviews]_block_invoke_6
-[WRReaderPencilNoteReviewManager uploadDrawing:thenEditReview:secretMode:readerVC:didUploadBlock:didEditReviewBlock:didWriteReviewBlock:]_block_invoke
-[WRReaderPencilNoteReviewManager writeReview:secretMode:readerVC:imageDict:drawingUrl:didWriteBlock:]
-[WRReaderPencilNoteReviewManager writeReview:secretMode:readerVC:imageDict:drawingUrl:didWriteBlock:]_block_invoke
-[WRReaderPencilNoteReviewManager writeReview:secretMode:readerVC:imageDict:drawingUrl:didWriteBlock:]_block_invoke_2
-[WRReaderPencilNoteViewController addPageReview:]
-[WRReaderPencilNoteViewController addRangeReview:]
-[WRReaderPencilNoteViewController checkUpdatePencilPageReview:pageNoteView:]
-[WRReaderPencilNoteViewController checkUpdatePencilPageReview:pageNoteView:]_block_invoke
-[WRReaderPencilNoteViewController checkUpdatePencilPageReview:pageNoteView:]_block_invoke_2
-[WRReaderPencilNoteViewController checkUpdatePencilPageReview]
-[WRReaderPencilNoteViewController checkUpdatePencilPageReview]_block_invoke
-[WRReaderPencilNoteViewController checkUpdatePencilRangeReview]
-[WRReaderPencilNoteViewController checkUpdatePencilRangeReview]_block_invoke
-[WRReaderPencilNoteViewController checkUpdatePencilRangeReview]_block_invoke_2
-[WRReaderPencilNoteViewController checkUpdatePencilRangeReview]_block_invoke_3
-[WRReaderPencilNoteViewController checkUpdateRangeReviewDrawingAsDraft]
-[WRReaderPencilNoteViewController dealloc]
-[WRReaderPencilNoteViewController deleteEmptyDrawingReview:]_block_invoke_2
-[WRReaderPencilNoteViewController editPencilReview:secretMode:imageDict:drawingUrl:]_block_invoke
-[WRReaderPencilNoteViewController editRangeReviewForColorStyleSilentWithReview:]_block_invoke
-[WRReaderPencilNoteViewController editRangeReviewForColorStyleSilentWithReview:]_block_invoke_2
-[WRReaderPencilNoteViewController handleBookmarkUpdatedNotification:]
-[WRReaderPencilNoteViewController handleCloseRangeReviewEditWithShowAlert:]
-[WRReaderPencilNoteViewController handleCloseRangeReviewEditWithShowAlert:]_block_invoke
-[WRReaderPencilNoteViewController handleDeleteRangeReview]_block_invoke_2
-[WRReaderPencilNoteViewController init]
-[WRReaderPencilNoteViewController resetContextWithRangeReviews:chapterIdx:defaultSecretMode:]
-[WRReaderPencilNoteViewController setupPageNoteView]_block_invoke
-[WRReaderPencilNoteViewController setupRangeNoteView]
-[WRReaderPencilNoteViewController setupRangeNoteView]_block_invoke
-[WRReaderPencilNoteViewController switchToRangeReview:curRange:curColorStyle:]
-[WRReaderPencilPageNoteListView addCanvasViewDrawingDidChangeBlockWithNoteView:]_block_invoke
-[WRReaderPencilPageNoteListView autoSaveEditingDrawingToLocalAsDraft]
-[WRReaderPencilPageNoteListView handleUpdatePageNoteReviewsWithBlock:]
-[WRReaderProgressChangeView handleNextButtonClick:]
-[WRReaderProgressChangeView handlePreButtonClick:]
-[WRReaderProgressChangeView sizeThatFits:]
-[WRReaderProgressData initWithBook:forPDF:]
-[WRReaderProgressData toCGIJsonDict]
-[WRReaderReviewsRNViewController handleWriteReviewButtonEvent:]
-[WRReaderSegmentViewController handleNotesOutputComputerButton]_block_invoke_2
-[WRReaderSegmentViewController initNoteControllerIfNeeded]
-[WRReaderSinglePurchaseEndTrailBookContentView renderData]
-[WRReaderTextSelector updateTurningPageTimerWithGesture:]
-[WRReaderTimer handleReadingTime:]
-[WRReaderTimer setActive:]
-[WRReaderTimer startTimer]
-[WRReaderUnderlineStyleButtonManager updateSelectedStyleButtonUI]
-[WRReaderViewController _saveReadingProgressAndIsAsync:]
-[WRReaderViewController addObservers]_block_invoke
-[WRReaderViewController addObservers]_block_invoke_2
-[WRReaderViewController animateAfterWritePageReview]_block_invoke
-[WRReaderViewController autoTestGetCurrentScreenContentString]
-[WRReaderViewController calculateReadingTimeAndUploadIfNeeded]
-[WRReaderViewController calculateReadingTimeFromLastReadDate]
-[WRReaderViewController canReadFromLocalWithChapterData:]
-[WRReaderViewController changeTypesetterAttributesWithBlock:]
-[WRReaderViewController checkLocationInCurrentPage:stringLocation:chapterIdx:]
-[WRReaderViewController detectExcessPageViews]
-[WRReaderViewController didEnterBackGround]
-[WRReaderViewController didEnterForeGround]
-[WRReaderViewController didFlipPage]
-[WRReaderViewController didReceiveMemoryWarning]
-[WRReaderViewController firstlyWillRenderPageView:progressData:source:]
-[WRReaderViewController gotoChapterIdx:filePosition:pageOfFlyleaf:shouldAutoJumpToCover:]
-[WRReaderViewController gotoChapterIdx:position:positionOfFile:]
-[WRReaderViewController handleBackProgressButtonClick:]
-[WRReaderViewController handleLastPageGesture:]
-[WRReaderViewController handleLastPageTapGesture:]
-[WRReaderViewController handleSizeChanged]
-[WRReaderViewController initChapterPageCount]
-[WRReaderViewController initChapterPageCount]_block_invoke
-[WRReaderViewController initChapterPageCount]_block_invoke_3
-[WRReaderViewController initWithBook:progress:forceUseInitialProgress:doodleMode:autoRead:]
-[WRReaderViewController initWithBookId:]
-[WRReaderViewController invokeVaildReadingProgress]
-[WRReaderViewController isLastPageWithChapterIdx:page:]
-[WRReaderViewController isReviewChapterFirstPageWithChapterData:page:]
-[WRReaderViewController isReviewChapterInMiddlePageWithChapterData:page:]
-[WRReaderViewController isReviewChapterLastPageWithChapterData:page:]
-[WRReaderViewController jumpReadingToNeigbourChapterForward:]
-[WRReaderViewController jumpReadingToNextChapter]
-[WRReaderViewController jumpReadingToPreChapter]
-[WRReaderViewController jumpToChapterUid:chapterOffset:shouldAutoJumpToCover:jumpToCloseChapterIdxIfNotExists:jumpFromStartProgress:completion:]
-[WRReaderViewController jumpToChapterUid:chapterOffset:shouldAutoJumpToCover:jumpToCloseChapterIdxIfNotExists:jumpFromStartProgress:completion:]_block_invoke
-[WRReaderViewController jumpToChapterUid:page:]
-[WRReaderViewController loadCurrentPagePencilNotes]
-[WRReaderViewController pageView:didClickPencilNote:]
-[WRReaderViewController recomposeAndClearCache:]
-[WRReaderViewController recomposeCurrentPageViewWithSource:]
-[WRReaderViewController recomposeLoadedPageView:]
-[WRReaderViewController refreshWithBook:]
-[WRReaderViewController reloadCurrentPageView]
-[WRReaderViewController reloadPageViewsWithProgressData:source:]
-[WRReaderViewController removeAllPageViewLinkBookPaperHighlight]
-[WRReaderViewController removeExcessPageViews:pageViewsToKeep:]
-[WRReaderViewController renderErrorPageView:error:chapter:andChapterFormat:progressData:source:]
-[WRReaderViewController renderLoadingContentPageView:progressData:source:]
-[WRReaderViewController renderLoadingContentPageView:progressData:source:]_block_invoke
-[WRReaderViewController renderPageView:nextToChapterIdx:page:]
-[WRReaderViewController renderPageView:previousToChapterIdx:page:]
-[WRReaderViewController renderPageView:progressData:source:]
-[WRReaderViewController savePreviousPagePencilNote]
-[WRReaderViewController scrollToLastReadingProgressIfNeeded]
-[WRReaderViewController setBaseReaderViewModel:]_block_invoke_2
-[WRReaderViewController showMileStoreRemind]
-[WRReaderViewController startShowingReadingPageView]
-[WRReaderViewController syncAuthorFlyleafDatas]
-[WRReaderViewController syncBookInfoAndChapterInfoWithCallback:]_block_invoke
-[WRReaderViewController syncFlyleapDataWithBook:]
-[WRReaderViewController tryToJumpToAuthorFlyLeafPage]
-[WRReaderViewController tryToJumpToAuthorFlyLeafPage]_block_invoke
-[WRReaderViewController turnToPlayingFileLocation:stringLocation:chapterIdx:]
-[WRReaderViewController uploadReadingProgressWithCallback:]
-[WRReaderViewController viewDidLoad]
-[WRReaderViewController viewWillDisappear:]
-[WRReaderViewController willPopInNavigationControllerWithAnimated:]
-[WRReaderViewModel loadChapterDataWithChapterIdx:reviewVid:tryRead:callback:]
-[WRReaderViewModel updateInfoAfterAutoPaidChapter:]
@@ -1,320 +0,0 @@
DTCoreText
DTCoreTextFontCollection
DTCoreTextFontDescriptor
DTCoreTextGlyphRun
DTCoreTextLayoutFrame
DTCoreTextLayoutFrameAccessibilityElementGenerator
DTCoreTextLayoutLine
DTCoreTextLayouter
DTCoreTextParagraphStyle
DTHTMLAttributedStringBuilder
DTHTMLElement
DTHTMLParser
DTHTMLParserDelegate
DTHTMLParserNode
DTHTMLParserTextNode
WRBookMarketManager
WRBookMarketRankListDataSource
WRBookMarketSearchData
WRBookMarketSearchDataSource
WRBookMarketUIHelper
WRBookMarketViewController
WRBookNetwork
WRBookNetworkReporter
WRBookmark
WRChapter
WRChapterAnchor
WRChapterData
WRChapterDownloadManger
WRChapterDownloadParam
WRChapterListener
WRChapterPageCount
WRChapterReadData
WRChapterRecommendAlbumsView
WRChapterRecommendAlbumsViewCell
WRChapterReviewsDownLoadModel
WRCoreTextFloatStatement
WRCoreTextImageAttributedStringFormatter
WRCoreTextLayoutFrame
WRCoreTextLayouter
WREncryptedFileManager
WREpubPage
WREpubParser
WREpubPositionConverter
WREpubTypesetter
WRMarkContent
WRMarkContentChapter
WRMarkContentInfoViewModel
WRMarkContentStore
WRMarkContentViewModel
WRMarketIcon
WRMarketNetwork
WRMarketPopToBookShelfTransition
WRMarketPopToDiscoverTransition
WRMarketPushToSearchTransition
WRMarketSearchModel
WRMarketSearchScopeTab
WRPageAVAttachment
WRPageAudioAttachment
WRPageAudioView
WRPageBookAttachment
WRPageBookView
WRPageChapterRewardAttachment
WRPageChapterRewardView
WRPageChapterToolAttachment
WRPageChapterToolAttachmentDelegate
WRPageChapterToolAttachmentHelper
WRPageChapterToolDelegate
WRPageChapterToolModel
WRPageChapterToolShareTipsView
WRPageChapterToolStore
WRPageCodeView
WRPageCodeViewController
WRPageComicView
WRPageCountReportManager
WRPageCoverAttachment
WRPageCoverAttachmentDelegate
WRPageCoverOrPageFlyleafAttachmentDelegate
WRPageData
WRPageElement
WRPageFlowCollectionViewLayout
WRPageFlyleafAttachment
WRPageHighlight
WRPageHighlightView
WRPageHyperlinksAttachment
WRPageHyperlinksAttachmentDelegate
WRPageIframeAttachment
WRPageIframeView
WRPageImageAttachment
WRPageImageAttachmentDelegate
WRPageImageAttachmentPreviewDelegate
WRPageImageAttachmentPreviewViewController
WRPageImageView
WRPageMark
WRPageMarkDelegate
WRPageMarkView
WRPagePreAttachment
WRPageRemindView
WRPageSearchHighlight
WRPageSliderAttachment
WRPageTableAttachment
WRPageTextView
WRPageTextViewDelegate
WRPageTurnModeControl
WRPageUnderline
WRPageVideoView
WRPageView
WRPageViewController
WRPageViewControllerDelegate
WRPageViewDelegate
WRPageViewRichElementStub
WRPreloadBookManager
WRPreloadBookSettingHeaderView
WRPreloadBookSettingViewController
WRPreloadStatisticsManager
WRReaderAIKnowledgeViewController
WRReaderAdDialog
WRReaderAnchorManager
WRReaderAuthorReviewDetailViewController
WRReaderAuthorReviewListViewCell
WRReaderAuthorReviewListViewController
WRReaderAutoPlayer
WRReaderAutoPlayerDelegate
WRReaderBackground
WRReaderBackgroundAdapter
WRReaderBackgroundChangeCell
WRReaderBackgroundChangeView
WRReaderBasePopupCellAdapter
WRReaderBitmapColorHelper
WRReaderBodyImageHelper
WRReaderBookBorrowUtils
WRReaderBookIntroControl
WRReaderBookReviewStarView
WRReaderBookmarkCell
WRReaderBookmarkViewController
WRReaderBorrowButton
WRReaderBrightnessBackgroundButton
WRReaderBrightnessChangeView
WRReaderBusinessHelper
WRReaderCatalogBaseCell
WRReaderCatalogBaseCellModel
WRReaderCatalogBaseCellView
WRReaderCatalogBatchBuyChapterView
WRReaderCatalogBookMarkCell
WRReaderCatalogBookMarkCellView
WRReaderCatalogCell
WRReaderCatalogCellUtils
WRReaderCatalogContainerViewController
WRReaderCatalogCurrentReadingInfo
WRReaderCatalogDataSource
WRReaderCatalogDataSourceDelegate
WRReaderCatalogDataSourceProtocol
WRReaderCatalogFooterCell
WRReaderCatalogHeaderView
WRReaderCatalogItemModel
WRReaderCatalogReadingCell
WRReaderCatalogReadingCellModel
WRReaderCatalogReadingCellView
WRReaderCatalogSearchHistoryView
WRReaderCatalogSearchManager
WRReaderCatalogSectionItem
WRReaderCatalogTableHeaderView
WRReaderCatalogViewController
WRReaderChangeFirstIndentTableViewCell
WRReaderChangeFirstIndentTableViewCellItemView
WRReaderChangeFirstIndentView
WRReaderChangeFirstIndentViewController
WRReaderChangeOrientationView
WRReaderChangeOrientationViewController
WRReaderChangePageTurningStyleView
WRReaderChangePageTurningStyleViewController
WRReaderCht2sManager
WRReaderColorThemeManager
WRReaderColorableProtocol
WRReaderComicsViewModel
WRReaderContentNavigationBottomControl
WRReaderContentNavigationControl
WRReaderContentNavigationManager
WRReaderContentNavigationTopControl
WRReaderContext
WRReaderControlBarView
WRReaderCurProgressTipsView
WRReaderDictionaryAIKnowledgeCollectionViewCell
WRReaderDictionaryCollectionBaseViewCell
WRReaderDictionaryCollectionResultViewCell
WRReaderDictionaryCollectionView
WRReaderDictionaryEncyclopediaCollectionViewCell
WRReaderDictionarySearchCollectionViewCell
WRReaderDictionaryTranslationCollectionViewCell
WRReaderDictionaryView
WRReaderDictionaryViewController
WRReaderEndOfTrialButton
WRReaderEndOfTrialView
WRReaderExchangePushInfo
WRReaderExperienceViewController
WRReaderFloatReviewsViewController
WRReaderFont
WRReaderFontChangeCategoryViewController
WRReaderFontChangeCategoryViewModel
WRReaderFontChangeCell
WRReaderFontChangeModalView
WRReaderFontChangeShareViewModel
WRReaderFontChangeTabsView
WRReaderFontChangeViewController
WRReaderFontConfig
WRReaderFontSizeChangeView
WRReaderFontTableViewCell
WRReaderFooterPageView
WRReaderFooternotePopupView
WRReaderHotUnderLinesTotalCountViewController
WRReaderHotUnderlinesCell
WRReaderHotUnderlinesViewController
WRReaderIncentiveButton
WRReaderInfoDebuggerViewController
WRReaderInfoDebuggerViewModel
WRReaderLastPageActionButton
WRReaderLastPageActionButtonContainerView
WRReaderLastPageBadgeView
WRReaderLastPageDelegate
WRReaderLastPageHelper
WRReaderLastPageMilestoneCardView
WRReaderLastPageReviewItem
WRReaderLastPageReviewsView
WRReaderLastPageViewController
WRReaderMaskProtocol
WRReaderMaskViewController
WRReaderMenuView
WRReaderMilestoneLabelView
WRReaderMistakeDialogContentView
WRReaderMistakeViewController
WRReaderModalView
WRReaderMoreOperationController
WRReaderNoteViewModel
WRReaderNotesSectionHeaderView
WRReaderOSSLogHelper
WRReaderOutlineViewController
WRReaderPaidVIPButton
WRReaderPanelSelectionView
WRReaderPanelSelectionViewController
WRReaderPencilNote
WRReaderPencilNoteBackgroundView
WRReaderPencilNoteBaseView
WRReaderPencilNoteButtonGroupView
WRReaderPencilNoteEraserTips
WRReaderPencilNoteEraserTipsManager
WRReaderPencilNoteHelper
WRReaderPencilNoteManager
WRReaderPencilNoteMaskView
WRReaderPencilNoteRangeReviewItem
WRReaderPencilNoteRangeReviewsPanel
WRReaderPencilNoteReviewManager
WRReaderPencilNoteTopToolView
WRReaderPencilNoteViewController
WRReaderPencilPageNoteListView
WRReaderPencilPageNoteView
WRReaderPencilRangeNoteView
WRReaderPlayerEntranceView
WRReaderPopupInfoTableViewCell
WRReaderPopupLoadMoreTableViewCell
WRReaderPopupReviewTableViewCell
WRReaderPresellPageView
WRReaderProgress
WRReaderProgressButton
WRReaderProgressChangeRuleView
WRReaderProgressChangeView
WRReaderProgressData
WRReaderProgressShareView
WRReaderProgressSlider
WRReaderProgressSliderDelegate
WRReaderProgressSmallChangeView
WRReaderReadOverToBuyView
WRReaderRefreshFooterView
WRReaderRefreshHeaderView
WRReaderReivewCountLabel
WRReaderReviewToolsView
WRReaderReviewsRNViewController
WRReaderSearchTableHeaderView
WRReaderSegmentViewController
WRReaderSettingPanelManager
WRReaderSettingPanelView
WRReaderSettingProtocol
WRReaderSinglePurchaseEndTrailBookContentView
WRReaderSizeManager
WRReaderStatisticPanelViewController
WRReaderStatisticRNViewController
WRReaderTextSelector
WRReaderTimeHelper
WRReaderTimer
WRReaderTraditionalChineseView
WRReaderTranslationManager
WRReaderTranslationUpgradeViewController
WRReaderUIFactory
WRReaderUnderlineStyleButtonManager
WRReaderVIPButton
WRReaderVIPButtonProtocol
WRReaderViewController
WRReaderViewControllerDelegate
WRReaderViewControllerHelper
WRReaderViewModel
WRReaderVisiblePageInfo
WRReaderVoteView
WRReaderWelfareCoinPanel
WRReaderWriteReviewSimpleView
WRUnderLineView
WRUnderline
WRUnderlineColorButtonsScrollView
WRUnderlineLayoutManager
WRUnderlineStore
WrBookmarkLoadErrorReport
WrBookmarkLoadErrorReportRoot
WrPageFlippingAnimationTypeRoot
WrReaderActionReport
WrReaderActionReportRoot
WrReaderActionRoot
WrReaderItemtypeRoot
WrReaderModuleRoot
WrReaderPayingtypeRoot
WrReaderSearchAuthoriedFailedTypeRoot
WrReaderSearchFailedtypeRoot
WrReaderSearchWords
WrReaderSearchWordsRoot
@@ -1,798 +0,0 @@
ivarLayout 0x1031bcf9c
layout map 0x11 0x12
name 0x1031bcf89 DTCoreTextLayouter
baseMethods 0x102acf508
entsize 12 (relative)
count 12
name 0x104ef88 (0x103b1e498)
types 0x95e950 (0x10342de64) @24@0:8@16
imp 0xfd5764d8 (0x1000459f0)
name 0x103a3ec (0x103b09908)
types 0x95e89b (0x10342ddbb) v16@0:8
imp 0xfd576560 (0x100045a84)
name 0x1058528 (0x103b27a50)
types 0x95ff95 (0x10342f4c1) @64@0:8{CGRect={CGPoint=dd}{CGSize=dd}}16{_NSRange=QQ}48
imp 0xfd576598 (0x100045ac8)
name 0x102881c (0x103af7d50)
types 0x95e883 (0x10342ddbb) v16@0:8
imp 0xfd576734 (0x100045c70)
name 0x10436d0 (0x103b12c10)
types 0x95ffb6 (0x10342f4fa) ^{__CTFramesetter=}16@0:8
imp 0xfd576754 (0x100045c9c)
name 0x1075b84 (0x103b450d0)
types 0x95e860 (0x10342ddb0) v24@0:8@16
imp 0xfd5767c4 (0x100045d18)
name 0x102e2c8 (0x103afd820)
types 0x95e84c (0x10342dda8) @16@0:8
imp 0xfd57684c (0x100045dac)
name 0x108cf3c (0x103b5c4a0)
types 0x95e8b5 (0x10342de1d) v20@0:8B16
imp 0xfd576848 (0x100045db4)
name 0x1094710 (0x103b63c80)
types 0x95e9a8 (0x10342df1c) B16@0:8
imp 0xfd57689c (0x100045e14)
--
reserved 0x0
ivarLayout 0x0
name 0x1031bcf89 DTCoreTextLayouter
baseMethods 0x0
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
000000010383bc60 0x103ba2550
isa 0x103ba2528
superclass 0x0 _OBJC_CLASS_$_NSObject
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x10388b308
flags 0x90
instanceStart 8
instanceSize 8
reserved 0x0
ivarLayout 0x0
name 0x1031bcf9f TABAnimatedChainManagerImpl
baseMethods 0x102acf5a0
entsize 12 (relative)
count 3
name 0x1033af0 (0x103b03098)
types 0x95ff9d (0x10342f549) v48@0:8@16@24@?32@40
imp 0xfd576cac (0x10004625c)
name 0x1033aec (0x103b030a0)
types 0x95ffa6 (0x10342f55e) v56@0:8@16@24@?32#40@48
imp 0xfd576d1c (0x1000462d8)
name 0x103bf00 (0x103b0b4c0)
types 0x95e7f7 (0x10342ddbb) v16@0:8
imp 0xfd576d9c (0x100046364)
baseProtocols 0x10388b260
--
ivarLayout 0x1031bc939
layout map 0x04
name 0x1031bfb46 WREpubParser
baseMethods 0x102aec440
entsize 12 (relative)
count 11
name 0x1032c20 (0x103b1f068)
types 0x9419c3 (0x10342de0f) @32@0:8@16@24
imp 0xfd7ec460 (0x1002d88b0)
name 0x10459b4 (0x103b31e08)
types 0x941ac4 (0x10342df1c) B16@0:8
imp 0xfd7ec68c (0x1002d8ae8)
name 0x1023418 (0x103b0f878)
types 0x9419c4 (0x10342de28) v32@0:8@16@24
imp 0xfd7ec6b4 (0x1002d8b1c)
name 0x102f9b4 (0x103b1be20)
types 0x94199f (0x10342de0f) @32@0:8@16@24
imp 0xfd7ed284 (0x1002d96f8)
name 0x102f5a0 (0x103b1ba18)
types 0x941993 (0x10342de0f) @32@0:8@16@24
imp 0xfd7ed468 (0x1002d98e8)
name 0x101a8d4 (0x103b06d58)
types 0x941987 (0x10342de0f) @32@0:8@16@24
imp 0xfd7ed4ec (0x1002d9978)
name 0x100ead8 (0x103afaf68)
types 0x9454c8 (0x10343195c) v40@0:8@16@24Q32
imp 0xfd7ed82c (0x1002d9cc4)
name 0x100dc6c (0x103afa108)
types 0x94b021 (0x1034374c1) v56@0:8@16@24Q32@40@48
imp 0xfd7edbd0 (0x1002da074)
name 0x10233c8 (0x103b0f870)
types 0x94197c (0x10342de28) v32@0:8@16@24
imp 0xfd7ee028 (0x1002da4d8)
--
reserved 0x0
ivarLayout 0x0
name 0x1031bfb46 WREpubParser
baseMethods 0x102aec428
entsize 12 (relative)
count 1
name 0x1046580 (0x103b329b0)
types 0x941a30 (0x10342de64) @24@0:8@16
imp 0xfd7ee188 (0x1002da5c0)
baseProtocols 0x1038b61b8
count 1
list[0] 0x103c17ce8
isa 0x0
name 0x1031bfb53 KFEpubControllerDelegate
protocols 0x1038b6130
count 1
list[0] 0x103c15580
isa 0x0
name 0x1031bc9c5 NSObject
protocols 0x0
instanceMethods 0x103884670
entsize 24
count 19
name 0x103348607 isEqual:
types 0x10342de6f B24@0:8@16
imp 0x0
name 0x1032e9bde class
types 0x10342df44 #16@0:8
imp 0x0
name 0x1033a90f1 self
types 0x10342dda8 @16@0:8
imp 0x0
name 0x1033780e4 performSelector:
--
ivarLayout 0x1031bfd8e
layout map 0x16 0x1c 0x12 0x15 0x11
name 0x1031bfd80 WRChapterData
baseMethods 0x102aeddf0
entsize 12 (relative)
count 118
name 0x102f158 (0x103b1cf50)
types 0x93ffac (0x10342dda8) @16@0:8
imp 0xfd809f38 (0x1002f7d38)
name 0x101552c (0x103b03330)
types 0x940101 (0x10342df09) q16@0:8
imp 0xfd809f80 (0x1002f7d8c)
name 0x1019920 (0x103b07730)
types 0x94150c (0x10342f320) {_NSRange=QQ}16@0:8
imp 0xfd80a044 (0x1002f7e5c)
name 0x103fd04 (0x103b2db20)
types 0x941500 (0x10342f320) {_NSRange=QQ}16@0:8
imp 0xfd80a07c (0x1002f7ea0)
name 0x1033920 (0x103b21748)
types 0x9400dd (0x10342df09) q16@0:8
imp 0xfd80a0b0 (0x1002f7ee0)
name 0x10353cc (0x103b23200)
types 0x94427a (0x1034320b2) B24@0:8q16
imp 0xfd80a0bc (0x1002f7ef8)
name 0x10353c8 (0x103b23208)
types 0x94426e (0x1034320b2) B24@0:8q16
imp 0xfd80a158 (0x1002f7fa0)
name 0x1035b9c (0x103b239e8)
types 0x944262 (0x1034320b2) B24@0:8q16
imp 0xfd80a18c (0x1002f7fe0)
name 0x1035c60 (0x103b23ab8)
types 0x944256 (0x1034320b2) B24@0:8q16
imp 0xfd80a1c0 (0x1002f8020)
--
reserved 0x0
ivarLayout 0x0
name 0x1031bfd80 WRChapterData
baseMethods 0x102aedd90
entsize 12 (relative)
count 7
name 0x100d288 (0x103afb020)
types 0x949a69 (0x103437805) v64@0:8@16{_NSRange=QQ}24q40q48@56
imp 0xfd80a52c (0x1002f82cc)
name 0x101d21c (0x103b0afc0)
types 0x940008 (0x10342ddb0) v24@0:8@16
imp 0xfd80a694 (0x1002f8440)
name 0x10161e8 (0x103b03f98)
types 0x949a74 (0x103437828) B40@0:8{_NSRange=QQ}16Q32
imp 0xfd80c140 (0x1002f9ef8)
name 0x1078b54 (0x103b66910)
types 0x9400a4 (0x10342de64) @24@0:8@16
imp 0xfd80c154 (0x1002f9f18)
name 0x1036ed8 (0x103b24ca0)
types 0x94008a (0x10342de56) B32@0:8@16@24
imp 0xfd80cf10 (0x1002face0)
name 0x104396c (0x103b31740)
types 0x949a6a (0x103437842) {_NSRange=QQ}32@0:8q16@24
imp 0xfd80e084 (0x1002fbe60)
name 0x1024f08 (0x103b12ce8)
types 0x9422b4 (0x103430098) q32@0:8@16@24
imp 0xfd80e738 (0x1002fc520)
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
000000010383c6c8 0x103ba8d38
isa 0x103ba8d60
--
ivarLayout 0x1031c36ba
layout map 0x01 0xa2
name 0x1031c36a4 WRCoreTextLayoutFrame
baseMethods 0x102b1a760
entsize 12 (relative)
count 47
name 0x1004bd8 (0x103b1f340)
types 0x922b0e (0x10343d27a) @80@0:8^{__CTFramesetter=}16@24{_NSRange=QQ}32{CGRect={CGPoint=dd}{CGSize=dd}}48
imp 0xfdba1dec (0x1006bc55c)
name 0xff9e1c (0x103b14590)
types 0x9137ac (0x10342df24) d16@0:8
imp 0xfdba1ef4 (0x1006bc670)
name 0x10388c8 (0x103b53048)
types 0x9143b0 (0x10342eb34) v48@0:8{CGRect={CGPoint=dd}{CGSize=dd}}16
imp 0xfdba1ef0 (0x1006bc678)
name 0x101dd44 (0x103b384d0)
types 0x922b3b (0x10343d2cb) B48@0:8{_NSRange=QQ}16{_NSRange=QQ}32
imp 0xfdba2028 (0x1006bc7bc)
name 0xfffc48 (0x103b1a3e0)
types 0x9136d3 (0x10342de6f) B24@0:8@16
imp 0xfdba2034 (0x1006bc7d4)
name 0x1007a5c (0x103b22200)
types 0x917ade (0x103432286) B32@0:8{_NSRange=QQ}16
imp 0xfdba20d0 (0x1006bc87c)
name 0xfed5f0 (0x103b07da0)
types 0x922b3d (0x10343d2f1) @64@0:8^{__CTTypesetter=}16d24{_NSRange=QQ}32d48@56
imp 0xfdba218c (0x1006bc944)
name 0x100debc (0x103b28678)
types 0x9135e8 (0x10342dda8) @16@0:8
imp 0xfdba2f20 (0x1006bd6e4)
name 0xfec0d0 (0x103b06898)
types 0x91373d (0x10342df09) q16@0:8
imp 0xfdba4788 (0x1006bef58)
--
reserved 0x0
ivarLayout 0x0
name 0x1031c36a4 WRCoreTextLayoutFrame
baseMethods 0x102b1a650
entsize 12 (relative)
count 2
name 0xfecc98 (0x103b072f0)
types 0x922bcf (0x10343d22b) @64@0:8@16@24{_NSRange=QQ}32{_NSRange=QQ}48
imp 0xfdba9834 (0x1006c3e94)
name 0x10492bc (0x103b63920)
types 0x922bef (0x10343d257) B60@0:8@16@24{_NSRange=QQ}32q48B56
imp 0xfdba9a84 (0x1006c40f0)
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
000000010383d6e0 0x103bb2e28
isa 0x103bb2e50
superclass 0x0 _OBJC_CLASS_$_QMUINavigationButton
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x103901990
flags 0x194 RO_HAS_CXX_STRUCTORS
instanceStart 8
instanceSize 56
reserved 0x0
ivarLayout 0x1031bcc1a
layout map 0x12
name 0x1031c36bd WRReviewNavigationButton
baseMethods 0x102b1a9a0
entsize 12 (relative)
count 15
name 0x10025a8 (0x103b1cf50)
--
reserved 0x0
ivarLayout 0x0
name 0x1031c405b DTCoreTextLayoutFrameAccessibilityElementGenerator
baseMethods 0x102b22c00
entsize 12 (relative)
count 7
name 0xfd6a98 (0x103af96a0)
types 0x90c852 (0x10342f45e) @40@0:8@16@24@?32
imp 0xfdc59bb0 (0x10077c7c0)
name 0xfd6a94 (0x103af96a8)
types 0x91ba43 (0x10343e65b) @48@0:8Q16@24@32@?40
imp 0xfdc59ccc (0x10077c8e8)
name 0xfeca30 (0x103b0f650)
types 0x91194f (0x103434573) v40@0:8@16Q24@?32
imp 0xfdc59ee0 (0x10077cb08)
name 0xfd6a64 (0x103af9690)
types 0x91ba40 (0x10343e670) @72@0:8@16{_NSRange=QQ}24@40@48@56@?64
imp 0xfdc5a1b0 (0x10077cde4)
name 0xfd6a50 (0x103af9688)
types 0x91ba5b (0x10343e697) @64@0:8@16{_NSRange=QQ}24@40@48@56
imp 0xfdc5a2d4 (0x10077cf14)
name 0x104f19c (0x103b71de0)
types 0x90c807 (0x10342f44f) @32@0:8@16@?24
imp 0xfdc5a468 (0x10077d0b4)
name 0xfeff18 (0x103b12b68)
types 0x914fd8 (0x103437c2c) {CGRect={CGPoint=dd}{CGSize=dd}}24@0:8@16
imp 0xfdc5a490 (0x10077d0e8)
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
Meta Class
isa 0x0 _OBJC_METACLASS_$_NSObject
--
reserved 0x0
ivarLayout 0x0
name 0x1031c405b DTCoreTextLayoutFrameAccessibilityElementGenerator
baseMethods 0x0
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
000000010383d9a0 0x103bb49a8
isa 0x103bb49d0
superclass 0x0 _OBJC_CLASS_$_UICollectionView
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x10390e140
flags 0x194 RO_HAS_CXX_STRUCTORS
instanceStart 8
instanceSize 48
reserved 0x0
ivarLayout 0x1031bcd23
layout map 0x11
name 0x1031c408e WRDiscoverCollectionView
baseMethods 0x102b22c60
entsize 12 (relative)
count 20
name 0x1001838 (0x103b244a0)
types 0x90b2b0 (0x10342df1c) B16@0:8
imp 0xfdc5a9b8 (0x10077d628)
name 0x101ef44 (0x103b41bb8)
types 0x91ba42 (0x10343e6ba) v36@0:8Q16B24@?28
imp 0xfdc5aa5c (0x10077d6d8)
name 0x1049f78 (0x103b6cbf8)
types 0x90b1eb (0x10342de6f) B24@0:8@16
imp 0xfdc5abc0 (0x10077d848)
--
ivarLayout 0x1031c51df
layout map 0x12 0x11 0x21
name 0x1031c51cc WRChapterPageCount
baseMethods 0x102b2ed70
entsize 12 (relative)
count 29
name 0xfefcf8 (0x103b1ea70)
types 0x910f9d (0x10343fd19) @40@0:8@16Q24q32
imp 0xfdd88e88 (0x1008b7c08)
name 0x100981c (0x103b385a0)
types 0x908ad4 (0x10343785c) {_NSRange=QQ}24@0:8q16
imp 0xfdd892a4 (0x1008b8030)
name 0xff70c8 (0x103b25e58)
types 0x8ff014 (0x10342dda8) @16@0:8
imp 0xfdd89500 (0x1008b8298)
name 0x1023294 (0x103b52030)
types 0x8ff010 (0x10342ddb0) v24@0:8@16
imp 0xfdd89504 (0x1008b82a8)
name 0xfd4710 (0x103b034b8)
types 0x8feffc (0x10342dda8) @16@0:8
imp 0xfdd89504 (0x1008b82b4)
name 0x10190fc (0x103b47eb0)
types 0x8feff8 (0x10342ddb0) v24@0:8@16
imp 0xfdd89508 (0x1008b82c4)
name 0xfd4650 (0x103b03410)
types 0x8ff145 (0x10342df09) q16@0:8
imp 0xfdd89508 (0x1008b82d0)
name 0x1019084 (0x103b47e50)
types 0x8ff141 (0x10342df11) v24@0:8q16
imp 0xfdd8950c (0x1008b82e0)
name 0xfd0fb0 (0x103affd88)
types 0x8fefcc (0x10342dda8) @16@0:8
imp 0xfdd89510 (0x1008b82f0)
--
reserved 0x0
ivarLayout 0x0
name 0x1031c51cc WRChapterPageCount
baseMethods 0x102b2ece0
entsize 12 (relative)
count 11
name 0xff2708 (0x103b213f0)
types 0x8ff0bc (0x10342dda8) @16@0:8
imp 0xfddc1db4 (0x1008f0aa4)
name 0xfdab1c (0x103b09810)
types 0x8ff0b0 (0x10342dda8) @16@0:8
imp 0xfddc1dc4 (0x1008f0ac0)
name 0x103b978 (0x103b6a678)
types 0x8ff0a4 (0x10342dda8) @16@0:8
imp 0xfddc1dc4 (0x1008f0acc)
name 0x10063cc (0x103b350d8)
types 0x8ff098 (0x10342dda8) @16@0:8
imp 0xfddc1dc4 (0x1008f0ad8)
name 0x10046e8 (0x103b33400)
types 0x8ff08c (0x10342dda8) @16@0:8
imp 0xfddc1dc4 (0x1008f0ae4)
name 0xfdc50c (0x103b0b230)
types 0x8ff080 (0x10342dda8) @16@0:8
imp 0xfddc1df0 (0x1008f0b1c)
name 0x10027f0 (0x103b31520)
types 0x910fe5 (0x10343fd19) @40@0:8@16Q24q32
imp 0xfdd89030 (0x1008b7d68)
name 0xfd982c (0x103b08568)
types 0x9006b8 (0x10342f3f8) Q24@0:8@16
imp 0xfdd89128 (0x1008b7e6c)
name 0xfee0c0 (0x103b1ce08)
types 0x8ff05c (0x10342dda8) @16@0:8
imp 0xfdd892d4 (0x1008b8024)
--
ivarLayout 0x1031c6257
layout map 0x04 0x15 0x28
name 0x1031c624c WRPageView
baseMethods 0x102b3b018
entsize 12 (relative)
count 104
name 0xfe4310 (0x103b1f330)
types 0x9064ba (0x1034414de) @64@0:8{CGRect={CGPoint=dd}{CGSize=dd}}16Q48q56
imp 0xfde85418 (0x1009c0440)
name 0x10294e4 (0x103b64510)
types 0x8f2eec (0x10342df1c) B16@0:8
imp 0xfde854e0 (0x1009c0514)
name 0x102a918 (0x103b65950)
types 0x8f2d7f (0x10342ddbb) v16@0:8
imp 0xfde85584 (0x1009c05c4)
name 0xfe0064 (0x103b1b0a8)
types 0x8f2d73 (0x10342ddbb) v16@0:8
imp 0xfde85704 (0x1009c0750)
name 0xfe0068 (0x103b1b0b8)
types 0x8f2d67 (0x10342ddbb) v16@0:8
imp 0xfde85770 (0x1009c07c8)
name 0xfe2eec (0x103b1df48)
types 0x8f2d5b (0x10342ddbb) v16@0:8
imp 0xfde85798 (0x1009c07fc)
name 0xfe0048 (0x103b1b0b0)
types 0x8f2d4f (0x10342ddbb) v16@0:8
imp 0xfde85af0 (0x1009c0b60)
name 0xfe2ac4 (0x103b1db38)
types 0x8f2d43 (0x10342ddbb) v16@0:8
imp 0xfde85ca8 (0x1009c0d24)
name 0xfe66d8 (0x103b21758)
types 0x8f2d24 (0x10342dda8) @16@0:8
imp 0xfde85df8 (0x1009c0e80)
--
reserved 0x0
ivarLayout 0x0
name 0x1031c624c WRPageView
baseMethods 0x102b3b000
entsize 12 (relative)
count 1
name 0xff1cb8 (0x103b2ccc0)
types 0x8f6062 (0x10343106e) d32@0:8@16@24
imp 0xfde86674 (0x1009c1684)
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
000000010383e338 0x103bba998
isa 0x103bba9c0
superclass 0x103bc8688
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x103932f00
flags 0x194 RO_HAS_CXX_STRUCTORS
instanceStart 16
instanceSize 32
reserved 0x0
ivarLayout 0x1031bc967
layout map 0x02
name 0x1031c625b WRConfirmH5PayViewController
baseMethods 0x102b3b500
entsize 12 (relative)
count 15
name 0x10011c8 (0x103b3c6d0)
types 0x8f28af (0x10342ddbb) v16@0:8
imp 0xfde90aa0 (0x1009cbfb0)
name 0xfedbb4 (0x103b290c8)
--
ivarLayout 0x1031c646d
layout map 0x44 0x81 0x31
name 0x1031c6457 DTCoreTextLayoutFrame
baseMethods 0x102b3ca60
entsize 12 (relative)
count 54
name 0xfc84e8 (0x103b04f50)
types 0x8f4143 (0x103430baf) q32@0:8{CGPoint=dd}16
imp 0xfdd403fc (0x10087ce6c)
name 0xfcc3a4 (0x103b08e18)
types 0x900b89 (0x10343d601) {CGRect={CGPoint=dd}{CGSize=dd}}24@0:8q16
imp 0xfdd406b8 (0x10087d134)
name 0xfe2878 (0x103b1f2f8)
types 0x904d71 (0x1034417f5) @72@0:8{CGRect={CGPoint=dd}{CGSize=dd}}16@48{_NSRange=QQ}56
imp 0xfdeb5da4 (0x1009f282c)
name 0xfe2864 (0x103b1f2f0)
types 0x8fdd25 (0x10343a7b5) @56@0:8{CGRect={CGPoint=dd}{CGSize=dd}}16@48
imp 0xfdeb5f20 (0x1009f29b4)
name 0xfcce70 (0x103b09908)
types 0x8f131f (0x10342ddbb) v16@0:8
imp 0xfdeb5f20 (0x1009f29c0)
name 0xfce904 (0x103b0b3a8)
types 0x8f1300 (0x10342dda8) @16@0:8
imp 0xfdeb5f6c (0x1009f2a18)
name 0xfbacd8 (0x103af7788)
types 0x900b34 (0x10343d5e8) {CGPoint=dd}32@0:8@16@24
imp 0xfdeb5fa4 (0x1009f2a5c)
name 0xfbacdc (0x103af7798)
types 0x8f2c9e (0x10342f75e) d24@0:8@16
imp 0xfdeb6274 (0x1009f2d38)
name 0xfbacc8 (0x103af7790)
types 0x900b1c (0x10343d5e8) {CGPoint=dd}32@0:8@16@24
imp 0xfdeb6364 (0x1009f2e34)
--
reserved 0x0
ivarLayout 0x0
name 0x1031c6457 DTCoreTextLayoutFrame
baseMethods 0x102b3ca40
entsize 12 (relative)
count 2
name 0x101fb08 (0x103b5c550)
types 0x8f13d1 (0x10342de1d) v20@0:8B16
imp 0xfdeba310 (0x1009f6d60)
name 0x10273a4 (0x103b63df8)
types 0x8f14c4 (0x10342df1c) B16@0:8
imp 0xfdeba310 (0x1009f6d6c)
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
000000010383e3c8 0x103bbaf38
isa 0x103bbaf60
superclass 0x0 _OBJC_CLASS_$_UIView
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x103935920
flags 0x194 RO_HAS_CXX_STRUCTORS
instanceStart 8
instanceSize 280
reserved 0x0
ivarLayout 0x1031c64b4
layout map 0x02 0xb9
name 0x1031c647c WHLyricPageTextView
baseMethods 0x102b3ccf0
entsize 12 (relative)
count 60
name 0xfe0258 (0x103b1cf50)
--
reserved 0x0
ivarLayout 0x0
name 0x1031c67a2 WREpubTypesetter
baseMethods 0x0
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
Meta Class
isa 0x0 _OBJC_METACLASS_$_NSObject
superclass 0x0 _OBJC_METACLASS_$_NSObject
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x10393a6e8
flags 0x91 RO_META
instanceStart 40
instanceSize 40
reserved 0x0
ivarLayout 0x0
name 0x1031c67a2 WREpubTypesetter
baseMethods 0x102b40010
entsize 12 (relative)
count 9
name 0xfbd748 (0x103afd760)
types 0x902393 (0x1034423af) @92@0:8@16Q24B32B36B40@44@52q60^q68^B76@84
imp 0xfdf0898c (0x100a489ac)
name 0x102d67c (0x103b6d6a0)
types 0x9023b2 (0x1034423da) v52@0:8@16@24@32B40B44B48
imp 0xfdf09b70 (0x100a49b9c)
name 0xfc41f8 (0x103b04228)
types 0x9023c0 (0x1034423f4) v40@0:8@16^B24^B32
imp 0xfdf0a380 (0x100a4a3b8)
name 0xfe4fbc (0x103b24ff8)
types 0x8ede2f (0x10342de6f) B24@0:8@16
imp 0xfdf0a5b8 (0x100a4a5fc)
name 0xfc9180 (0x103b091c8)
types 0x8ede18 (0x10342de64) @24@0:8@16
imp 0xfdf0a644 (0x100a4a694)
name 0xfc917c (0x103b091d0)
types 0x8ede0c (0x10342de64) @24@0:8@16
imp 0xfdf0a754 (0x100a4a7b0)
name 0xfc9178 (0x103b091d8)
types 0x8ede97 (0x10342defb) @28@0:8@16B24
imp 0xfdf0a864 (0x100a4a8cc)
name 0xfe3dbc (0x103b23e28)
types 0x8eddff (0x10342de6f) B24@0:8@16
imp 0xfdf0aa10 (0x100a4aa84)
name 0xfc9170 (0x103b091e8)
types 0x8edd93 (0x10342de0f) @32@0:8@16@24
imp 0xfdf0aa70 (0x100a4aaf0)
--
ivarLayout 0x1031bc9ce
layout map 0x13
name 0x1031c67c4 WRCoreTextLayouter
baseMethods 0x102b40160
entsize 12 (relative)
count 15
name 0xfbd6f8 (0x103afd860)
types 0x8edc3c (0x10342dda8) @16@0:8
imp 0xfdf0b9a8 (0x100a4bb18)
name 0xfde32c (0x103b1e4a0)
types 0x8edc97 (0x10342de0f) @32@0:8@16@24
imp 0xfdf0ba50 (0x100a4bbcc)
name 0xfd2a90 (0x103b12c10)
types 0x8ef376 (0x10342f4fa) ^{__CTFramesetter=}16@0:8
imp 0xfdf0badc (0x100a4bc64)
name 0xfc7b5c (0x103b07ce8)
types 0x902277 (0x103442407) @72@0:8{_NSRange=QQ}16{CGRect={CGPoint=dd}{CGSize=dd}}32Q64
imp 0xfdf0bb4c (0x100a4bce0)
name 0x1004f38 (0x103b450d0)
types 0x8edc14 (0x10342ddb0) v24@0:8@16
imp 0xfdf0bc0c (0x100a4bdac)
name 0xff1274 (0x103b31418)
types 0x8f7c6e (0x103437e16) @40@0:8{_NSRange=QQ}16@32
imp 0xfdf0c034 (0x100a4c1e0)
name 0xff1270 (0x103b31420)
types 0x8f7c62 (0x103437e16) @40@0:8{_NSRange=QQ}16@32
imp 0xfdf0c1ac (0x100a4c364)
name 0xfd0444 (0x103b10600)
types 0x8edbe8 (0x10342dda8) @16@0:8
imp 0xfdf0c410 (0x100a4c5d4)
name 0xfff160 (0x103b3f328)
types 0x902277 (0x103442443) @84@0:8@16{CGRect={CGPoint=dd}{CGSize=dd}}24Q56Q64B72@76
imp 0xfdf0c420 (0x100a4c5f0)
--
reserved 0x0
ivarLayout 0x0
name 0x1031c67c4 WRCoreTextLayouter
baseMethods 0x102b40118
entsize 12 (relative)
count 5
name 0x1028e50 (0x103b68f70)
types 0x8edd4b (0x10342de6f) B24@0:8@16
imp 0xfdf0b47c (0x100a4b5a4)
name 0xfe54fc (0x103b25628)
types 0x8edd3f (0x10342de6f) B24@0:8@16
imp 0xfdf0b7cc (0x100a4b900)
name 0x10300e8 (0x103b70220)
types 0x8f10a1 (0x1034311dd) v28@0:8B16@20
imp 0xfdf0b8b8 (0x100a4b9f8)
name 0xfc6ebc (0x103b07000)
types 0x8edd1c (0x10342de64) @24@0:8@16
imp 0xfdf0bd08 (0x100a4be54)
name 0xfc6eb8 (0x103b07008)
types 0x8edd10 (0x10342de64) @24@0:8@16
imp 0xfdf0c020 (0x100a4c178)
baseProtocols 0x0
ivars 0x0
weakIvarLayout 0x0
baseProperties 0x0
000000010383e4b8 0x103bbb898
isa 0x103bbb8c0
superclass 0x103bb0ee8
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x10393ab58
flags 0x194 RO_HAS_CXX_STRUCTORS
instanceStart 16
--
ivarLayout 0x1031c75f6
layout map 0x02 0x2f 0x01 0x33 0x11
name 0x1031c75c3 DTHTMLAttributedStringBuilder
baseMethods 0x102b4aa58
entsize 12 (relative)
count 25
name 0xfd4958 (0x103b1f3b8)
types 0x8eb102 (0x103435b66) @40@0:8@16@24^@32
imp 0xfdffe5dc (0x100b49044)
name 0xfacf14 (0x103af7980)
types 0x8e34ac (0x10342df1c) B16@0:8
imp 0xfdffe7dc (0x100b49250)
name 0xfc8d80 (0x103b137f8)
types 0x8e332c (0x10342dda8) @16@0:8
imp 0xfdfff100 (0x100b49b80)
name 0xfae034 (0x103af8ab8)
types 0x8e3333 (0x10342ddbb) v16@0:8
imp 0xfdfff124 (0x100b49bb0)
name 0xfae020 (0x103af8ab0)
types 0x8e3327 (0x10342ddbb) v16@0:8
imp 0xfdffff00 (0x100b4a998)
name 0xfe7d3c (0x103b327d8)
types 0x8f88ae (0x10344334e) v56@0:8@16@24@32{CGPoint=dd}40
imp 0xfe000968 (0x100b4b40c)
name 0xfe7d20 (0x103b327c8)
types 0x8e337c (0x10342de28) v32@0:8@16@24
imp 0xfe000efc (0x100b4b9ac)
name 0xfe7be4 (0x103b32698)
types 0x8e32f8 (0x10342ddb0) v24@0:8@16
imp 0xfe0010c8 (0x100b4bb84)
name 0xfe7d30 (0x103b327f0)
types 0x8e3364 (0x10342de28) v32@0:8@16@24
imp 0xfe0015b8 (0x100b4c080)
--
reserved 0x0
ivarLayout 0x0
name 0x1031c75c3 DTHTMLAttributedStringBuilder
baseMethods 0x0
baseProtocols 0x10394b7f0
count 1
list[0] 0x103c1bed0
isa 0x0
name 0x1031c75e1 DTHTMLParserDelegate
protocols 0x10394b690
count 1
list[0] 0x103c15580
isa 0x0
name 0x1031bc9c5 NSObject
protocols 0x0
instanceMethods 0x103884670
entsize 24
count 19
name 0x103348607 isEqual:
types 0x10342de6f B24@0:8@16
imp 0x0
name 0x1032e9bde class
types 0x10342df44 #16@0:8
imp 0x0
name 0x1033a90f1 self
types 0x10342dda8 @16@0:8
imp 0x0
name 0x1033780e4 performSelector:
types 0x10342df4c @24@0:8:16
imp 0x0
name 0x103378163 performSelector:withObject:
types 0x10342df57 @32@0:8:16@24
imp 0x0
--
ivarLayout 0x1031c0ccf
layout map 0x61
name 0x1031cb9a9 WRPageViewController
baseMethods 0x102b81cf8
entsize 12 (relative)
count 73
name 0xfbd2d0 (0x103b3efd0)
types 0x8ac0b7 (0x10342ddbb) v16@0:8
imp 0xfe4dedec (0x101060af4)
name 0xff0bac (0x103b728b8)
types 0x8c707f (0x103448d8f) v72@0:8@16q24{CGPoint=dd}32q48B56B60@?64
imp 0xfe4dedf0 (0x101060b04)
name 0xfdf8d0 (0x103b615e8)
types 0x8b32e5 (0x103435001) v44@0:8@16q24B32@?36
imp 0xfe4df5ec (0x10106130c)
name 0xf9d194 (0x103b1eeb8)
types 0x8bdff1 (0x10343fd19) @40@0:8@16Q24q32
imp 0xfe4df984 (0x1010616b0)
name 0xfaf870 (0x103b315a0)
types 0x8ac1d5 (0x10342df09) q16@0:8
imp 0xfe4dfba8 (0x1010618e0)
name 0xff0084 (0x103b71dc0)
types 0x8ac07b (0x10342ddbb) v16@0:8
imp 0xfe4dfbac (0x1010618f0)
name 0xff0038 (0x103b71d80)
types 0x8ac0d1 (0x10342de1d) v20@0:8B16
imp 0xfe4dfcb4 (0x101061a04)
name 0xf87bb4 (0x103b09908)
types 0x8ac063 (0x10342ddbb) v16@0:8
imp 0xfe4dfcf0 (0x101061a4c)
name 0xf78590 (0x103afa2f0)
types 0x8ac057 (0x10342ddbb) v16@0:8
imp 0xfe4dfe08 (0x101061b70)
--
reserved 0x0
ivarLayout 0x0
name 0x1031cb9a9 WRPageViewController
baseMethods 0x102b81c98
entsize 12 (relative)
count 7
name 0xf9f110 (0x103b20db0)
types 0x8ac117 (0x10342ddbb) v16@0:8
imp 0xfe4dc830 (0x10105e4d8)
name 0xfb0c9c (0x103b32948)
types 0x8ac10b (0x10342ddbb) v16@0:8
imp 0xfe4dc99c (0x10105e650)
name 0xfb0c88 (0x103b32940)
types 0x8ac0ff (0x10342ddbb) v16@0:8
imp 0xfe4dd264 (0x10105ef24)
name 0xfb0c74 (0x103b32938)
types 0x8ac0f3 (0x10342ddbb) v16@0:8
imp 0xfe4ddb28 (0x10105f7f4)
name 0xf89a18 (0x103b0b6e8)
types 0x8c708d (0x103448d61) B48@0:8@16@24B32B36B40B44
imp 0xfe4de164 (0x10105fe3c)
name 0xfa437c (0x103b26058)
types 0x8ae3b8 (0x103430098) q32@0:8@16@24
imp 0xfe4dedac (0x101060a90)
name 0xfe3180 (0x103b64e68)
types 0x8ac0c4 (0x10342ddb0) v24@0:8@16
imp 0xfe4e15b8 (0x1010632a8)
baseProtocols 0x1039a0c00
count 4
list[0] 0x103c17bc8
isa 0x0
name 0x1031bf992 UIPageViewControllerDataSource
protocols 0x1038b4590
+181
View File
@@ -0,0 +1,181 @@
# WXRead/resources 文件说明
## 目录结构
```
resources/
├── js/
│ ├── Text/ # 文本编辑/展示相关
│ │ ├── WeReadApi.js
│ │ ├── rich_editor.js
│ │ ├── rich_display.js
│ │ ├── correctArticle.js
│ │ └── style_html.js
│ ├── Readability.js
│ ├── weread-highlighter.js
│ ├── rangy-core.js
│ ├── rangy-classapplier.js
│ ├── rangy-highlighter.js
│ ├── rangy-textrange.js
│ ├── highlight.min.js
│ ├── cssInjector.js
│ └── patch_6.2.1.4.js
├── css/
│ ├── Style/
│ │ ├── style.css
│ │ ├── preview.css
│ │ └── normalize.css
│ ├── default.css
│ ├── dark.css
│ ├── replace.css
│ ├── replaceForLatinLanguageBook.css
│ ├── replaceForMPChapter.css
│ ├── MPExtra.css
│ ├── MediaPlatform.css
│ ├── WREpubMPVideo.css
│ └── xcode.min.css
└── fonts/ # 字体文件
```
---
## JS 文件
### 核心功能
#### `Readability.js`
Arc90 的 Readability 库 (v1.7.1),用于从网页中提取正文内容。通过正则匹配和 DOM 分析算法,从杂乱的 HTML 中识别出文章主体,过滤导航、广告、侧栏等非内容元素。是读书解析公众号文章内容的基础依赖。
#### `weread-highlighter.js`
读书的划线/高亮核心模块。依赖 Rangy 库实现以下功能:
- 初始化 Rangy 高亮器,注册 `highlight`(划线)、`review`(自己的想法)、`friend-review`(好友想法)、`reference`(想法圈划线)、`tts`(朗读高亮)等样式
- 监听 `selectionchange` 事件,将选区位置信息通过 `wereadBridge` 通知原生层
- 提供 `getShareAbstractText()` 从文章段落中提取分享摘要文本
- 字体缩放 `changeFontSizeWithScale()` 支持
- 图片点击事件绑定和 H5 链接转换
#### `cssInjector.js`
CSS 动态注入/移除工具。提供 `inject(json)``remove(identifier)` 两个方法,通过创建/删除 `<style>` 元素实现运行时样式切换。
#### `patch_6.2.1.4.js`
版本补丁脚本。修改 `WRAboutViewController``viewDidLoad`,将版权信息文案中的 "rights" 和 "reserved" 首字母改为大写。
### Rangy 库系列 (第三方)
#### `rangy-core.js`
Rangy 核心库 (v1.3.0, MIT License)。跨浏览器的 Range 和 Selection 操作库,提供统一的 API 处理 DOM 选区。
#### `rangy-classapplier.js`
Rangy ClassApplier 模块。对 Range 和 Selection 添加/移除/切换 CSS 类,是实现划线高亮的基础。
#### `rangy-highlighter.js`
Rangy Highlighter 模块。依赖 core 和 ClassApplier,提供更高层的文本高亮 API,支持序列化/反序列化高亮位置。
#### `rangy-textrange.js`
Rangy TextRange 模块。支持按字符/词偏移移动选区边界、文本搜索、选区保存/恢复等功能。
#### `highlight.min.js`
highlight.js 代码语法高亮库(压缩版)。用于在阅读器中高亮显示 `<pre><code>` 代码块。
### Text 子目录
#### `Text/WeReadApi.js`
读书 WebView Bridge。定义 `WeReadBridge` 类,通过隐藏 iframe + 自定义 URL scheme`wereadapijs://`)实现 JS 与原生层的双向通信。支持回调机制和可用功能查询。
#### `Text/rich_editor.js`
富文本编辑器核心模块。定义 `RE` 对象,管理编辑器 DOM 引用和编辑操作。
#### `Text/rich_display.js`
富文本展示模块。定义 `RDisplay` 对象,处理展示模式下的交互(书籍卡片触摸反馈、点击高亮等)。
#### `Text/correctArticle.js`
文章内容校正脚本。用于对公众号文章的 HTML 结构进行清洗和修正。
#### `Text/style_html.js`
JS Beautifier 库。HTML/JS/CSS 代码格式化工具(MIT License),用于代码块的美化显示。
---
## CSS 文件
### 默认/基础样式
#### `default.css`
公众号文章的基础阅读样式。覆盖微信原生样式,定义:
- 文章区域布局(`rich_media_area_primary`padding、字号 18px、行高 30px
- 标题样式(`rich_media_title`24px/36px
- 内容区域溢出处理、blockquote 样式
- 隐藏工具栏(`rich_media_tool`
- 划线/想法/高亮样式(`.highlight` 橙色、`.review` 红色虚线、`.friend-review` 灰色虚线)
- 隐藏 iPad 上的 PC 二维码
- TTS 朗读高亮(`.tts` 蓝色背景)
- 公众号图片链接禁用点击
#### `dark.css`
深色模式样式。全局覆盖为纯黑背景(`rgba(0,0,0,1)`),文字颜色设为灰色(`rgba(180,180,182,1)`),链接为蓝色,blockquote 为深色背景。适配搜狗百科和百度搜索的特殊元素。
#### `xcode.min.css`
代码语法高亮配色方案(highlight.js 的 Xcode 主题),白色背景,关键字紫色、字符串红色、注释绿色等。
### 内容替换样式
#### `replace.css`
EPUB 书籍的主要排版样式。定义:
- 代码块字体(Menlo/Consolas)、版权标题、图片说明文字
- 六级标题样式(`.firstTitle` ~ `.sixthTitle`1.0em~1.5em
- 首字下沉(`.ftext`)、引用(`.conQuot`)、副标题(`.subHead`
- 图片垂直居中(`wr-vertical-center-style`)、翻译行高
- 章节工具栏高度(`.book-chapter-tool`78px
#### `replaceForLatinLanguageBook.css`
拉丁语系书籍的排版样式。与 `replace.css` 类似,但标题使用 `Source Han Serif CN` 字体并加粗(而非 `SourceHanSerifCN-Medium` normal),适配西文排版习惯。
#### `replaceForMPChapter.css`
公众号文集(小文章)的排版样式。在 `replace.css` 基础上增加了:
- `.weread-page-relate` 跨页关联标记
- `.chapter-reward` 打赏区域(120px
- `.chapter-tool` 工具栏(140px
- `.re_bookItem` 书籍卡片间距
- `img[data-image-size="large"]` 大图全宽
- `.unsupported_iframe` 不支持控件的提示样式
- 强制清除 `<p>``<strong>``<span>``<section>` 的背景色
### 公众号专用样式
#### `MPExtra.css`
公众号文章的完整样式表(从微信 CSS 复制并修改)。包含:
- 微信 UI 组件样式(`.rich_media_*``.weui-*`
- 小程序卡片样式(`.weapp_*`
- GIF 图片播放提示
- 全局消息提示栏
- 对话框组件(`.weui-dialog`
- 公众号音频播放器样式(`.audio_*`,含 Retina 适配)
- 被删公众号链接隐藏处理
- iPhone 横屏适配
#### `MediaPlatform.css`
公众号文章阅读的精简样式。覆盖微信原生样式中的关键属性:背景色、字号、行高、blockquote、QQ 音乐区域、分享图片等。主要用于非文集场景的公众号阅读。
#### `WREpubMPVideo.css`
腾讯视频播放器的自定义样式。完全重写视频控制器 UI:
- 自定义播放/暂停、全屏按钮图标(使用 CDN sprite 图)
- 进度条、时间显示器布局
- 隐藏广告和下载提示
- 响应式适配(iPhone 6/6P 尺寸)
### Style 子目录
#### `Style/style.css`
笔记/想法的编辑和展示样式(EPUB 基准 1em=16px)。定义:
- 编辑器容器(`.re`)基础样式
- 段落、标题、列表、blockquote 样式
- 书籍卡片组件(`.re_bookItem`,含 Retina 边框)
- 图片样式(`.re_img``.bodyPic`
- QQ 表情样式
- 深色模式(`.re_Night`
#### `Style/preview.css`
想法/笔记的预览样式。与 `style.css` 类似但适用于阅读展示场景,字号 18px,行高 30px,使用 `-apple-system` 字体。
#### `Style/normalize.css`
normalize.css v3.0.2MIT License)。标准化各浏览器的默认样式差异。
-26
View File
@@ -1,26 +0,0 @@
var generator = {};
generator.generateHtml = function (content, js, css) {
var result = content;
result = result.replace("<!--headTrap<body></body><head></head><html></html>-->", "");
result = result.replace("<!--tailTrap<body></body><head></head><html></html>-->", "");
var match = result.match(/window\.__nonce_str = "(\d+)"/);
var nonce = "";
if (match && match.length > 1) {
nonce = "nonce='" + match[1] + "'";
}
var insertJs = "<script " + (nonce.length > 1 ? nonce : "") + " type='text/javascript'>" + js + "</script></body>";
var insertStyle = "<style type='text/css'>" + css + "</style></head>";
result = result.replace("</head>", insertStyle);
result = result.replace("</body>", insertJs);
return result;
}
generator.generateHtmlForMPReview = function (content,js, css) {
var result = generator.generateHtml(content,js,css)
var modifiedCopyRight = " <span id = 'copyright_logo' stype = 'display:none' > ";
var reg = /<span id="copyright_logo".*>?/;
result = result.replace(reg,modifiedCopyRight);
return result;
}
-26
View File
@@ -1,26 +0,0 @@
(function(){
var head = document.getElementsByTagName("head")[0];
var meta = document.createElement('meta');
meta.name = "viewport";
meta.content = "width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no";
head.appendChild(meta);
var children = document.body.children;
var titleFounded = false;
for(var i = 0; i < children.length; i++){
var child = children[i]
var tagName = child.tagName.toLowerCase()
// 隐藏标题前的空段落
if(!child.textContent){
child.style.display = "none";
}else if(titleFounded){
// 如果找到标题了,那么遇到第一个不为空的短路,就不再处理了
break
}
// 隐藏标题
if(tagName === 'h1' || tagName === 'h2' || tagName === 'h3'){
child.style.display = "none"
titleFounded = true
}
}
})()
-125
View File
@@ -1,125 +0,0 @@
var mediaPlatform = {};
mediaPlatform.getMPHeight = function() {
var height = document.getElementById('js_article').scrollHeight;
return height;
};
mediaPlatform.getMPInfo = function() {
var title;
if (msg_title) {
title = msg_title;
}
else {
title = document.getElementsByTagName('h1')[0].innerHTML.toString();
}
var thumbUrl;
if (msg_cdn_url) {
thumbUrl = msg_cdn_url;
}
else {
thumbUrl = document.getElementsByTagName('img')[0].src.toString();
}
var account;
if (nickname) {
account = nickname;
}
if (!title) {title = "";}
if (!thumbUrl) {thumbUrl= "";}
if (!account) {account = "";}
var info = {
"title": title,
"thumbUrl": thumbUrl,
"account": account,
}
return info;
};
mediaPlatform.getMPInfoStr = function() {
return JSON.stringify(mediaPlatform.getMPInfo());
};
// 这里的做法是为了非独立图片(下方有内容)可以保持跟内容12px的距离
mediaPlatform.handleImageBlank = function() {
var imgs = document.getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
var nextNode = imgs[i].nextSibling;
var preNode = imgs[i].previousSibling;
// 只处理上方有空行的情况,下方有空行经常会跟图片的说明文字连用,尝试修改会导致样式错乱
if (preNode && preNode.nodeName.toLowerCase() == 'br') {
// 处理图片上面有个br,但是br不能自定义高度,所以直接去掉重新加margin
if (preNode.style) {
preNode.style.display = "none";
}
imgs[i].style.marginTop = '12px';
} else if (preNode && preNode.nodeType == 3 && !this.emptyTextNode(preNode)) {
// 处理图片跟上面文字在同一个p里面,但是没有br隔开
imgs[i].style.marginTop = '12px';
}
}
};
mediaPlatform.emptyTextNode = function(el) {
return !el.data || /^(\s|\t)+$/g.test(el.data)
}
// 干掉p>br的情况的margin-top
mediaPlatform.updateBlankHeight = function() {
var blanks = document.getElementsByTagName('br');
for (var i = blanks.length - 1; i >= 0; i--) {
var parentNode = blanks[i].parentNode;
if (parentNode.nodeName.toLowerCase() == "p" && parentNode.childNodes.length == 1) {
parentNode.style.height = '20px';
parentNode.style.minHeight = '0em';
}
}
};
// 观察到部分公众号文章首评的懒加载图片无法正常显示,这是由于 scroll 事件没有触发导致的(怀疑是在 rangy-classapplier 引入后产生了混合反应,但在 Android 上确是好的)。这里的解决办法是手动触发一次 scroll 事件,但由于我们的 webview 其实是完整高度的,本身并不能滚动,所以这样做也不会产生抖动或者其他副作用。
mediaPlatform.protectLazyLoad = function() {
window.scrollTo(0, 1);
};
mediaPlatform.init = function() {
mediaPlatform.updateBlankHeight();
mediaPlatform.handleImageBlank();
mediaPlatform.protectLazyLoad();
};
mediaPlatform.getAuthor = function() {
var find = false;
var author = document.getElementById('js_name');
if (author != null) {
console.log('mediaPlatform.getAuthor ' + author.innerText)
author.addEventListener('click',function(){
wereadBridge.handleWithRichEditor("onClickAuthor",{"param" : author.innerText, "cmd": "onClickAuthor"}, "", "");
}, false)
}
}
mediaPlatform.init();
// 用于在退出公众号文章的时候暂停视频播放
// 由于腾讯视频是通过 iFrame 内嵌的,没有办法直接操作,我们用刷新 iFrame 的方式实现停止播放的效果
function pauseMedia() {
pauseCurrentAudio();
pauseCurrentVideo();
}
function pauseCurrentAudio() {
var audios = document.querySelectorAll('audio');
for (var i = 0; i < audios.length; i++) {
var audio = audios[i];
audio.pause();
}
}
function pauseCurrentVideo() {
var iframes = document.querySelectorAll('iframe');
for (var i = 0; i < iframes.length; i++) {
var oldFrame = iframes[i];
oldFrame.src = oldFrame.src;
}
}
-349
View File
@@ -1,349 +0,0 @@
var WRAUDIO_TEMPLATE = '<div id="wraudioid_xxx" class="audio_container">\
<div id="wraudio_button" class="audio_button"></div>\
<div class="audio_content">\
<p id="wraudio_title" class="audio_title"></p>\
<div class="audio_progress">\
<div class="audio_progress_bottom"></div>\
<div id="wraudio_progress_bar" class="audio_progress_top" style="width: 0;"></div>\
<div id="wraudio_progress_button" class="audio_progress_current" style="left: 0;"></div>\
</div>\
<div class="audio_time">\
<span id="wraudio_time_elapsed" class="audio_time_left"></span>\
<span id="wraudio_time_remains" class="audio_time_right"></span>\
</div>\
</div>\
</div>';
var _Utils = function () {
this.findChildById = function (element, childID) {
var retElement = null;
var lstChildren = Utils.getAllDescendant(element);
for (var i = 0; i < lstChildren.length; i++) {
if (lstChildren[i].id == childID) {
retElement = lstChildren[i];
break;
}
}
return retElement;
}
this.getAllDescendant = function (element, lstChildrenNodes) {
lstChildrenNodes = lstChildrenNodes ? lstChildrenNodes : [];
var lstChildren = element.childNodes;
for (var i = 0; i < lstChildren.length; i++) {
if (lstChildren[i].nodeType == 1) // 1 is 'ELEMENT_NODE'
{
lstChildrenNodes.push(lstChildren[i]);
lstChildrenNodes = Utils.getAllDescendant(lstChildren[i], lstChildrenNodes);
}
}
return lstChildrenNodes;
}
this._formatTime = function (time, quotationStyle) {
if (time < 0) {
return '- : -'
}
var hour = parseInt(time / 3600);
var min = parseInt((time - hour * 3600) / 60);
var sec = parseInt((time - hour * 3600 - min * 60));
var timeText = '';
if (hour > 0) {
timeText += hour + ':';
}
if (quotationStyle) {
if (min > 0) {
timeText += min + "'";
}
} else {
if (min < 10) {
timeText += '0' + min + ':';
} else {
timeText += min + ':';
}
}
if (quotationStyle) {
timeText += sec + "''";
} else {
if (sec < 10) {
timeText += '0' + sec;
} else {
timeText += sec;
}
}
return timeText;
}
this.formatTime = function (time, remains) {
var intTime = parseInt(time);
var desc = this._formatTime(intTime);
if (remains && intTime > 0) {
return '-' + desc;
}
return desc;
}
}
var Utils = new _Utils;
var player = {audio: null, current: null};
var videoIframes = [];
function getContentRoot() {
return document.getElementById('editor');
}
function createWRAudio(title, src, duration) {
var tmp = document.createElement('div');
tmp.innerHTML = WRAUDIO_TEMPLATE;
var wrAudio = tmp.firstChild;
wrAudio.id = 'wraudioid_' + Date.now() + '_' + Math.floor((Math.random() * 1000) + 1);
wrAudio.src = src;
wrAudio.duration = duration;
var titleEl = Utils.findChildById(wrAudio, 'wraudio_title', true);
titleEl.innerHTML = title || '';
var button = Utils.findChildById(wrAudio, 'wraudio_button', true);
button.addEventListener('click', function() {
clickPlayButton(wrAudio);
}, false);
var elapsedEl = Utils.findChildById(wrAudio, 'wraudio_time_elapsed', true);
var remainsEl = Utils.findChildById(wrAudio, 'wraudio_time_remains', true);
elapsedEl.innerHTML = Utils.formatTime(0);
remainsEl.innerHTML = Utils.formatTime(duration, true);
return wrAudio;
}
function resetWRAudio(wrAudio) {
if (!wrAudio) {
return;
}
var button = Utils.findChildById(wrAudio, 'wraudio_button', true);
button.classList.remove('active');
var elapsedEl = Utils.findChildById(wrAudio, 'wraudio_time_elapsed', true);
var remainsEl = Utils.findChildById(wrAudio, 'wraudio_time_remains', true);
elapsedEl.innerHTML = Utils.formatTime(0);
remainsEl.innerHTML = Utils.formatTime(wrAudio.duration, true);
var progressBar = Utils.findChildById(wrAudio, 'wraudio_progress_bar', true);
var progressButton = Utils.findChildById(wrAudio, 'wraudio_progress_button', true);
progressBar.style.width = '0';
progressButton.style.left = '0';
}
function clickPlayButton(wrAudio) {
if (!wrAudio) {
return;
}
var src = wrAudio.src;
if (!player.current) {
player.current = wrAudio;
player.audio.src = src;
player.audio.play();
} else if (player.current.id != wrAudio.id) {
var last = player.current;
player.current = wrAudio;
resetWRAudio(last);
player.audio.src = src;
player.audio.play();
} else {
if (!player.audio.paused) {
player.audio.pause();
} else {
player.audio.play();
}
}
}
function pauseCurrentAudio() {
if (player.audio) {
player.audio.pause();
}
}
function pauseCurrentVideo() {
let newVideoIframes = [];
for (var i = 0; i < videoIframes.length; i++) {
var oldFrame = videoIframes[i];
oldFrame.src = oldFrame.src;
}
}
function pauseMedia() {
pauseCurrentAudio();
pauseCurrentVideo();
}
function onPlay() {
var button = Utils.findChildById(player.current, 'wraudio_button', true);
button.classList.add('active');
}
function onPause() {
var button = Utils.findChildById(player.current, 'wraudio_button', true);
button.classList.remove('active');
}
function onEnded() {
var button = Utils.findChildById(player.current, 'wraudio_button', true);
button.classList.remove('active');
}
function onDurationchange() {
player.current.duration = player.audio.duration;
}
function onVideoPlaying() {
pauseCurrentAudio();
}
function onTimeupdate() {
var wrAudio = player.current;
var elapsedEl = Utils.findChildById(wrAudio, 'wraudio_time_elapsed', true);
var remainsEl = Utils.findChildById(wrAudio, 'wraudio_time_remains', true);
elapsedEl.innerHTML = Utils.formatTime(player.audio.currentTime);
remainsEl.innerHTML = Utils.formatTime(player.audio.duration - player.audio.currentTime, true);
var progressBar = Utils.findChildById(wrAudio, 'wraudio_progress_bar', true);
var progressButton = Utils.findChildById(wrAudio, 'wraudio_progress_button', true);
var progress = 0;
if (player.audio.duration > 0) {
progress = parseInt(player.audio.currentTime / player.audio.duration * 100);
}
progressBar.style.width = progress + '%';
progressButton.style.left = progress + '%';
}
function adjustMPContent() {
var imgs = document.querySelectorAll('img[data-src]');
for (var i = 0; i < imgs.length ; i++) {
var img = imgs[i];
img.src = img.getAttribute('data-src');
img.style = 'width: auto !important; height: auto !important; visibility: visible !important;max-width:100% !important';
}
var links = document.querySelectorAll('a[href^="https://open.weixin.qq.com/connect/oauth2/authorize"],a[href^="http://open.weixin.qq.com/connect/oauth2/authorize"]');
for (var i = 0; i < links.length ; i++) {
var link = links[i]
params = link.href.split('&');
for (var j = 0;j<params.length;j++) {
param = params[j];
if (param.startsWith('redirect_uri=')) {
link.href = decodeURIComponent(param.split('redirect_uri=')[1]);
}
}
}
var iframes = document.querySelectorAll('iframe[data-src]');
for (var i = 0; i < iframes.length ; i++) {
(function (index) {
var iframe = iframes[index];
var iframeWidth = document.body.offsetWidth;
var iframeHeight = iframeWidth * 0.75;
var src = iframe.getAttribute('data-src');
src = src.replace(/preview.html/, 'player.html');
src = src.replace(/&(width=.*height=.*)&/, '&width=' + iframeWidth + '&height=' + iframeHeight + '&');
iframe.src = src;
// 是否视频
/*
if ((' ' + iframe.className + ' ').indexOf(' video_iframe ') > -1) {
iframe.onload = function () {
var styleNode = document.createElement('style');
styleNode.type = 'text/css';
styleNode.appendChild(document.createTextNode(''));
iframe.contentDocument.body.appendChild(styleNode);
}
}
*/
// if (iframe.classList.contains("video_iframe")) {
// iframe.onload = function() {
// if (iframe.contentWindow && iframe.contentWindow.document) {
// var videoEl = iframe.contentWindow.document.getElementById("tenvideo_video_player_0");
// if (videoEl) {
// videoEl.onplaying = function() {
// onVideoPlaying();
// };
// }
// }
// };
// }
videoIframes.push(iframe);
})(i);
}
var votes = document.querySelectorAll(".vote_area");
for (var i = 0; i < votes.length; i++) {
var vote = votes[i];
vote.parentElement.removeChild(vote);
}
var miniPrograms = document.querySelectorAll("mp-miniprogram");
for (var i = 0; i < miniPrograms.length; i++) {
var miniProgram = miniPrograms[i];
var parentElement = miniProgram.parentElement;
if (parentElement && parentElement.tagName && parentElement.tagName.toLowerCase() === 'p') {
if (parentElement.parentElement) {
parentElement.parentElement.removeChild(parentElement);
}
}
}
var miniAppLinks = document.querySelectorAll(".weapp_text_link, .weapp_image_link");
for (var i = 0; i < miniAppLinks.length; i++) {
var miniAppLink = miniAppLinks[i];
miniAppLink.parentElement.removeChild(miniAppLink);
}
var needPlayer = false;
var mpvoices = document.querySelectorAll('mpvoice[voice_encode_fileid]');
for (var i = 0; i < mpvoices.length ; i++) {
var mpvoice = mpvoices[i];
var title = mpvoice.getAttribute('name');
var src = 'https://res.wx.qq.com/voice/getvoice?mediaid=' + mpvoice.getAttribute('voice_encode_fileid');
var duration = mpvoice.hasAttribute('play_length') ? mpvoice.getAttribute('play_length') / 1000 : -1;
var wrAudio = createWRAudio(title, src, duration);
mpvoice.parentElement.appendChild(wrAudio);
needPlayer = true;
}
var qqmusics = document.querySelectorAll('qqmusic[audiourl]');
for (var i = 0; i < qqmusics.length ; i++) {
var qqmusic = qqmusics[i];
var title = qqmusic.getAttribute('music_name');
var src = qqmusic.getAttribute('audiourl');
var duration = qqmusic.hasAttribute('play_length') ? qqmusic.getAttribute('play_length') / 1000 : -1;
var wrAudio = createWRAudio(title, src, duration);
qqmusic.parentElement.appendChild(wrAudio);
needPlayer = true;
}
if (needPlayer) {
var audio = document.createElement('audio');
audio.autoplay = false;
audio.controls = true;
audio.style.display = "none";
audio.addEventListener("play", onPlay, false);
audio.addEventListener("pause", onPause, false);
audio.addEventListener("ended", onEnded, false);
audio.addEventListener("durationchange", onDurationchange, false);
audio.addEventListener("timeupdate", onTimeupdate, false);
getContentRoot().appendChild(audio);
player.audio = audio;
}
}
document.addEventListener('DOMContentLoaded', function() {
adjustMPContent();
}, false);
-74
View File
@@ -1,74 +0,0 @@
(function() {
if (window.wrClickHandler) {
window.removeEventListener('click', window.wrClickHandler, true);
}
window.wrClickHandler = function(e) {
console.log('Hook: Click event intercepted', {
target: e.target,
tagName: e.target.tagName,
id: e.target.id,
className: e.target.className
});
var eventInfo = null;
var currentElement = e.target;
while (currentElement && currentElement !== document) {
var tagName = currentElement.tagName || '';
var currentId = currentElement.id || '';
if (currentId === 'js_name') {
// 公众号顶部的作者
eventInfo = {
contentType: 'profile',
bizId: ''
};
console.log('Hook: MP author click intercepted');
break;
} else if (currentId === 'copyright_info') {
// 公众号顶部的文章来源
var bizId = typeof source_encode_biz !== 'undefined' ? source_encode_biz : '';
if (bizId) {
eventInfo = {
contentType: 'profile',
bizId: bizId
};
console.log('Hook: Copyright profile click intercepted, bizId:', bizId);
}
break;
} else if (tagName === 'MP-COMMON-PROFILE') {
// 公众号
var bizId = currentElement.dataset && currentElement.dataset['id'] ? currentElement.dataset['id'] : '';
if (bizId) {
eventInfo = {
contentType: 'profile',
bizId: bizId
};
console.log('Hook: Profile click intercepted, bizId:', bizId);
}
break;
} else if (currentElement.href && currentElement.href.indexOf('mp.weixin.qq.com') !== -1) {
// 公众号文章链接
eventInfo = {
contentType: 'link',
url: currentElement.href
};
console.log('Hook: Link click intercepted, URL:', currentElement.href);
break;
}
currentElement = currentElement.parentElement;
}
// 如果有 eventInfo,则阻断事件冒泡,拦截公众号原始的跳转弹窗
if (eventInfo) {
e.preventDefault();
e.stopPropagation();
}
if (eventInfo && wereadBridge) {
wereadBridge.execMPReaderMethod('MPReader', {
cmd: 'clickMpInterceptor',
data: eventInfo
});
}
};
window.addEventListener('click', window.wrClickHandler, true);
console.log('Hook: Click interceptor setup completed');
})();
@@ -1,16 +0,0 @@
window.newsInjector = {
removeUnnecessary: function() {
document.getElementsByTagName('body')[0].style = 'background-color:red'
var divs = document.getElementsByTagName('div')
for (var i = divs.length - 1; i >= 0; i--) {
var node = divs[i]
if (node.textContent == '查看全文' &&
node.nextSibling &&
node.nextSibling.nodeName == 'IMG') {
node.style = 'display: none!important;'
node.nextSibling.style = 'display: none!important';
}
}
}
}
@@ -1,13 +1,13 @@
# 微信读书 EPUB 阅读器实现架构分析
# 读书 EPUB 阅读器实现架构分析
> 分析日期: 2026-05-18
> 基于逆向工程: 微信读书 v10.0.3 (Build 79)
> 基于读书 v10.0.3
---
## 核心结论:双渲染引擎架构
微信读书使用了 **两套渲染引擎**,根据内容类型选择不同的渲染路径:
读书使用了 **两套渲染引擎**,根据内容类型选择不同的渲染路径:
```
┌─────────────────────────────────────────────────┐
@@ -319,7 +319,7 @@ WeRead/Src/Modules/MediaPlatform/
```
加载优先级 (从低到高):
1. default.css - 基础 HTML 标签样式 (Safari 默认)
2. replace.css - 微信读书默认替换样式
2. replace.css - 读书默认替换样式
├── 标题样式 (h1-h6, 使用 Source Han Serif CN 字体)
├── 代码块 (pre, 使用 Menlo 字体)
├── 图片 (.bodyPic, wr-vertical-center-style: 2)
@@ -332,7 +332,7 @@ WeRead/Src/Modules/MediaPlatform/
5. 用户设置 - 字号、行高、主题覆盖
```
**自定义 CSS 属性** (微信读书私有):
**自定义 CSS 属性** (读书私有):
- `wr-vertical-center-style: 1|2` - 图片垂直居中方式
- `weread-page-relate: true` - 控制分页时的内容关联
@@ -380,7 +380,7 @@ WeRead/Src/Modules/MediaPlatform/
| `mpForArticle.js` | 文章相关 JS 逻辑 |
| `MPExtra.css` | 公众号额外样式 |
| `MediaPlatform.css` | 公众号基础样式 |
| `WeReadApi.js` | 微信读书 JS API (供 WebView 调用原生功能) |
| `WeReadApi.js` | 读书 JS API (供 WebView 调用原生功能) |
| `rich_display.js` | 富文本显示逻辑 |
| `cssInjector.js` | CSS 注入器 |
| `highlight.min.js` | 代码语法高亮 (highlight.js) |
@@ -436,7 +436,7 @@ WeRead/Src/Modules/MediaPlatform/
├── FZJuZhenXinFang.ttf # 方正聚珍新仿
├── Lora-Regular.ttf / Italic.ttf # Lora 衬线体
├── PlayfairDisplay-Regular.ttf # Playfair Display
├── WeReadLS-Regular/Medium/Bold # 微信读书 LS 系列
├── WeReadLS-Regular/Medium/Bold # 读书 LS 系列
├── WeReadRN-Regular.ttf # RN 专用字体
├── WeRead-Icon.ttf # 图标字体
├── WeRead-Rating-Icon.ttf # 评分图标