
上周在 F-Droid 刷新列表时看到 Gander v1.9 发布,提交信息写着「PDFs via pdf.js, no native code, one APK at 8 MB」。作为一个对「零权限、纯离线」这类工具有执念的人,我把 APK 拉下来在 Pixel 8a(Android 15)上跑了一遍,顺便把源码结构翻了一圈。
部署实录
安装路径只有两条:去 Releases 页下 gander-v1.9.apk 直接装,或者自己跑 ./gradlew assembleRelease。后者需要 JDK 21(gradle.properties 里写死 org.gradle.java.home=/usr/lib/jvm/java-21-openjdk),首次同步依赖约 40 秒,编译出的 app/build/outputs/apk/release/app-release-unsigned.apk 约 7.8 MB,加上 v1.9 引入的 pdf.js 资源包解压后也就 8.3 MB,和 README 标称的「about 8 MB」一致。
真正的坑不在构建,而在 WebView 版本门槛:README 明确要求 Android System WebView ≥ 125(2024 年 5 月发布)。我手头一台停留在 Android 12 的旧机型,WebView 卡在 119,打开 PDF 直接弹「WebView too old for pdf.js」提示并拒绝渲染——这倒是诚实,不像某些应用静默崩溃。如果你的设备还在收到 WebView 更新(大多数 2022 年后的手机都满足),这一关就能过。
首启时会请求「访问所有文件」的系统授权(MANAGE_EXTERNAL_STORAGE),但这属于用户主动授予的「一次性系统授权」,不在 AndroidManifest.xml 的权限列表里。授权后进入主页,顶部是最近文件缩略图网格,下方是已授权文件夹列表,长按文件夹可撤销授权。整个流程没有任何登录、联网、埋点请求,logcat 过滤 INTERNET 关键字零输出。
核心亮点
pdf.js 在沙箱 WebView 里跑通 PDF 渲染,彻底甩掉 Pdfium 原生依赖
v1.9 之前用的是 Pdfium(Chromium 同源的 C++ PDF 引擎),编出来的 libpdfium.so 单就有 15 MB 以上,且涉及 NDK 编译链、架构适配(arm64-v8a / x86_64)、内存泄漏排查。改用 pdf.js(Apache-2.0)后,渲染逻辑全移到 assets/pdfjs/ 下的 JS 代码,通过 WebView.evaluateJavascript() 与 Kotlin 侧通信。WebView 配置了 setJavaScriptEnabled(true) + addJavascriptInterface(null) + setAllowFileAccess(false) + setAllowContentAccess(false),文档流以 content:// URI 传入,never touches the network stack。实测打开 40 MB 的《Deep Learning》教材 PDF,首屏渲染 1.2 秒,拖动翻页基本跟手,内存峰值 180 MB,比 Pdfium 时代的 300 MB+ 低一截。代价是复杂矢量图(如 CAD 导出的 PDF)偶尔出现字形缺失,且无法利用 GPU 加速——但对于「看文档、查表格、批注高亮」的主流场景,这笔交换划得来。
六个 JS 库零原生代码覆盖 Office 全家桶 + 多媒体
除 pdf.js 外,assets/ 还内置了:docx-preview(Word)、SheetJS CE(Excel)、PPTXjs + divs2slides(PPT)、marked + DOMPurify(Markdown)、Media3 ExoPlayer(音视频)。它们统一跑在同一个沙箱 WebView 里,Kotlin 侧只负责:① 解析文件扩展名/MIME 类型 ② 把 ParcelFileDescriptor 转 content:// URI 喂给 WebView ③ 监听 JS 侧回调的「打开失败/加载进度/搜索匹配」事件。这种架构把「格式支持」变成了「往 assets 扔一个 JS 库」的配置活,不需要写一行 JNI。实测 .docx 保留了换行/表格/图片,.xlsx 能切 Sheet Tab、冻结首行,.pptx 能放映模式逐页翻放,.md 渲染出带代码高亮的 HTML。唯一的短板是 .doc/.xls/.ppt 这类 OLE Compound Document 二进制格式——README 直白承认「no faithful offline renderer exists」,建议另存为 Office Open XML。
深度缩放图片查看器(Tiled Decoding)是隐藏的杀手级功能
打开一张 12000×9000 像素的全景图(约 45 MB JPEG),Gander 不会一次性解码进内存导致 OOM,而是用 ImageDecoder 做分瓦解码,配合 TouchImageView 实现双指缩放、平移,缩放到 500% 依然能看清纹理细节。EXIF 信息一键展开,包含快门/光圈/ISO/GPS 坐标。这套实现完全复用了 Android 框架能力,零第三方依赖,代码在 app/src/main/java/.../viewer/ImageViewerFragment.kt 不足 200 行。
避坑与总结
值得花时间折腾的理由:真正做到「零权限、零网络、零广告、零追踪」的全格式查看器在 Android 生态里极其稀缺;8 MB 体积换来 pdf.js + SheetJS + ExoPlayer 全家桶,技术选型极其克制;MIT 协议、签名密钥本地保管、Obtainium 可验证指纹,供应链安全做到位。
不得不接受的妥协:① WebView 版本硬门槛把一部分老设备挡在外面;② 复杂 PDF 矢量渲染保真度不如原生 Pdfium;③ 无法编辑、无法批注、无法表单填充——它定位就是「只读查看器」;④ 搜索功能仅对文本类格式生效,扫描版 PDF 走不了 OCR;⑤ 代码高亮依赖 WebView 注入 CSS,极长单行(>10k 字符)会卡顿。
个人判断:如果你需要一个「扔进手机、永远不联网、什么格式都能打开看一眼」的工具,Gander 是目前能找到的最干净、最透明、体积最小的答案。把它装在主力机上,下次收到微信传过来的 .docx/.xlsx/.pdf,长按「用其他应用打开」选 Gander,全程不出设备、不留痕迹——这份安心感,值得那 8 MB 存储空间。
推荐阅读:
支付宝可直接付款,3分钟搞定 ChatGPT/Gemini/Claude订阅
我用自然语言写了个带后台的App。AI“零代码”终于脱离玩具时代了
手慢无:送出 5 个免手续费汇款名额(最高 US$600),AI 开发者自取。
👇👇👇点击识别下方账号名片关注「YouywayAI」获取更多学习编程、AI开发相关的趣工具和实用资源!
夜雨聆风