UniApp实战:如何优雅地把 uv-ui (uv-qrcode) 生成的二维码保存到手机相册

前言

在 UniApp 开发中,使用 uv-uiuv-qrcode 组件生成二维码非常方便。但是,当我们试图将这个生成的二维码保存到手机相册时,往往会遇到各种"坑",比如:

  • 调用 toTempFilePath 拿到的不是路径而是 Base64 字符串?

  • saveImageToPhotosAlbum 报错文件不支持?

  • 用户拒绝了相册权限后怎么引导重新开启?

本文将为你提供一套**"保姆级"**的完整解决方案,涵盖从获取数据、Base64转文件到权限处理的全流程。


1. 核心流程概览

保存二维码的过程本质上就是把"内存里的画"变成"相册里的图"。主要分为三个关键步骤:

  1. 获取数据:调用组件方法,把当前的二维码画面导出来。

  2. 数据清洗(关键避坑点):判断导出的是"文件路径"还是"Base64 字符串"。如果是 Base64,系统保存接口不支持,必须手动转成二进制文件。

  3. 保存入库:调用系统 API 存入相册,并优雅地处理权限授权问题。


2. 详细实现步骤

第一步:获取组件实例并导出

首先,在 template 中给组件绑定 ref,并在 JS 中调用组件内部的 toTempFilePath 方法。

Template 代码:

HTML

javascript 复制代码
<template>
  <view>
    <uv-qrcode ref="qrcode" value="https://www.example.com" size="200px"></uv-qrcode>
    <button @click="saveQrcode">保存二维码</button>
  </view>
</template>

JS 代码:

JavaScript

javascript 复制代码
methods: {
  saveQrcode() {
    const ref = this.$refs.qrcode;
    // 必须判空,防止组件没加载完就调用报错
    if (!ref) return;
    
    ref.toTempFilePath({
      success: (res) => {
        // 拿到结果:res.tempFilePath
        // 这里千万别急着存,先交给下一步清洗函数处理
        this.handleSave(res.tempFilePath);
      },
      fail: (err) => {
        console.error('获取图片失败', err);
      }
    });
  }
}

第二步:数据清洗与转换(核心黑科技)

这是最容易翻车的地方!res.tempFilePath 返回的数据有两种情况:

  • 情况 A(理想)wxfile://tmp/xxxx.png ------ 真实路径,直接存。

  • 情况 B(现实)data:image/png;base64,iVBORw... ------ Base64 字符串,系统 API 无法直接保存

我们需要使用 uni.getFileSystemManager 将 Base64 写入为本地临时文件。

JavaScript

javascript 复制代码
handleSave(filePath) {
  // 1. 判断是否是 Base64 数据流
  if (filePath.startsWith('data:image')) {
    // === 核心黑科技开始 ===
    
    // 创建文件管理器
    const fs = uni.getFileSystemManager();
    
    // 去掉头部 'data:image/png;base64,',只保留纯数据
    const code = filePath.split(',')[1];
    
    // 把 Base64 字符串转成二进制 Buffer
    const buffer = uni.base64ToArrayBuffer(code);
    
    // 定义一个本地临时文件名(使用时间戳防止重名)
    const fileName = `${uni.env.USER_DATA_PATH}/qrcode_${Date.now()}.png`;
    
    // 写入本地文件
    fs.writeFile({
      filePath: fileName,
      data: buffer,
      encoding: 'binary',
      success: () => {
        // 写入成功!现在 fileName 就是一个真实的本地路径了
        console.log('转换成功,临时路径:', fileName);
        this.saveImageToAlbum(fileName);
      },
      fail: (err) => {
        console.log('Base64转文件失败', err);
        uni.showToast({ title: '图片转换失败', icon: 'none' });
      }
    });
    // === 核心黑科技结束 ===
    
  } else {
    // 2. 如果本身就是路径(如微信小程序环境部分情况),直接保存
    this.saveImageToAlbum(filePath);
  }
}

