一款基于 Flutter 的跨平台多媒体阅读器,兼容阅读(Legado)书源规则体系(CSS/JSONPath/XPath/JS 规则 +
java.*桥接对象),不支持 Legado 的 java 包类(io.legado.app.*原生类),支持小说、漫画、音频、视频与本地书。
- 完整语法支持:CSS/JSoup 选择器、JSONPath、XPath、JavaScript、正则替换、模板规则
- JS 引擎:QuickJS(C 原生 FFI,ES2020)
- 加密兼容:
CryptoJSAPI +java.*桥接加密方法,底层统一走 C 原生实现(AES/MD5/SHA/HMAC) - 书源管理:兼容 Legado JSON 导入/导出,支持书源调试 + 执行追踪树
| 类型 | 功能 |
|---|---|
| 小说阅读器 | 仿真翻页 / 滚动 / 滑动 / TTS 朗读 / 自定义主题 |
| 漫画阅读器 | 竖向滚动 / 左右翻页 / 双页模式 / 按需缓存 |
| 音频播放器 | 后台播放 / 定时停止 / 播放列表 |
| 视频播放器 | 内置播放页 / 横竖屏切换 |
- 支持书源配置的
coverDecodeJs(封面解密)和ruleContent.imageDecode(正文图片解密) DecodedImageProvider自定义 ImageProvider:下载 → JS 解密 → 解码- 已重写
==/hashCode,FlutterImageCache可正常复用
- Android / iOS / HarmonyOS(鸿蒙)/ Web / Windows / Linux / macOS 同一代码库
- Web 平台自动启动 CORS 代理(
ProxyService.instance.start()) - 鸿蒙构建未签名 HAP,用户自行用 DevEco Studio 签名后安装
- 书源无需针对平台修改
CrashLogService启动最先初始化,注册全局错误捕获runZonedGuarded捕获所有未处理异步错误StorageService未初始化时所有同步 getter 返回空值,避免HiveError崩溃- 启动时检测上次崩溃日志并弹窗显示
| 层 | 技术 | 路径 |
|---|---|---|
| UI 框架 | Flutter 3.41+ | lib/ |
| 状态管理 | Provider(6 个 Provider) | lib/providers/ |
| 本地存储 | Hive | lib/services/storage_service.dart |
| HTTP 客户端 | Dio + OkHttp(Android 原生通道) | lib/services/source_engine/ |
| JS 引擎 | QuickJS(C FFI,ES2020) | lib/services/native/ |
| 规则引擎 | 自定义解析器 | lib/services/source_engine/ |
| HTML 解析 | package:html(CSS 选择器) |
规则引擎内部 |
| HTML 解析(C) | lexbor(C99 HTML 解析器) | quickjs/lexbor/ |
| 加密 | C 原生实现 | quickjs/crypto/ |
| 图片解密 | DecodedImageProvider |
lib/services/image_decode_provider.dart |
| 崩溃日志 | CrashLogService |
lib/services/crash_log_service.dart |
| 路由 | 自定义 AppPageRoute(零时长切换) |
lib/routes/app_routes.dart |
lib/main.dart 在 runZonedGuarded 中依次初始化:
CrashLogService.instance.init()— 崩溃日志(最先,注册全局错误捕获)AppLogger.instance.initFileLogging()+enableDebugPrintCapture()— 应用日志Hive.initFlutter()→StorageService.instance.init()— 本地存储JsEngine.instance.init()— JS 引擎CoverConfigService.instance.init()— 封面配置ProxyService.instance.start()— CORS 代理(仅 Web)runApp(DanShenqiApp())
每个服务初始化均包裹在 try-catch 中,单个服务失败不中断启动。
mr/
├── lib/ # Dart 源码
│ ├── main.dart # 入口:runZonedGuarded 初始化各服务
│ ├── models/ # 数据模型
│ │ ├── book.dart / book_source.dart / chapter.dart
│ │ ├── highlight.dart / miniprogram.dart / replace_rule.dart
│ │ └── rules/ # 六类规则模型(search/explore/bookInfo/toc/content/review)
│ ├── pages/ # 13 个页面子目录
│ │ ├── bookshelf/ # 书架
│ │ ├── reader/ # 小说阅读器 + 漫画阅读器
│ │ ├── player/ # 音频和视频播放器
│ │ ├── detail/ # 书籍详情 + 章节列表
│ │ ├── search/ # 搜索
│ │ ├── discovery/explore/ # 发现 / 发现详情
│ │ ├── miniprogram/ # 小程序
│ │ ├── web/ # 内置浏览器
│ │ ├── debug/ # 书源调试 + 崩溃日志面板
│ │ ├── profile/ # 设置中心(11 个子页)
│ │ ├── settings/ # 主题 / AI 设置
│ │ └── main/ # 主框架页
│ ├── providers/ # 6 个状态 Provider
│ ├── routes/app_routes.dart # 集中路由表
│ ├── services/
│ │ ├── source_engine/ # 规则引擎核心
│ │ │ ├── analyze_rule.dart # 规则解析器(CSS/JSON/XPath/JS/正则/模板)
│ │ │ ├── analyze_url.dart # URL 解析(含 Legado 选项)
│ │ │ ├── web_book.dart # 网络书籍抓取引擎
│ │ │ ├── legado_json_path.dart # JSONPath 实现
│ │ │ ├── legado_xpath.dart # XPath 实现
│ │ │ ├── dan_file.dart # .dan 打包文件解析
│ │ │ ├── charset_utils.dart # 字符集转换
│ │ │ ├── proxy_service.dart # CORS 代理
│ │ │ └── web_proxy*.dart # Web 请求代理(平台分支)
│ │ ├── native/ # 原生桥接层
│ │ │ ├── js_engine.dart # JsEngine 主入口 + 引擎调度
│ │ │ ├── quickjs_runtime.dart # QuickJS FFI 绑定(Android/iOS/桌面)
│ │ │ ├── quickjs_runtime_stub.dart # QuickJS Web 平台 stub
│ │ │ ├── shared_js_scope.dart # 跨引擎共享作用域
│ │ │ ├── js_advanced_service.dart # 高级 JS(WebView 注入)
│ │ │ ├── platform_bridge.dart # 平台桥接
│ │ │ ├── platform_channel.dart # Android/iOS 原生通道
│ │ │ └── dio_ssl_helper_*.dart # Dio SSL 平台分支
│ │ ├── local_book/ # 本地书解析(EPUB / TXT)
│ │ ├── storage_service.dart # Hive 存储(含未初始化防护)
│ │ ├── book_data_provider.dart
│ │ ├── book_source_import_service.dart
│ │ ├── book_source_locator.dart
│ │ ├── chapter_cache_service.dart
│ │ ├── chapter_prefetch_service.dart
│ │ ├── source_debug_service.dart
│ │ ├── reader_bookmark_service.dart
│ │ ├── reader_tts_manager.dart
│ │ ├── read_record_service.dart
│ │ ├── cookie_service.dart
│ │ ├── cover_config_service.dart
│ │ ├── share_service.dart
│ │ ├── image_decode_provider.dart # 图片解密 ImageProvider
│ │ ├── crash_log_service.dart # 崩溃日志服务
│ │ └── app_logger.dart # 应用日志
│ ├── themes/ # 主题配置 + 圆角徽标
│ ├── utils/ # 设计令牌 / 简繁转换 / 分享工具
│ └── widgets/ # 公共组件 + reader 子组件
├── quickjs/ # QuickJS C 源码
│ ├── quickjs.c / quickjs.h # QuickJS 引擎核心
│ ├── quickjs_bridge.c/h # C 桥接层 — 所有 FFI 导出符号
│ ├── handle_table.c/h # 句柄表(id→指针映射,ABA 防护)
│ ├── memory_tracker.c/h # 全局内存追踪器
│ ├── quickjs-c-atomics.h # 跨编译器 C11 原子操作兼容层
│ ├── crypto/ # 加密实现(AES/MD5/SHA/HMAC)
│ ├── html_native.c/h # HTML 解析 C 原生加速
│ ├── http_client.c/h # C HTTP 客户端
│ ├── charset_conv.c/h # 字符集转换
│ ├── lzstring.c # LZ 字符串压缩
│ ├── batch_decompress.c/h # 批量解压
│ ├── lexbor/ # lexbor HTML 解析器(C99)
│ └── ohos/ # 鸿蒙 CMakeLists.txt
├── android/app/src/main/cpp/ # Android CMakeLists + 符号映射
├── ios/ # iOS Runner + Podfile + NativePlugin.swift
├── assets/templates/ # 书源模板 + 帮助文档
└── tools/cors-proxy.js # Web CORS 代理脚本
| 优先级 | 模块 | 功能 | 文件 |
|---|---|---|---|
| P1 | 内存所有权 | 句柄表(id→指针)+ 版本号 ABA 防护 + 自由链复用 + 自动扩容 | handle_table.c/h |
| P1 | 内存追踪 | 全局线程安全 malloc/free 计数 + 峰值 + 失败计数 | memory_tracker.c/h |
| P1 | 原子操作兼容 | GCC <4.9 回退到 __sync 内建函数 | quickjs-c-atomics.h |
| P2 | 超时熔断 | JS_SetInterruptHandler + 5s 默认超时 + OC 熔断标记 |
quickjs_bridge.c |
| P2 | GC 阈值 | JS_SetGCThreshold(memory_limit/4) |
quickjs_bridge.c |
| P2 | 字节码剥离 | JS_SetStripInfo(JS_STRIP_SOURCE | JS_STRIP_DEBUG) |
quickjs_bridge.c |
| P3 | 线程安全 | pthread_mutex_t 保护所有 QuickJS 调用(多 Isolate 防崩溃) |
quickjs_bridge.c |
| P4 | 输入验证 | 脚本 1MB / HTML 10MB / HTTP 50MB / Base64 10MB / 加密 10MB | quickjs_bridge.c |
| P4 | 8KB 行限制 | HTTP 逐行读取行缓冲上限 | http_client.c |
| P5 | 引擎内存监控 | JS_ComputeMemoryUsage 25 字段全量暴露 |
quickjs_bridge.c |
| P5 | 调试面板 | JS 内存卡片 + GC 按钮 + Promise 状态监控 + JS 值打印 | crypto_stats_panel.dart |
| P5 | 降级回退 | 所有 C 调用 try-catch 包裹 | quickjs_runtime.dart |
| 规则类型 | 状态 | 说明 |
|---|---|---|
| CSS/JSoup 选择器 | ✅ | class.xxx / tag.xxx / @css: / 索引切片 |
| JSONPath | ✅ | $.xxx / $[n] / $..xxx / 过滤器 |
| XPath | ✅ | //div[@class] / @xpath: / HTML 自动补全 |
| JavaScript | ✅ | @js: / <js> / 全局 JS 执行 |
| 正则替换 | ✅ | ##regex##replacement / ### |
| 模板规则 | ✅ | {{@@.xxx@text}} / {{$.xxx}} |
| 变量系统 | ✅ | @put / @get / java.put/getStr |
| CryptoJS | ✅ | AES / MD5 / SHA / HMAC 全支持 |
| java.* 桥接 | ✅ | HTTP / 加密 / 解析 / 缓存 / 日志 |
- Flutter 3.41+(项目内置
flutter.bat,默认指向D:\flutter_windows_3.41.7-stable,可设FLUTTER_ROOT覆盖) - Android NDK 28.x(编译 C 桥接层时需 CMake + NDK clang)
- CMake 3.22+
- 鸿蒙开发需额外安装 鸿蒙 Flutter SDK + DevEco Studio
flutter pub get # 安装依赖
flutter run # 运行
flutter build apk # 构建 Android APK(含 C 编译)
flutter build ios # 构建 iOS(含 C 编译)
flutter build hap # 构建 HarmonyOS HAP(需鸿蒙 Flutter SDK)
flutter analyze # 静态分析 + lint
flutter test # 运行 test/ 全部测试
flutter.bat已预设国内镜像(pub.flutter-io.cn/storage.flutter-io.cn)与本地 pub-cache。
test/ 目录:
| 文件 | 内容 | 运行命令 |
|---|---|---|
widget_test.dart |
占位测试 | flutter test |
legado_rule_test.dart |
CSS/JSoup 链式选择器规则 | flutter test test/legado_rule_test.dart |
book_source_compat_test.dart |
书源导入、URL 解析、元数据合并、源定位 | flutter test test/book_source_compat_test.dart |
crypto_native_test.dart |
C 原生加密对比(需 Android 真机/模拟器加载 .so) | flutter test test/crypto_native_test.dart |
chinese_converter_test.dart |
简繁中文转换 | flutter test test/chinese_converter_test.dart |
CI 不跑测试与 lint。
analysis_options.yaml(.gitignore 忽略):avoid_print、prefer_single_quotes、sort_child_properties_last、use_key_in_widget_constructors、prefer_const_constructors、prefer_final_fields/locals、prefer_const_declarations。
使用 debugPrint 替代 print(avoid_print 强制)。
- 全项目使用中文注释与中文标识符
- 路由使用
Map<String, dynamic>?参数(见app_routes.dart) - 路由参数可能是
Map(动态)或Map<String, dynamic>— 代码通过is Map检查兼容两者 - 序列化:
Book.fromJson/BookSource.fromJson - 异步操作后使用
BuildContext前必须检查mounted - 空值断言
!应替换为局部变量 + null 检查(类型提升) - 删除文件时同步清理 barrel export(
source_engine.dart等)
push 到任意分支(非 master)时,自动将该分支合并到 master。冲突 → 自动创建 PR。
| 平台 | 触发 | 产物 | 签名 | 允许失败 |
|---|---|---|---|---|
| Android | push master / 手动 | mr_v*_dev_*.apk(arm64) |
Release 签名 | 否 |
| iOS | push master / 手动 | mr_v*_dev_*.ipa |
未签名(--no-codesign) |
是 |
| HarmonyOS | push master / 手动 | mr_v*_dev_*.hap |
未签名(用户自行签名) | 是 |
- 版本号格式:
YY.MMDD.今日提交数(如25.0715.3) - 手动触发可选
dev(测试版)或stable(正式版) - 鸿蒙 Flutter SDK 为华为 fork,CI 动态获取最新 release 分支并克隆
- CI 不跑测试与 lint
MIT License