# 微信小程序云迁移uniCloud

# 概念澄清

uniCloud,可以自选阿里云和腾讯云的serverless。类似于uni-app屏蔽了各家小程序的端侧差异,uniCloud也屏蔽了微信小程序云开发和支付宝小程序云开发的差异。

也就是说,uniCloud选择腾讯云时,和微信小程序云开发,连的是一套云服务,都是腾讯云官方提供的。

虽然硬件相同,包括API也很相似,但uniCloud和微信云开发仍然有一些软件层面的差异。

uniCloud去掉了微信云开发的一些功能,添加了更多功能。以及在生态配套上差别也比较大。

# 优劣对比

微信云开发 uniCloud
跨端 只有微信小程序(虽可用其他工具变相开发H5、QQ小程序,但端不够全也难以保持一致性) 全端。App、web、各家小程序快应用全支持
跨云 只支持腾讯云。为其编写的云函数不能运行在其他云平台 阿里云、腾讯云均支持,方便互相切换。对其他云也持开放态度
定价 选用uniCloud腾讯云版与微信云开发价格相同。DCloud只是获取腾讯云的返点,而不是加价售卖。如选用uniCloud阿里云版,则比微信云开发更便宜详见
前端操作数据库 使用微信的账户权限而不是应用的账户权限,无法编程,不能有效控制数据权限安全。客户端js sdk体积大,影响性能 完善的clientDB模块,使用应用自己的用户权限体系,可灵活编程,安全可靠控制权限
数据库schema 不支持 完善的数据库schema设计,自带权限验证和数据合法性验证
数据库查询语法 MongoDB语法。学习门槛高、写法复杂,尤其联表查询很难用 除了MongoDB语法外,支持JQL语法,大幅降低学习门槛,减少数据库操作的代码量,快速完成复杂查询
开发工具 微信小程序工具,编码体验欠佳 通用编程工具HBuilderX,高效操作完善,插件体系开放
前端数据库watch 支持。权限按微信账户体系执行 有更强大的免费的websocket服务详情查看
opendb 开放的数据库规范,众多价值,详情
账户服务 仅微信登录,但鉴权更简单 uni-id支持应用自己的账户体系,手机号或email,内置短信验证码和app端一键登录,支持微信、支付宝等三方登录,支持权限、角色、社交裂变等众多功能
admin系统 不自带 自带开源uniCloud admin系统,大小屏自适配,自带用户、角色、权限功能,还有更多插件拿来即用
支付 仅微信支付,但鉴权更简单 uniPay,跨端统一支付
cms 支持。但前端部分跨端不足 支持。前端跨端、管理端开源
插件生态 腾讯云开发了部分插件 丰富的插件生态,包含腾讯云为uniCloud开发的插件,众多现成项目模块,详情

上述差异,总结来看,uniCloud更开放、生态更丰富、开发效率更高。

开发效率之所以高的原因,包括clientDB、JQL、HBuilderX这些对效率起很大影响的重要功能和工具,也包括大量现成的轮子拿来就用。详见:2021了,让我们把开发效率提升10倍吧!

# 技术迁移指南

如果已经开发了微信小程序,想迁移到uniCloud,下面提供云函数和数据库部分的技术迁移指南。

# 云函数迁移指南

# 对接微信登录

uniCloud可以使用uni-id更简单的接入微信小程序登录。参考uni-id

不同于微信云开发中的直接获取openid,uni-id提供的登录接口会在数据库的uni-id-users表内添加用户记录。

如果要控制云存储的权限可以使用自定义登录,uniCloud腾讯云自定义登录

# 对接微信支付

uniCloud提供了uniPay来实现支付功能,同时支持微信和支付宝unipay文档

老的微信云开发+原生小程序的代码是这样:

// 云函数部分的代码
const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})

exports.main = async (event, context) => {
  const res = await cloud.cloudPay.unifiedOrder({
    "body" : "商品描述",
    "outTradeNo" : "商户订单号",
    "spbillCreateIp" : "127.0.0.1",
    "totalFee" : 1,
	// 用于接收支付异步通知的云函数所在的服务空间ID和云函数名
    "envId": "test-f0b102",
    "functionName": "pay_cb"
  })
  return res
}

