uni.saveImageToPhotosAlbum必须传本地filePath,不能直接传base64;需先去除data:image/xxx;base64,前缀,再用uni.base64ToArrayBuffer转ArrayBuffer,配合encoding:'binary'写入wx.env.USER_DATA_PATH路径,最后调用保存API。

uni.saveImageToPhotosAlbum 不能直接接收 base64 字符串,必须提供一个本地文件路径。所以核心问题不是“能不能存”,而是“怎么把 base64 变成合法的 filePath”。
base64 去头 + 转 ArrayBuffer 是最稳的写法
很多代码直接用 encoding: 'base64' 写入,但在 iOS 或部分安卓机型上会失败(表现为黑图、保存成功但相册看不到)。真正兼容的做法是:先去掉 data:image/png;base64, 前缀,再用 uni.base64ToArrayBuffer 转成二进制数据。
-
base64.replace(/^data:image\/\w+;base64,/, '')必须做,否则写入失败或解码错乱 -
uni.base64ToArrayBuffer(base64)返回 ArrayBuffer,writeFile的data字段必须用它,不能传字符串 -
encoding: 'binary'是关键参数,和 ArrayBuffer 搭配才有效;设成'base64'仅适用于字符串 + encoding=base64 的组合,但该组合在真机上兼容性差
filePath 必须用 wx.env.USER_DATA_PATH,不能用 _doc/ 或临时路径
小程序沙箱环境对文件路径权限很严格。_doc/ 是 5+App 的路径,微信/支付宝/飞书小程序不认;uni.getEnv().USER_DATA_PATH 在各端都稳定返回可写的用户数据目录。
- 正确写法:
${wx.env.USER_DATA_PATH}/img_${Date.now()}.png - 错误写法:
_doc/img.png、temp/img.png、/data/img.png(均无权限或路径不存在) - 文件名建议带时间戳或随机字符串,避免重复覆盖导致写入失败
权限检查和降级处理不能只走一次
用户可能第一次拒绝授权,第二次再点按钮时,uni.authorize 会直接 fail,不会再次弹窗。必须用 uni.openSetting 引导手动开启。
- 先调
uni.getSetting查当前状态 - 如果
scope.writePhotosAlbum === false,说明用户明确拒绝过,此时uni.authorize必定失败,应直接跳uni.openSetting - 如果
scope.writePhotosAlbum === undefined,才是首次授权,可用uni.authorize -
uni.saveImageToPhotosAlbum的fail回调里,要区分是权限问题(err.errMsg含authorize字样)还是文件路径/格式问题,前者引导设置,后者需查 filePath 是否合法
大图(>2MB)要提前清理旧文件
微信小程序单个文件写入上限约 10MB,但多次写入后 USER_DATA_PATH 空间可能耗尽,尤其反复保存海报类大图时,writeFile 会静默失败。
- 每次保存前,用
uni.getFileSystemManager().getSavedFileList查已存文件 - 遍历
fileList,对旧文件调removeSavedFile(注意:不是unlink) - 或者更简单:每次生成唯一文件名(如加时间戳),不删旧文件,靠系统自动回收(但长期运行仍建议清理)
实际保存逻辑里最容易被忽略的,是 ArrayBuffer 和 encoding: 'binary' 的绑定关系——漏掉任意一环,iOS 就大概率存出一张看不见的“幽灵图”。


















