app端离线缓存必须用plus.io或plus.sqlite,因uni.setstorage仅支持小量键值对,无法安全存储图片、html等大资源,易致内存溢出、读取失败或ios写入丢失。

uni-app App端离线缓存不能只靠 uni.setStorage,必须结合 plus.io 或 plus.sqlite 才能真正落地——因为 uni.setStorage 在App端虽映射为 plus.storage(持久化),但它只适合小量键值对,无法存图片、HTML、JSON文件等资源型内容。
为什么 uni.setStorage 不够用?
它本质是键值对存储,value 会被序列化为字符串。一旦你要缓存一张 2MB 的商品图、一个含 HTML 的富文本详情页、或一组带附件的离线工单数据,uni.setStorage 就会触发内存溢出、写入失败或读取变慢。
常见错误现象包括:
-
plus.storage写入大对象时无报错但实际未写入(尤其 iOS) - 读取后 JSON.parse 失败,提示 “Unexpected token”(因字符串被截断或编码损坏)
- H5 端和 App 端行为不一致:H5 的
localStorage有 5MB 限制,而 App 端虽无硬限制,但直接塞大字符串仍会卡 UI 线程
App端推荐用 plus.io 存文件资源
这是最贴近“离线包”语义的方案:把远程资源(如 https://api.example.com/pages/order-detail.html)下载并保存为本地文件(如 _doc/offline/order-detail.html),后续直接用 plus.io 读取并渲染。
实操要点:
- 使用
plus.io.PRIVATE_DOC目录(App 可读写,且不会被系统清理) - 文件路径必须用
plus.io.convertLocalFileSystemURL(path)转成可被<web-view></web-view>或uni.loadSubNVue加载的本地 URL - 下载前先检查磁盘空间:
plus.runtime.getDiskInfo(),避免写满导致崩溃 - 文件名建议用资源 URL 的 MD5 值(如
md5('https://.../detail.json')),避免特殊字符和路径冲突
怎么管理离线包的版本与更新?
离线包不是“写一次就完事”,必须支持增量更新、过期校验、回滚机制。关键动作:
- 服务端提供 manifest.json,包含每个资源的
url、md5、size和timestamp - App 启动时比对本地 manifest 与服务端 manifest,只下载变更/新增的文件(跳过未变的)
- 下载完成后原子替换:
manifest.json.new → manifest.json+资源文件.new → 资源文件,防止半更新状态 - 异常中断时,保留上一版完整 manifest 和资源,保证下次启动仍可用
注意:plus.io 没有事务概念,所以“原子替换”要靠重命名 + moveTo 实现,不能直接覆盖写。
离线包加载时如何无缝 fallback?
用户打开页面时,你得先尝试加载本地离线包,失败再走网络请求。但不能简单 try/catch plus.io.resolveLocalFileSystemURL 就去发网络请求——因为首次冷启动时文件可能还没下完,或者用户刚删了缓存。
更稳妥的做法是:
- 用
uni.getStorageSync('offline_status')记录当前离线包状态('ready'/'downloading'/'failed') - 在页面
onLoad中,先查状态;若为'ready',则用plus.io.resolveLocalFileSystemURL加载;否则显示 loading 并静默拉取 - 网络请求失败时,才兜底用本地缓存(哪怕旧一点),而不是直接报错或白屏
容易被忽略的一点:iOS 上 plus.io 读取文件时,如果路径含中文或空格,resolveLocalFileSystemURL 会返回 null —— 必须提前 encodeURIComponent 文件名,且全程用英文路径命名离线包目录。