// 小程序部分的代码
wx.cloud.callFunction({
  name: '函数名',
  data: {
    // ...
  },
  success: res => {
    const payment = res.result.payment
    wx.requestPayment({
      ...payment,
      success (res) {
        console.log('pay success', res)
      },
      fail (res) {
        console.error('pay fail', err)
      }
    })
  },
  fail: console.error,
})

迁移到uniCloud + uni-app体系,代码改成这样:

// 云函数部分的代码
const unipayIns = unipay.initWeixin({
  appId: 'your appId',
  mchId: 'your mchId',
  key: 'you parterner key',
  // pfx: fs.readFileSync('/path/to/your/pfxfile'), // p12文件路径,使用微信退款时需要,需要注意的是务必使用绝对路径
})


exports.main = async (event, context) => {
	const res = await unipayIns.getOrderInfo({
		openid: 'user openid',
		body: '商品描述',
		outTradeNo: '商户订单号',
		totalFee: 1, // 金额,单位分
		notifyUrl: 'https://xxx.xx' // 支付结果通知地址
	})
  return res
}

// 客户端部分的代码
uniCloud.callFunction({
	name: '云函数名',
	data: {
		// ...
	},
	success(res) {
		uni.requestPayment({
			provider: 'wxpay',
			...res.result.orderInfo
			success (res) {
			  console.log('pay success', res)
			},
			fail (res) {
			  console.error('pay fail', err)
			}
		})
	}
})

注意

  • uniPay和微信小程序的CloudPay接口很相似,需要注意的是uniPay接收的参数都是驼峰形式的,输出的参数也都是驼峰形式的。微信小程序的CloudPay有些接口是驼峰形式参数有些是蛇形参数

# 临时CDN

临时CDN主要用于解决需要传输大文件到云函数的场景,使用uniCloud时可以通过先上传到云存储再传递fileID给云函数的方式实现

微信云开发写法:

wx.cloud.callFunction({
  name: 'test',
  data: {
    filePathDemo: wx.cloud.CDN({
      type: 'filePath',
      filePath: 'xxxxxxxx',
    })
  },
})

uniCloud写法:

uniCloud.uploadFile({
	filePath: filePath,
	cloudPath: 'a.jpg'
}).then(res => {
	const fileID = res.fileID
	uniCloud.callFunction({
		name: 'test',
		data: {
			filePathDemo: fileID
		}
	})
})

# 微信开放接口

使用微信开放接口的场景可以替换为mp-cloud-openapi来实现。用法基本和微信云开发一致

微信云开发写法:

const cloud = require('wx-server-sdk')
cloud.init()
exports.main = async (event, context) => {
  try {
    const result = await cloud.openapi.wxacode.createQRCode({
        path: 'page/index/index',
        width: 430
      })
    return result
  } catch (err) {
    return err
  }
}

uniCloud写法:

// mp-cloud-openapi,地址:https://ext.dcloud.net.cn/plugin?id=1810
const openapi = require('mp-cloud-openapi')
const openapiWeixin = openapi.initWeixin({
  appId: 'appId',
  secret: 'secret'
})
exports.main = async (event, context) => {
  try {
    const result = await openapiWeixin.wxacode.createQRCode({
        path: 'page/index/index',
        width: 430
      })
    return result
  } catch (err) {
    return err
  }
}

# 数据库迁移指南

# 数据导出导入

微信小程序云开发的控制台可以导出json数据,这个格式与uniCloud相同,可以将导出文件直接在uniCloud的web控制台操作导入。

# 新增与更新数据的写法

微信小程序云开发add、update、set操作时参数比uniCloud多了一层data 从微信小程序云开发迁移时最需要注意的事项

微信云开发写法:

const res = await db.collection('todos').doc('todo-id').add({
  data: {
    description: "learn cloud database",
    done: false
  }
})

uniCloud写法:

const res = await db.collection('todos').doc('todo-id').add({
  description: "learn cloud database",
  done: false
})

# 客户端操作数据库

uniCloud内也支持客户端操作数据库(下面成为clientDB),但是与微信云开发稍有不同。主要有以下两点

  • 权限依赖于uni-id
  • 需要在表结构的permission里面配置权限,可以配置字段级的权限

另外clientDB支持以下扩展能力

  • 数据校验能力,参考:DB schema
  • 在数据库操作前/后执行额外操作,参考:action
  • 更加简单的查询方式,参考:JQL