第三步:保存到相册与权限处理

最后一步调用 saveImageToPhotosAlbum,同时要考虑到用户可能第一次手抖点了"拒绝授权",我们需要引导用户去设置页重新开启。

JavaScript

javascript 复制代码
saveImageToAlbum(filePath) {
  uni.showLoading({ title: '保存中...' });
  
  uni.saveImageToPhotosAlbum({
    filePath: filePath,
    success: () => {
      uni.hideLoading();
      uni.showToast({ title: '保存成功', icon: 'success' });
    },
    fail: (err) => {
      uni.hideLoading();
      console.log('保存失败', err);
      
      // 检查是不是因为权限问题失败的
      // 不同端报错信息可能不同,覆盖 auth deny 和 authorize:fail
      if (err.errMsg && (err.errMsg.includes('auth deny') || err.errMsg.includes('authorize:fail'))) {
        // 引导用户去设置页开启权限
        uni.showModal({
          title: '权限提示',
          content: '保存图片需要您授权访问相册,请前往设置开启权限',
          success: (res) => {
            if (res.confirm) {
              uni.openSetting({
                success: (settingRes) => {
                  if (settingRes.authSetting['scope.writePhotosAlbum']) {
                     uni.showToast({ title: '授权成功,请重试', icon: 'none' });
                  }
                }
              });
            }
          }
        });
      } else {
        // 其他错误(如文件路径错误等)
        uni.showToast({ title: '保存失败,请重试', icon: 'none' });
      }
    }
  });
}

3. 避坑总结与 H5 兼容

核心避坑点

  1. 先打印 :遇到组件(Charts/Painter/QRCode)导出失败,先 console.log 看看路径是不是 data:image 开头。

  2. 转文件 :只要是 Base64,必须用 getFileSystemManager 转存成临时文件,不要试图直接传给保存接口。

H5 端的特殊处理

上述代码主要适用于 小程序App 端。 如果是 H5 端uni.saveImageToPhotosAlbum 是无效的(浏览器机制限制)。H5 端需要通过创建 <a> 标签模拟点击下载:

JavaScript

javascript 复制代码
// H5 专用保存逻辑
if (
// #ifdef H5
true
// #endif
) {
  const a = document.createElement('a');
  a.href = filePath; // 这里的 filePath 可以直接是 Base64
  a.download = 'qrcode.png';
  a.click();
  return;
}

结语:这套逻辑是处理 UniApp 图片保存的标准"满分"答案。如果你觉得有用,欢迎点赞收藏,下次遇到类似需求直接 Copy 代码!

相关推荐
烟囱土著11 小时前
如何让相册「动」起来❓看这里❗
微信·微信小程序·小程序
azhou的代码园18 小时前
基于SpringBoot与微信小程序的招聘管理系统的设计与实现
spring boot·微信小程序·毕业设计·求职招聘小程序
蓝帆傲亦20 小时前
Web前端Mock数据实战指南:正确使用Mock.js提升开发效率
微信小程序·小程序·uni-app
kyh100338112020 小时前
微信小游戏《找茬找汉字闯关王》开发实战:送全部源码
microsoft·微信·微信小程序·小程序·微信小游戏·汉字找茬找梗
汤姆yu1 天前
基于微信小程序的校园快递代取系统
微信小程序·小程序
albert-einstein1 天前
微信小程序反编译(不通过模拟器进行反编译)
微信小程序·小程序
毕设源码纪师姐2 天前
计算机毕设 java 基于微信小程序的社区物资订购系统 基于 SpringBoot 的微信小程序社区物资采购平台 Java 社区物资订购与配送管理系统
java·微信小程序·课程设计
qq_12498707532 天前
基于微信小程序的智慧社区娱乐服务管理平台(源码+论文+部署+安装)
人工智能·hadoop·信息可视化·微信小程序·小程序·毕业设计·娱乐
平淡风云2 天前
摸鱼时间工资计算器(微信小程序)
微信小程序·小程序