App端离线阅读需用uni.downloadFile下载资源至本地沙盒并用fs.moveFile持久化存储,而非缓存HTML或使用uni.setStorage;H5端依赖HTTP缓存;Android需申请WRITE_EXTERNAL_STORAGE权限。

uni-app App端离线缓存阅读:用 uni.downloadFile + uni.getFileSystemManager 存本地文件
App端离线阅读的核心不是“缓存HTML”,而是把资源(PDF、TXT、EPUB解包后的HTML/图片等)下载到本地沙盒,再用 web-view 或 rich-text 渲染。H5端走HTTP缓存就行,但App端必须手动管理文件路径和权限。
常见错误是直接用 uni.request 拿到数据后试图在内存里渲染——App重启就丢;或者误用 uni.setStorage 存大文件(有5MB限制,且无法被 web-view 直接加载)。
-
uni.downloadFile下载后务必检查tempFilePath,它只是临时路径,需立刻用fs.moveFile移到fs.dir下的持久化目录(如uni.env.USER_DATA_PATH) - Android需额外申请
android.permission.WRITE_EXTERNAL_STORAGE(仅targetSdkVersion - iOS上不能写入
Documents目录以外的路径,且web-view只认file://协议下的绝对路径,必须用fs.realpathSync转成真实路径
PDF离线阅读:别用 web-view 直接打开网络URL,改用本地 file:// 路径
很多开发者卡在“App里点PDF链接没反应”,其实是 web-view 在App端不支持跨域加载远程PDF,也不支持HTTP协议直接渲染——必须先下载,再传 file:// 路径进去。
注意iOS对PDF路径的校验极严:路径不能含中文、空格、特殊符号;也不能是相对路径或带查询参数的URL式路径。
- 下载完成后,用
fs.copyFile把tempFilePath复制到uni.env.USER_DATA_PATH + '/pdfs/' + fileName - 构造路径时用
fs.realpathSync确保返回的是系统可识别的绝对路径,例如:file:///var/mobile/Containers/Data/Application/xxx/Documents/pdf/123.pdf - Android上若遇到白屏,检查是否漏了
android:usesCleartextTraffic="true"(仅调试期需要,正式包应禁用)
文本类内容(TXT/Markdown)离线读取:用 fs.readFile + v-html 安全渲染
纯文本离线读取比PDF简单,但容易忽略编码和XSS风险。uni-app默认用UTF-8读取,如果服务端返回GBK或Big5编码的TXT,直接读会乱码。
更关键的是,用 v-html 渲染用户可控内容前,必须过滤HTML标签——否则本地文件被篡改后可能执行JS。
- 读取前先确认文件编码:服务端统一转UTF-8,或前端用
iconv-lite(需自行引入并构建为nvue兼容版本) - 避免直接
v-html="content",至少做基础过滤:content.replace(/<script>)<[^<]*)*<\/script>/gi, '')</script> - Markdown建议用
marked+DOMPurify预处理,而不是依赖uni-app自带的rich-text(它不支持表格、代码块等扩展语法)
缓存策略与清理:别只存不管,uni.getStorageInfo 和 fs.getFileInfo 得常查
离线文件越攒越多,用户没感知,但App可能因存储爆满崩溃。uni-app没有自动缓存淘汰机制,得自己判断过期、大小、数量。
尤其要注意:App冷启动时,fs.stat 检查文件是否存在可能返回 fail no such file,不是路径错,而是文件系统还没就绪——得加个 setTimeout 延迟或监听 onLaunch 后再操作。
- 用
fs.getFileInfo查单个文件大小,结合uni.getStorageInfo的currentSize控制总缓存量(比如限制在200MB内) - 给每个缓存文件加JSON元数据(如
{url: 'xxx', timestamp: 171xxxxx, size: 1024}),存在uni.setStorage里,方便按时间或URL批量清理 - Android上删除文件后记得调用
fs.unlink清理残留,否则getFileInfo可能仍返回旧大小
最麻烦的其实是路径拼接——不同平台返回的 USER_DATA_PATH 格式不一致,iOS带 file:// 前缀,Android不带,直接拼字符串大概率挂掉。每次构造路径都得先 fs.realpathSync 再验证是否存在,少这步就白忙活。











