把漫画放进口袋,
按需解压,一页不卡。

inkScroll 是一个 Android 优先的本地漫画 / 文档阅读器。 压缩包不解压整个文件、图片永远保持原始比例、多页无缝拼成一条长页, 并针对 120Hz 高刷屏做了适配。

Android 7.0+ (minSdk 24) · arm64-v8a / armeabi-v7a / x86_64 · MIT 开源
Features

不只是"能看"

每一条都对应一个真实踩过的坑,而不是功能清单上的凑数项。

🗜️

压缩包按需读取

自己实现 ZIP 中央目录解析(含 Zip64),只解真正要显示的那一页;打开 1GB 的压缩包和打开 1MB 的一样快,不会一次性解压全部内容。

📐

原始比例,不裁不拉伸

只给宽度约束、高度交给解码器决定。图片宽度撑满屏幕,高度按真实宽高比自动算出——同时做到不变形、不裁切、不留白。

🧵

虚拟长页无缝拼接

上下滑动模式下,下一张的顶部就是上一张的底部,没有间隙也没有高度跳动——占位用嗅探到的真实比例撑开,加载完成不重排。

⚡

120Hz 高刷新率

国产 ROM 默认把应用锁在 60Hz。inkScroll 主动申请显示模式 + 在绘制 Surface 上声明帧率,实测跑满 120fps(vsync 8.33ms)。

📁

真正可用的文件夹导入

Android 11+ 的分区存储让常规方案彻底失效。这里直接用 SAF 原生读取内容并复制进应用目录,选完即用,还能按扩展名过滤。

🔢

按文件名自然排序

2.jpg 排在 10.jpg 前面,而不是字典序。导入前还能手动调整顺序,上移、下移、置顶都支持。

🔍

格式识别到位

PNG / JPEG / GIF / WebP / BMP / ICO / AVIF / HEIC / QOI 头部解析,文件夹导入时用内容嗅探兜底,扩展名不对也能认出来。

🎛️

两种阅读模式

左右翻页:拖动和点击两侧翻页同时可用,中间呼出菜单。上下滑动:适合条漫的连续长页。

💾

进度与设置在本地

每本书独立记忆阅读模式与进度,全套设置本地持久化,不需要账号、不联网、不收集任何数据。

Screenshots

实机截图

真机(vivo V2417A / Android 16)与模拟器实测,测试图带红/绿边框以便一眼看出有没有被裁切。

真机 120fps 阅读界面
真机 120fps(左上角系统角标)
文件夹导入结果
文件夹导入:12 张图立即渲染
左右翻页模式
左右翻页:未超屏时居中
上下滑动长页
上下滑动:宽度撑满、顶部对齐
阅读菜单
阅读菜单与模式切换
Engineering

几个值得说的技术点

这个项目踩过的坑比功能多。下面几条都有实测数据支撑。

问题根因解法
图片永远加载不出来 whenComplete 返回的代理 Future 不完成,await 永久挂起 清理逻辑放进 finally,直接返回原始 Future
上下滑动完全失效 注册了 onDoubleTap 后,双击识别器在 pointer down 时就抢占手势竞技场 滚动模式不注册双击,让 Drag 拿到手势
滑动持续卡顿 占位高度为 0,解码后才变真实高度,RenderSliverList 每次重排下方全部内容 占位直接用嗅探到的比例撑开,高度零变化
文件夹导入静默失败 Android 11+ 禁止授权存储根目录;file_picker 的路径转换在 API 30+ 被跳过 自研 SAF 插件,不转路径、直接读内容
高刷屏只有 60fps 应用从未调用 Surface.setFrameRate,系统保守给 60Hz 同时申请显示模式 + 在 Surface 上声明 120Hz
渲染死循环 在 LayoutBuilder 的 builder 里改状态并 notifyListeners build 期间不做任何副作用,重建推迟到帧末

技术栈

Flutter 3.47 / Dart 3.13,状态管理用 Provider + ChangeNotifier; ZIP 解析自己写(只借用 archive 的 Inflate); 文件夹导入用自研 Kotlin SAF 插件。

性能取舍

解码宽度限制到屏幕物理宽(一页约 6MB 而不是 48MB); 页缓存 32 项 / 128MB;进度通知做节流,滚动时不再每帧重建进度条。

设计文档

仓库里的 DESIGN.md 记录了完整架构决策与取舍, README.md 有每一轮修复的根因分析——包括那些失败的尝试。

Install

安装

  1. 到 Releases 下载对应架构的 APK。
    绝大多数手机选 arm64-v8a;老设备选 armeabi-v7a;模拟器选 x86_64。
  2. 在手机上允许"安装未知来源应用",然后点击 APK 安装。
  3. 打开 inkScroll,点右下角导入,选择文件夹 / 压缩包 / 图片。
  4. 想跑满 120Hz?在系统设置里为 inkScroll 手动开启高刷新率—— 这是 Android 与国产 ROM 的限制,应用无法绕过。

从源码构建:

git clone https://github.com/BaiFeng940/inkscroll.git
cd inkscroll
flutter pub get
flutter build apk --release --split-per-abi