- 实现EPUB阅读器搜索功能及选中注释功能 - 优化CFI模块,修复代码审查发现的11个问题 - 实现大书远距目录跳转与后台补全优化方案 - 优化设置面板与章节运行时联动 - 重构及大量改进优化
484 lines
16 KiB
Markdown
484 lines
16 KiB
Markdown
# 公开 API 参考手册
|
||
|
||
> 最后更新:2026-06-18
|
||
|
||
本文档列出 ReadViewSDK 所有公开 API 的完整签名、参数说明和使用方法。
|
||
|
||
---
|
||
|
||
## 1. RDEPUBReaderController — 入口控制器
|
||
|
||
**文件**:`Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift` 及扩展
|
||
|
||
### 1.1 初始化
|
||
|
||
```swift
|
||
// EPUB 文件初始化
|
||
init(
|
||
epubURL: URL, // EPUB 文件路径
|
||
configuration: RDEPUBReaderConfiguration = .default, // 阅读配置
|
||
persistence: RDEPUBReaderPersistence? = nil, // 持久化实现
|
||
dependencies: RDEPUBReaderDependencies? = nil // 依赖注入
|
||
)
|
||
|
||
// 预构建 TextBook 初始化(如 .txt 文件)
|
||
init(
|
||
textBook: RDEPUBTextBook, // 预构建的文本书籍
|
||
bookIdentifier: String, // 书籍唯一标识
|
||
title: String, // 书籍标题
|
||
textFileURL: URL? = nil, // 原始文件路径
|
||
configuration: RDEPUBReaderConfiguration = .default,
|
||
persistence: RDEPUBReaderPersistence? = nil,
|
||
dependencies: RDEPUBReaderDependencies? = nil
|
||
)
|
||
```
|
||
|
||
### 1.2 公开属性
|
||
|
||
| 属性 | 类型 | 读写 | 说明 |
|
||
|------|------|------|------|
|
||
| `delegate` | `RDEPUBReaderDelegate?` | 读写 | 委托代理 |
|
||
| `configuration` | `RDEPUBReaderConfiguration` | 读写 | 阅读配置,设置后触发重新分页 |
|
||
| `currentLocation` | `RDEPUBLocation?` | 只读 | 当前阅读位置 |
|
||
| `currentPageNumber` | `Int?` | 只读 | 当前页码(1-based) |
|
||
| `currentSelection` | `RDEPUBSelection?` | 只读 | 当前文本选区 |
|
||
| `highlights` | `[RDEPUBHighlight]` | 只读 | 所有高亮标注 |
|
||
| `bookmarks` | `[RDEPUBBookmark]` | 只读 | 所有书签 |
|
||
| `annotations` | `[RDEPUBAnnotation]` | 只读 | 合并排序后的统一标注列表 |
|
||
| `tableOfContents` | `[EPUBTableOfContentsItem]` | 只读 | 目录树(嵌套结构) |
|
||
| `flattenedTableOfContents` | `[RDEPUBReaderTableOfContentsItem]` | 只读 | 扁平化目录列表 |
|
||
| `currentTableOfContentsItem` | `RDEPUBReaderTableOfContentsItem?` | 只读 | 当前所在目录项 |
|
||
|
||
### 1.3 导航方法
|
||
|
||
```swift
|
||
/// 重新加载书籍
|
||
func reloadBook()
|
||
|
||
/// 跳转到指定位置
|
||
func go(to location: RDEPUBLocation)
|
||
|
||
/// 跳转到指定页码(1-based)
|
||
/// - Returns: 是否跳转成功
|
||
@discardableResult
|
||
func go(toPageNumber pageNumber: Int, animated: Bool = false) -> Bool
|
||
|
||
/// 跳转到目录项(EPUBTableOfContentsItem)
|
||
@discardableResult
|
||
func go(toTableOfContentsItem item: EPUBTableOfContentsItem, animated: Bool = true) -> Bool
|
||
|
||
/// 跳转到目录项(RDEPUBReaderTableOfContentsItem)
|
||
@discardableResult
|
||
func go(toTableOfContentsItem item: RDEPUBReaderTableOfContentsItem, animated: Bool = true) -> Bool
|
||
|
||
/// 跳转到目录 href(支持 fragment,如 "chapter1.xhtml#section2")
|
||
@discardableResult
|
||
func go(toTableOfContentsHref href: String, animated: Bool = true) -> Bool
|
||
|
||
/// 跳转到指定高亮位置
|
||
@discardableResult
|
||
func go(toHighlightID id: String, animated: Bool = true) -> Bool
|
||
|
||
/// 跳转到指定书签位置
|
||
@discardableResult
|
||
func go(toBookmarkID id: String, animated: Bool = true) -> Bool
|
||
```
|
||
|
||
### 1.4 高亮方法
|
||
|
||
```swift
|
||
/// 添加高亮(使用当前选区或指定选区)
|
||
/// - Parameters:
|
||
/// - selection: 选区信息,nil 时使用 currentSelection
|
||
/// - color: 高亮颜色(十六进制),默认 "#F8E16C"
|
||
/// - note: 可选备注
|
||
/// - Returns: 创建的高亮对象,失败返回 nil
|
||
@discardableResult
|
||
func addHighlight(
|
||
from selection: RDEPUBSelection? = nil,
|
||
color: String = "#F8E16C",
|
||
note: String? = nil
|
||
) -> RDEPUBHighlight?
|
||
|
||
/// 添加标注(支持高亮和下划线样式)
|
||
@discardableResult
|
||
func addAnnotation(
|
||
from selection: RDEPUBSelection? = nil,
|
||
style: RDEPUBHighlightStyle,
|
||
color: String = "#F8E16C",
|
||
note: String? = nil
|
||
) -> RDEPUBHighlight?
|
||
|
||
/// 更新或插入高亮
|
||
@discardableResult
|
||
func upsertHighlight(_ highlight: RDEPUBHighlight) -> RDEPUBHighlight?
|
||
|
||
/// 删除高亮
|
||
@discardableResult
|
||
func removeHighlight(id: String) -> RDEPUBHighlight?
|
||
|
||
/// 更新高亮备注
|
||
@discardableResult
|
||
func updateHighlightNote(id: String, note: String?) -> RDEPUBHighlight?
|
||
|
||
/// 删除所有高亮
|
||
func removeAllHighlights()
|
||
|
||
/// 根据 ID 查找高亮
|
||
func highlight(withID id: String) -> RDEPUBHighlight?
|
||
```
|
||
|
||
### 1.5 书签方法
|
||
|
||
```swift
|
||
/// 添加书签(使用当前位置)
|
||
@discardableResult
|
||
func addBookmark(note: String? = nil) -> RDEPUBBookmark?
|
||
|
||
/// 切换书签状态(已存在则删除,不存在则添加)
|
||
@discardableResult
|
||
func toggleBookmark(note: String? = nil) -> RDEPUBBookmark?
|
||
|
||
/// 删除书签
|
||
@discardableResult
|
||
func removeBookmark(id: String) -> RDEPUBBookmark?
|
||
|
||
/// 根据 ID 查找书签
|
||
func bookmark(withID id: String) -> RDEPUBBookmark?
|
||
```
|
||
|
||
### 1.6 搜索方法
|
||
|
||
```swift
|
||
/// 开始搜索
|
||
func search(keyword: String)
|
||
|
||
/// 跳转到下一个匹配
|
||
/// - Returns: 是否有下一个匹配
|
||
@discardableResult
|
||
func searchNext() -> Bool
|
||
|
||
/// 跳转到上一个匹配
|
||
@discardableResult
|
||
func searchPrevious() -> Bool
|
||
|
||
/// 清除搜索
|
||
func clearSearch()
|
||
```
|
||
|
||
### 1.7 其他方法
|
||
|
||
```swift
|
||
/// 清除当前文本选区
|
||
func clearSelection()
|
||
|
||
/// 获取当前页面的语义摘要(调试用)
|
||
func nativeTextSemanticSummary() -> String?
|
||
```
|
||
|
||
---
|
||
|
||
## 2. RDEPUBReaderDelegate — 委托协议
|
||
|
||
**文件**:`Sources/RDReaderView/EPUBUI/RDEPUBReaderDelegate.swift`
|
||
|
||
所有方法均有默认空实现,可按需实现。
|
||
|
||
```swift
|
||
public protocol RDEPUBReaderDelegate: AnyObject {
|
||
|
||
/// 书籍打开完成
|
||
func epubReader(_ reader: UIViewController, didOpen publication: RDEPUBPublication)
|
||
|
||
/// 阅读位置变化
|
||
func epubReader(_ reader: UIViewController, didUpdateLocation location: RDEPUBLocation)
|
||
|
||
/// 到达书籍末尾
|
||
func epubReaderDidReachEnd(_ reader: UIViewController)
|
||
|
||
/// 文本选区变化(nil 表示取消选中)
|
||
func epubReader(_ reader: UIViewController, didChangeSelection selection: RDEPUBSelection?)
|
||
|
||
/// 高亮列表变化
|
||
func epubReader(_ reader: UIViewController, didUpdateHighlights highlights: [RDEPUBHighlight])
|
||
|
||
/// 书签列表变化
|
||
func epubReader(_ reader: UIViewController, didUpdateBookmarks bookmarks: [RDEPUBBookmark])
|
||
|
||
/// 搜索结果更新
|
||
func epubReader(_ reader: UIViewController, didUpdateSearchResult result: RDEPUBSearchResult?)
|
||
|
||
/// 当前搜索匹配项变化
|
||
func epubReader(_ reader: UIViewController, didChangeCurrentSearchMatch match: RDEPUBSearchMatch?)
|
||
|
||
/// 当前目录项变化
|
||
func epubReader(_ reader: UIViewController, didUpdateCurrentTableOfContentsItem item: RDEPUBReaderTableOfContentsItem?)
|
||
|
||
/// 外部链接被点击
|
||
func epubReader(_ reader: UIViewController, didActivateExternalLink url: URL)
|
||
|
||
/// 是否允许打开外部链接(返回 false 拦截)
|
||
func epubReader(_ reader: UIViewController, shouldOpenExternalURL url: URL) -> Bool
|
||
|
||
/// 错误回调
|
||
func epubReader(_ reader: UIViewController, didFailWithError error: Error)
|
||
|
||
/// 配置顶部工具栏(自定义按钮等)
|
||
func epubReader(_ reader: UIViewController, configureTopToolView topToolView: RDEPUBReaderTopToolView)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. RDEPUBReaderPersistence — 持久化协议
|
||
|
||
**文件**:`Sources/RDReaderView/EPUBUI/RDEPUBReaderPersistence.swift`
|
||
|
||
```swift
|
||
public protocol RDEPUBReaderPersistence: AnyObject {
|
||
|
||
func loadLocation(for bookIdentifier: String) -> RDEPUBLocation?
|
||
func saveLocation(_ location: RDEPUBLocation, for bookIdentifier: String)
|
||
|
||
func loadBookmarks(for bookIdentifier: String) -> [RDEPUBBookmark]
|
||
func saveBookmarks(_ bookmarks: [RDEPUBBookmark], for bookIdentifier: String)
|
||
|
||
func loadHighlights(for bookIdentifier: String) -> [RDEPUBHighlight]
|
||
func saveHighlights(_ highlights: [RDEPUBHighlight], for bookIdentifier: String)
|
||
|
||
func loadReaderSettings() -> RDEPUBReaderSettings?
|
||
func saveReaderSettings(_ settings: RDEPUBReaderSettings)
|
||
}
|
||
```
|
||
|
||
默认实现 `RDEPUBUserDefaultsPersistence` 使用 UserDefaults 存储:
|
||
|
||
| 数据 | Key 格式 |
|
||
|------|----------|
|
||
| 阅读位置 | `ssreader.epub.location.{bookID}` |
|
||
| 书签 | `ssreader.epub.bookmarks.{bookID}` |
|
||
| 高亮 | `ssreader.epub.highlights.{bookID}` |
|
||
| 全局设置 | `ssreader.epub.settings` |
|
||
|
||
---
|
||
|
||
## 4. RDEPUBReaderConfiguration — 配置模型
|
||
|
||
**文件**:`Sources/RDReaderView/EPUBUI/Settings/RDEPUBReaderConfiguration.swift`
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `fontSize` | `CGFloat` | `15` | 字体大小(pt) |
|
||
| `lineHeightMultiple` | `CGFloat` | `1.6` | 行距倍数 |
|
||
| `fontChoice` | `RDEPUBReaderFontChoice` | `.system` | 字体选择(system/serif/rounded/monospaced) |
|
||
| `numberOfColumns` | `Int` | `1` | 每页列数(1 或 2) |
|
||
| `columnGap` | `CGFloat` | `20` | 列间距 |
|
||
| `displayType` | `RDReaderView.DisplayType` | `.pageCurl` | 翻页模式 |
|
||
| `landscapeDualPageEnabled` | `Bool` | `true` | 横屏双页 |
|
||
| `showsTableOfContents` | `Bool` | `true` | 显示目录 |
|
||
| `allowsHighlights` | `Bool` | `true` | 允许高亮 |
|
||
| `showsSettingsPanel` | `Bool` | `true` | 显示设置面板 |
|
||
| `reflowableContentInsets` | `UIEdgeInsets` | `(40,16,40,16)` | 重排内容内边距 |
|
||
| `fixedContentInset` | `UIEdgeInsets` | `.zero` | 固定布局内边距 |
|
||
| `theme` | `RDEPUBReaderTheme` | `.light` | 阅读主题 |
|
||
| `darkImageAdjustmentEnabled` | `Bool` | `true` | 暗色模式图片调整 |
|
||
| `darkImageBlendRatio` | `CGFloat` | `0.15` | 暗色图片混合比例(0-0.35) |
|
||
| `fixedLayoutFit` | `RDEPUBFixedLayoutFit` | `.page` | 固定布局适配方式 |
|
||
| `fixedLayoutSpreadMode` | `RDEPUBFixedLayoutSpreadMode` | `.automatic` | 固定布局跨页模式 |
|
||
| `textRenderingEngine` | `RDEPUBTextRenderingEngine` | `.dtCoreText` | 文本渲染引擎 |
|
||
| `onDemandChapterWindowSize` | `Int` | `3` | 按需加载窗口大小(奇数,3-15) |
|
||
| `metadataParsingConcurrency` | `Int` | CPU 核心数 | 后台解析并发数 |
|
||
| `jumpSessionPolicy` | `RDEPUBJumpSessionPolicy` | `.default` | 远距跳转策略 |
|
||
| `allowedExternalURLSchemes` | `Set<String>` | `["https"]` | 允许的外部 URL 协议 |
|
||
| `requiresExternalLinkConfirmation` | `Bool` | `true` | 外部链接需确认 |
|
||
| `allowsInspectableWebViews` | `Bool` | `false` | WebView 可调试 |
|
||
| `enablesVerboseWebViewLogging` | `Bool` | `false` | WebView 详细日志 |
|
||
|
||
**计算属性**:
|
||
- `chapterWindowRadius: Int` — 内存缓存窗口半径(`onDemandChapterWindowSize / 2`)
|
||
|
||
---
|
||
|
||
## 5. 翻页容器协议
|
||
|
||
**文件**:`Sources/RDReaderView/ReaderView/RDReaderViewProtocols.swift`
|
||
|
||
### 5.1 RDReaderPageProvider(推荐)
|
||
|
||
```swift
|
||
@objc public protocol RDReaderPageProvider: NSObjectProtocol {
|
||
|
||
/// 总页数
|
||
func numberOfPages(in readerView: RDReaderView) -> Int
|
||
|
||
/// 返回指定页的视图
|
||
/// - Parameters:
|
||
/// - index: 页码索引(0-based)
|
||
/// - reusableView: 可复用的旧视图(可能为 nil)
|
||
func readerView(_ readerView: RDReaderView, viewForPageAt index: Int, reusableView: UIView?) -> UIView
|
||
|
||
/// 页面标识符(用于缓存去重)
|
||
@objc optional func pageIdentifier(in readerView: RDReaderView, index: Int) -> String?
|
||
|
||
/// 顶部工具栏视图
|
||
@objc optional func readerViewTopChrome(_ readerView: RDReaderView) -> UIView?
|
||
|
||
/// 底部工具栏视图
|
||
@objc optional func readerViewBottomChrome(_ readerView: RDReaderView) -> UIView?
|
||
}
|
||
```
|
||
|
||
### 5.2 RDReaderDelegate
|
||
|
||
```swift
|
||
@objc public protocol RDReaderDelegate: NSObjectProtocol {
|
||
|
||
/// 页面变化回调
|
||
func pageNum(readerView: RDReaderView, pageNum: Int)
|
||
|
||
/// 屏幕方向即将变化
|
||
@objc optional func readerViewOrientationWillChange(readerView: RDReaderView, isLandscape: Bool)
|
||
}
|
||
```
|
||
|
||
### 5.3 RDReaderPageNavigating
|
||
|
||
```swift
|
||
public protocol RDReaderPageNavigating: AnyObject {
|
||
|
||
/// 当前页码
|
||
var currentPage: Int { get }
|
||
|
||
/// 重新加载所有页面
|
||
func reloadPages()
|
||
|
||
/// 跳转到指定页
|
||
func transition(to page: Int, animated: Bool)
|
||
}
|
||
```
|
||
|
||
### 5.4 RDReaderDataSource(遗留)
|
||
|
||
```swift
|
||
@objc public protocol RDReaderDataSource: NSObjectProtocol {
|
||
func pageCountOfReaderView(readerView: RDReaderView) -> Int
|
||
func pageContentView(readerView: RDReaderView, pageNum: Int, containerView: UIView?) -> UIView
|
||
func pageIdentifier(readerView: RDReaderView, pageNum: Int) -> String?
|
||
@objc optional func topToolView(readerView: RDReaderView) -> UIView?
|
||
@objc optional func bottomToolView(readerView: RDReaderView) -> UIView?
|
||
}
|
||
```
|
||
|
||
通过 `RDReaderLegacyDataSourceAdapter` 自动适配到 `RDReaderPageProvider`。
|
||
|
||
---
|
||
|
||
## 6. 数据模型速查
|
||
|
||
### 6.1 RDEPUBLocation
|
||
|
||
```swift
|
||
public struct RDEPUBLocation: Codable, Equatable {
|
||
public var bookIdentifier: String? // 书籍标识
|
||
public var href: String // 章节文件路径
|
||
public var progression: Double // 章节内进度(0.0-1.0)
|
||
public var lastProgression: Double? // 上次进度(用于恢复方向)
|
||
public var fragment: String? // 片段 ID(如 #section1)
|
||
public var rangeAnchor: RDEPUBTextRangeAnchor? // 文本范围锚点
|
||
}
|
||
```
|
||
|
||
### 6.2 RDEPUBBookmark
|
||
|
||
```swift
|
||
public struct RDEPUBBookmark: Codable, Equatable, Identifiable {
|
||
public let id: String // 唯一标识
|
||
public let bookIdentifier: String?
|
||
public let location: RDEPUBLocation
|
||
public let chapterTitle: String?
|
||
public let note: String?
|
||
public let createdAt: Date
|
||
}
|
||
```
|
||
|
||
### 6.3 RDEPUBHighlight
|
||
|
||
```swift
|
||
public struct RDEPUBHighlight: Codable, Equatable, Identifiable {
|
||
public let id: String
|
||
public let bookIdentifier: String?
|
||
public let location: RDEPUBLocation
|
||
public let text: String // 高亮文本内容
|
||
public let style: RDEPUBHighlightStyle // .highlight / .underline
|
||
public let color: String // 十六进制颜色
|
||
public let note: String?
|
||
public let rangeInfo: String? // CoreText 选区范围信息
|
||
public let createdAt: Date
|
||
public var uiColor: UIColor { ... } // 计算属性
|
||
}
|
||
```
|
||
|
||
### 6.4 RDEPUBAnnotation
|
||
|
||
```swift
|
||
public struct RDEPUBAnnotation: Codable, Equatable, Identifiable {
|
||
public let id: String
|
||
public let bookIdentifier: String?
|
||
public let kind: RDEPUBAnnotationKind // .bookmark / .highlight / .underline
|
||
public let location: RDEPUBLocation
|
||
public let text: String?
|
||
public let rangeInfo: String?
|
||
public let chapterTitle: String?
|
||
public let createdAt: Date
|
||
public var bookmark: RDEPUBBookmark? { ... } // kind == .bookmark 时有值
|
||
public var highlight: RDEPUBHighlight? { ... } // kind == .highlight/.underline 时有值
|
||
}
|
||
```
|
||
|
||
### 6.5 RDEPUBSelection
|
||
|
||
```swift
|
||
public struct RDEPUBSelection: Equatable {
|
||
public let bookIdentifier: String?
|
||
public let location: RDEPUBLocation
|
||
public let text: String // 选中文本
|
||
public let rangeInfo: String? // CoreText 选区范围
|
||
public let createdAt: Date
|
||
}
|
||
```
|
||
|
||
### 6.6 EPUBPage / EPUBChapterInfo
|
||
|
||
```swift
|
||
public struct EPUBPage: Equatable {
|
||
public let spineIndex: Int
|
||
public let chapterIndex: Int
|
||
public let pageIndexInChapter: Int
|
||
public let totalPagesInChapter: Int
|
||
public let chapterTitle: String
|
||
public let fixedSpread: EPUBFixedSpread?
|
||
}
|
||
|
||
public struct EPUBChapterInfo: Equatable {
|
||
public let spineIndex: Int
|
||
public let title: String
|
||
public let pageCount: Int
|
||
}
|
||
```
|
||
|
||
### 6.7 RDEPUBSearchResult / RDEPUBSearchMatch
|
||
|
||
```swift
|
||
public struct RDEPUBSearchResult: Equatable {
|
||
public let keyword: String
|
||
public let matches: [RDEPUBSearchMatch]
|
||
}
|
||
|
||
public struct RDEPUBSearchMatch: Equatable {
|
||
public let spineIndex: Int
|
||
public let progression: Double
|
||
public let previewText: String
|
||
public let rangeAnchor: RDEPUBTextRangeAnchor?
|
||
}
|
||
```
|