需求背景

微信小程序只提供分享到微信好友的接口,但是没有分享到朋友圈的接口。产品希望能生成一张带有小程序二维码的海报,让用户保存至本地,然后发往朋友圈,来实现分享到朋友圈的操作。

整理需求

  • 准备一张海报
  • 准备一张动态的小程序码,码上携带分享者信息
  • 使用canvas把海报和小程序码拼成一张图片
  • 保存canvas拼成的图片到本地

准备一张海报

海报图片需要先用过getImageInfo方法获取对应的filepath,才可以使用drawImage绘制。
注意:网络图片需先配置download域名才能生效,或者直接使用云存储,可以省略配置download域名这一步。

getImageInfo(src) {
  return new Promise((resolve, reject) => {
    wx.getImageInfo({
      src,
      success(res) {
        resolve(res)
      },
      fail(err) {
        reject(err)
      },
    })
  })
}

准备一张动态的小程序二维码,码上携带分享者信息

小程序码有两个接口可以生成:get、getUnlimited。
get、getUnlimited差别主要是入参和生成数量,入参差别不是最重要的,我们的活动参加人数无法预估,所以一定要采用没有数量限制的getUnlimited接口。

getUnlimited接口调用方式有两种:HTTPS调用、云调用。
这个项目使用云调用(需要开通云开发服务)。

在cloudfunctions中先写一个生成小程序码的云函数工具,命名为miniprogramCode。

// miniprogramCode
const cloud = require('wx-server-sdk')
cloud.init()
exports.main = async (event, context) => {
  try {
    const page = event.page
    const scene = `userid=${event.userid}`
    const result = await cloud.openapi.wxacode.getUnlimited({ scene, page })
    return result
  } catch (err) {
    return err
  }
}

因为需要加载wx-server-sdk,所以需要安装一下依赖

npm install --save wx-server-sdk@latest

在miniprogram中写一个调用miniprogramCode工具的方法getMiniprogramCode备用

getMiniprogramCode () {
  wx.cloud.init()
  const userid = '用户的userid'
  const page = 'pages/index/index'
  return wx.cloud.callFunction({
    name: 'qrcode',
    data: { userid, page }
  })
}

tips:miniprogramCode返回的小程序码的数据类型是Buffer类型,所以我们把他转化成本地路径才可以使用drawImage绘制。
先说说这个地方的知识点,平时用的不是很多。

  • 本地用户文件是从 1.7.0 版本开始新增的概念。我们提供了一个用户文件目录给开发者,开发者对这个目录有完全自由的读写权限。通过 wx.env.USER_DATA_PATH 可以获取到这个目录的路径。
  • wx.getFileSystemManager() 获取全局唯一的文件管理器
  • FileSystemManager.writeFile(Object object) 写文件
getMiniprogramCodePath (buffer) {
  const filePath = `${wx.env.USER_DATA_PATH}/miniprogram_code.jpeg`
  const fs = wx.getFileSystemManager()
  fs.writeFileSync(filePath, buffer, 'binary')
  return filePath
}

使用canvas把海报和小程序码拼成一张图片

使用canvas,需要现在wxml文件中码好一个canvas组件

<canvas style="width: 250px; height: 406px" canvas-id="posterCanvas" />

data中数据准备好

data: {
  posterImage: 'https://6465-dev-ecej-1300456941.tcb.qcloud.la/test.jpg',
}

然后开始画图

createCanvas () {
  Promise.all([this.getImageInfo(this.data.posterImage), this.getMiniprogramCode()]).then(res => {
    const imagePath = res[0].path
    const miniprogramCode = res[1].result.buffer
    const context = wx.createCanvasContext('posterCanvas')
    context.drawImage(imagePath, 0, 0, 250, 406)
    context.drawImage(this.getMiniprogramCodePath(miniprogramCode), 85, 300, 80, 80)
    context.draw()
  })
}

到这里,绘图工作就告一段落了。剩下的就是宝保存到本地。

保存canvas拼成的图片到本地

tips:以为保存很简单,并没有,细节多的很~~

  1. 通过wx.getSetting检测用户是否做过保存到相册的授权
  2. 如果没有,使用wx.authorize授权保存到相册
  3. canvas绘制得图片缓存到本地生成filepath
  4. 授权成功后,使用wx.saveImageToPhotosAlbum保存图片到系统相册就可以了

通过wx.getSetting检测用户是否做过保存到相册的授权

isWritePhotosAlbum() {
  return new Promise((resolve, reject) => {
    wx.getSetting({
      success: res => {
        resolve(res.authSetting['scope.writePhotosAlbum'])
      },
      fail: res => {
        reject()
      }
    })
  })
}

如果没有,使用wx.authorize授权保存到相册

authWritePhotosAlbum () {
  return new Promise((resolve, reject) => {
    wx.authorize({
      scope: 'scope.writePhotosAlbum',
      success() {
        resolve()
      },
      fail(err) {
        reject(err)
      }
    })
  })
}

canvas绘制得图片缓存到本地生成filepath

canvasToTempFilePath() {
  return new Promise((resolve, reject) => {
    wx.canvasToTempFilePath({
      x: 0,
      y: 0,
      width: 250,
      height: 406,
      canvasId: 'posterCanvas',
      fileType: 'jpg',
      quality: 1,
      success: res => {
        resolve(res.tempFilePath)
      },
      fail: err => {
        reject(err)
      }
    })
  })
}

授权成功后,使用wx.saveImageToPhotosAlbum保存图片到系统相册就可以了

saveImageToPhotosAlbum (path) {
  return new Promise((resolve, reject) => {
    wx.saveImageToPhotosAlbum({
      filePath: path,
      success: res => {
        resolve()
      },
      fail: err => {
        reject()
      }
    })
  })
}

最后把保存canvas拼成的图片到本地的流程串起来

async saveImage () {
  try {
    const isWritePhotosAlbum = await this.isWritePhotosAlbum()
    if (!isWritePhotosAlbum) {
      await this.authWritePhotosAlbum()
    }
    const filepath = await this.canvasToTempFilePath()
    await this.saveImageToPhotosAlbum(filepath)
    wx.showToast({
      title: '保存成功',
    })
  } catch {
    wx.showToast({
      title: '保存失败',
    })
  }
}

END

朋友圈,走起。


李小凡Amy
1 声望0 粉丝