一款克制、专注的 Android 文本阅读器 —— 暖纸质感、仿真翻页、进度永不丢失。本地 txt / EPUB / MOBI(AZW3) 阅读 · 可选自定义规则 · WebDAV 跨端同步。
Inkwell 用 Jetpack Compose 从零写成,没有广告、没有账号、没有推送。排版引擎全自绘、进度以「章节 + 章内偏移」为真身,改字号也不丢位置;书架、进度与用户配置可通过 WebDAV 单文件同步,书籍文件不上云。默认不内置任何第三方内容或访问规则;规则如需使用,均由用户自行导入并对其合法性负责(见下方免责声明)。
阅读
- 四种翻页:仿真(贝塞尔卷页 + 背面镜像 + 折线阴影)/ 覆盖 / 平移 / 无动画,拖拽跟手、按位移与速度裁决提交或回滚,左右点击与音量键复用同一动画。
- 自绘排版引擎:Canvas +
TextMeasurer分页,测量产出的TextLayoutResult即渲染对象,机制上杜绝分页溢出。 - 进度真身为
(章节索引, 章内字符偏移),页码只是当前排版下的投影 —— 换字号 / 字体 / 屏幕都不丢位置。 - 四款系统预设字体(默认 / 衬线 / 无衬线 / 等宽),亮暗主题跟随暖纸配色。
- 阅读中可切换用户已配置的规则来源;同一次阅读会话内会复用已找到的候选,不必每次重搜。
书架与规则
- 本地导入 txt / EPUB / MOBI(AZW3),与经用户规则加载的内容统一为
ContentElement段落流,一套引擎渲染;同名同作者的本地书不会重复入库。 - 支持用户自行导入 JSON 规则(含与 Legado 文本规则兼容的子集,见下节「高级:规则说明」);应用不预置、不推荐任何具体规则来源。
- 目录刷新:书架下拉可检查更新、显示最新章节与未读提示。
- 分组筛选、书内 / 全局搜索、可开关的发现入口(仅在用户已导入相应规则时可用)。
- 长按书籍弹出操作面板(详情 / 分组 / 删除等);面板内可进入多选,批量删除、分组或隐藏。
- 私密书架:可选生物识别 / 密码保护的隐藏分区,入口本身不可见(长按书架标题进入)。
- RSS 订阅:导入订阅源、浏览文章列表与正文。
同步与维护
- WebDAV 单文件(
inkwell/backup.json.gz)增量同步,字段级 Last-Write-Wins 合并(进度按readAt、元数据按updatedAt);凭据经系统密钥库加密存放。 - 应用内更新检查,稳定 / 测试双通道。
- 一键清理正文缓存(不影响书架与阅读进度)。
| 模块 | 说明 |
|---|---|
:core |
纯 JVM:统一书籍模型、txt/EPUB/MOBI 解析器、可选规则引擎(含 Rhino JS)、WebDAV 客户端与备份合并(全部可 JVM 单测) |
:reader |
阅读排版引擎:Canvas 自绘 + TextMeasurer 分页;测量层抽象为接口,分页算法纯 Kotlin 可测 |
:app |
Compose UI、Room、DataStore、导航、DI(Koin)、同步 |
技术栈:Kotlin 2.3 · Jetpack Compose · Room · Koin · OkHttp · Jsoup · Rhino · kotlinx.serialization。
# 需要 JDK 21 与 Android SDK (platform 36+, build-tools 与 compileSdk 对齐)
./gradlew assembleDebug # 产出 app/build/outputs/apk/debug/app-debug.apk
./gradlew test # 全部 JVM 单元测试在 local.properties 配置 sdk.dir=<Android SDK 路径>。正式签名从环境变量注入(CI 用),本地未配置时自动回落 debug 签名。
- 测量渲染同源:分页时产出的
TextLayoutResult就是渲染时绘制的对象,从机制上消灭「分页看着对、渲染却溢出」。 - 进度与排版解耦:进度是
(章节, 章内偏移),页码是投影;任何排版参数变化都能重新定位到同一句话。 - 统一段落流:txt / EPUB / MOBI / 用户规则加载的内容统一解析为
ContentElement(段落 / 标题 / 图片 / 分隔线),一套排版引擎渲染全部格式。 - 可测优先:核心逻辑(解析、分页、规则求值、备份合并)下沉到纯 JVM 模块,脱离 Android 也能单测。
以下内容面向自行编写或导入规则的进阶用户。应用默认不包含任何规则;导入与使用规则的合法性由用户自行负责。
支持用户导入的 JSON 规则格式。自研 Schema 的选择器 mini-DSL 支持 css: / json: / regex: / text: 前缀、|| 回退、&& 拼接与后处理管道。示例仅说明字段结构,不构成对任何站点的指向或推荐:
{
"schemaVersion": 1,
"id": "com.example.mysource",
"name": "示例规则",
"baseUrl": "https://www.example.com",
"version": 1,
"search": {
"request": { "url": "/search?q={{keyword}}" },
"list": "css:div.result-item",
"fields": {
"title": "css:h3 a@text",
"bookUrl": "css:h3 a@href",
"author": "css:.author@text"
}
},
"detail": { "fields": { "tocUrl": "css:a.toc@href" } },
"toc": {
"list": "css:dd a",
"fields": { "title": "css:@text", "url": "css:@href" }
},
"content": {
"content": "css:div#content@html",
"purify": [ { "pattern": "本章未完.*", "replacement": "", "isRegex": true } ]
}
}在「设置 → 书源管理」可通过剪贴板或网址导入(单个对象或数组均可);详情页支持校验与格式化。
引擎亦兼容部分 Legado(阅读)文本规则语义(运行时求值,而非一次性静态转换)。
面向文本类规则。支持的子集包括:
- 默认 Jsoup 层级(
class.foo.0@tag.a@href)、@css:、JSONPath($.)、:正则、XPath(@XPath:///) ||回退、&&拼接、##正则##替换净化、replaceRegex- JS 规则(
<js>/@js:/ 部分{{表达式}}),由 Rhino 执行;引擎带沙箱与超时,禁止访问本地私网等危险能力 - POST 搜索(
searchUrl的 method/body/charset 选项,含字符集编码选项) exploreUrl发现页(名称::url格式)、concurrentRate限速、倒序目录(-前缀)
不支持:音频 / 漫画 / 文件源(bookSourceType ≠ 0);依赖未实现 Legado API 或绕过沙箱的极端 JS;部分动态发现地址无法静态列举。关键规则无法解析时会在导入或校验结果中说明;次要字段失败时丢弃该字段、规则仍可用。
- 下载:前往 Releases 获取签名 APK。应用内「设置 → 检查更新」也可直接拉取。
- 发版流程:改
gradle/libs.versions.toml的inkwell版本号 → 提交 → 打带注解的 tag(git tag -a vX.Y.Z)→ 推送 tag。CI 校验 tag 与版本号一致后自动构建签名 APK 并发布 Release。 - Release 正文取自 tag 注解本身,且应用内更新弹窗按纯文本渲染 —— tag 注解请写纯文本、不要用 Markdown。
- 带
-后缀的 tag(如v0.1.9-beta.7)会标为预发布,只推测试渠道。
【特别提示】 在下载、安装或使用 Inkwell(墨水)前,请您务必仔细阅读并充分理解本协议及免责声明的全部内容。您一旦下载、安装或使用本软件,即视为已阅读、理解并同意接受本声明的全部内容。
- 本软件是一款面向文本书籍的本地阅读工具,主要提供本地书籍打开与排版、阅读界面自定义、书架与进度管理、以及用户可选的数据备份等功能。本软件不提供也不支持有声书、漫画、视频等其他内容形态。
- 本软件默认状态下不预置、不内置、不提供任何第三方站点内容或第三方阅读内容,也不预置任何第三方访问规则。
- 本软件开发者不提供任何内容运营、内容存储、内容发布或内容传播服务。
- 用户可导入本人合法持有的本地文本书籍(如 TXT、EPUB、MOBI 等)。如用户自行添加或导入第三方规则,相关配置完全由用户决定;开发者不提供、不推荐、不运营任何具体规则或内容来源。
- 用户可自行创建、编辑、导入或使用其获得的规则;是否使用、如何使用,均由用户自行决定。
- 规则的来源、合法性、准确性与适用性均由用户自行判断并承担责任。开发者不对任何第三方规则作背书。
- 若用户启用了相关规则,由此产生的网络访问由用户设备发起;本软件仅在用户设备本地完成展示与排版,不代替用户向公众传播内容,也不对第三方站点内容进行再分发。
- 用户应遵守所在地法律法规、网络安全要求以及相关网站或内容的服务协议与版权规范,不得利用本软件从事侵犯知识产权、非法传播或其他违法违规行为。
- 任何由第三方建立或维护的规则分享平台、论坛、交流群组、网站或其他社区,均属于独立运营的第三方平台,与本软件开发者无隶属关系。
- 开发者不参与第三方规则、内容或社区的制作、发布、运营、维护与传播行为,亦不对相关内容承担主动审查义务。
- 用户因使用第三方规则或访问第三方站点而产生的风险,包括但不限于版权纠纷、数据安全风险、网络访问风险或其他法律风险,应由相关行为主体依法承担相应责任。
- 本软件主要功能运行于用户本地设备,不设立用于提供阅读内容服务的自有内容服务器。
- 本软件不会主动收集、上传或存储用户的阅读正文、规则列表、浏览记录或其他个人隐私数据用于运营分析。
- 用户主动启用的功能(例如 WebDAV 备份同步、应用内检查更新、意见反馈)会在用户操作或明确配置的前提下,与用户指定的服务器或公开仓库发生必要的网络通信;相关凭据与数据的安全由用户自行妥善保管。
- 部分网络、存储或同步权限,仅用于实现本地阅读、备份同步或用户主动触发的更新与反馈等功能。
- 开发者尊重并保护知识产权权利人的合法权益,并反对任何侵犯著作权、商标权或其他合法权益的行为。
- 用户应确保其使用本软件打开、阅读或管理相关内容的行为符合适用法律法规及权利要求。
- 若权利人认为某些第三方规则存在涉嫌侵权情形,可依法向相关内容实际托管方主张权利。
- 权利人亦可向开发者提交包含身份证明、权属证明、具体规则信息及相关说明的有效通知。开发者将在合理技术能力范围内采取必要处理措施(例如协助处理反馈渠道中的相关讨论);开发者无法远程删除用户设备上已导入的规则或本地数据。
- 本软件按「现状」提供。开发者不对第三方规则是否可用、第三方站点是否可访问、或用户自行配置后的阅读效果作任何明示或默示担保。
- 因用户自行配置的规则、网络环境、第三方站点变更或不可抗力导致的任何直接或间接损失,开发者在法律允许的最大范围内不承担责任。
- 本软件以开源形式发布,程序代码的许可条款以仓库根目录 LICENSE(MIT)为准;本声明不构成对开源许可的修改。
开发者可根据需要更新本声明。更新后的内容将随软件版本或项目文档公布;继续使用本软件即视为接受更新后的内容。
独立全文亦见 DISCLAIMER.md;应用内「设置 → 关于 → 用户协议与免责声明」可查阅同文。