
在微信小程序(游戏)与 QQ 小程序(游戏)中使用 LeanCloud
在微信小程序(游戏)与 QQ 小程序(游戏)中使用 LeanCloud
小程序是一个全新的跨平台移动应用平台,小游戏是小程序的一个类目,在小程序的基础上开放了游戏相关的 API。LeanCloud 为小程序提供一站式后端云服务,为你免去服务器维护、证书配置等繁琐的工作,大幅降低你的开发和运维成本。本文说明了如何在小程序与小游戏中使用 LeanCloud 提供的各项服务。
Demo
我们在小程序上实现了 LeanTodo 应用。在这个 Demo 中你可以看到:
- 如何集成 LeanCloud 用户系统,包括自动登录、unionid 绑定以及如何在登录后设置账号与密码以供用户在其他平台的 LeanTodo 应用上登录
- 如何对云端数据进行查询、增加、修改与删除
- 如何将查询结果数组绑定到视图层进行展示,以及如何在点击事件中得到对应的数组项
- 如何使用 LiveQuery 实现对查询结果的实时更新和多端同步
- 如何集成微信支付(仅支持微信小程序)
你可以通过微信或 QQ 扫描以下二维码进入 Demo。 Demo 的源码与运行说明请参考 https://github.com/leancloud/leantodo-weapp。
准备工作
创建应用
- 如果你还没有创建过 LeanCloud 应用,请登录 LeanCloud 控制台创建一个新应用。
- 如果你还没有小程序帐号,请访问 微信公众平台 或 QQ 小程序开放平台 注册一个小程序帐号。如果你不需要进行真机调试可以跳过这一步。
- 下载对应平台的小程序开发工具,按照指引创建一个新项目。
配置域名白名单
如果你不需要进行真机调试可以暂时跳过这一步(可在开发者工具的 详情 > 项目设置 中勾选不校验安全域名、TLS 版本以及 HTTPS 证书)。
安装与初始化 SDK
要使用 LeanCloud 的结构化对象存储、文件存储、用户系统等功能,需要使用 LeanCloud 存储 SDK。存储 SDK 的安装与初始化请请参阅《JavaScript SDK 安装指南》中对应平台的说明。
app.js
// 获取 AV 命名空间的方式根据不同的安装方式而异,这里假设是通过手动导入文件的方式安装的 SDK
const AV = require('./libs/av-core-min.js');
const adapters = require('./libs/leancloud-adapters-weapp.js');
AV.setAdapters(adapters);
AV.init({
appId: '{{appid}}',
appKey: '{{appkey}}',
// 请将 xxx.example.com 替换为你的应用绑定的自定义 API 域名
serverURLs: "https://xxx.example.com",
});
要使用 LeanCloud 的即时通讯服务实现聊天等功能,需要使用 LeanCloud 即时通讯 SDK。即时通讯 SDK 是与存储 SDK 独立的 SDK,我们在单独的 即时通讯 章节介绍其安装与初始化的步骤。
结构化对象存储
所有的结构化对象存储 API 都能正常使用,详细的用法请参考 JavaScript 数据存储开发指南。
数据绑定
AV.ObjectdataAV.Objectdata
AV.QueryTodocontentdonegetDataForRender
const getDataForRender = todo => ({
content: todo.get('content'),
done: todo.get('done')
});
Page({
data: {
todos: []
},
onReady() {
new AV.Query('Todo')
.find()
.then(todos => this.setData({
todos: todos.map(getDataForRender)
}))
.catch(console.error);
}
});
AV.Object#toJSON()getDataForRender
const getDataForRender = todo => todo.toJSON();
setDataAV.ObjectsetDatajsonify
const isPlainObject = target =>
target &&
target.toString() == '[object Object]' &&
Object.getPrototypeOf(target) == Object.prototype;
const _jsonify = target => {
if (target && typeof target.toJSON === 'function') return target.toJSON();
if (Array.isArray(target)) return target.map(_jsonify);
return target;
};
const jsonify = target =>
isPlainObject(target)
? Object.keys(target).reduce(
(result, key) => ({
...result,
[key]: _jsonify(target[key])
}),
{}
)
: _jsonify(target);
jsonifyAV.ObjectAV.ObjectsetDatajsonify
this.setData(jsonify({
todos, // AV.Object list
user, // AV.Object
}));
AV.ObjectAV.Object
Page({
// todos 存放的是 AV.Object 列表,后续可以这些对象进行操作(比如调用其 save 方法),不参与渲染
todos: [],
data: {
// data.todo 存放的是 JSON 数据,供 WXML 页面渲染用
todos: []
},
onReady() {
new AV.Query('Todo')
.find()
.then(todos => {
this.todos = todos;
this.setData(jsonify({
todos
});
})
.catch(console.error);
},
saveAll() {
// 可以在这里获取到 this.todos 进行操作
return AV.Object.saveAll(this.todos)
}
});
文件存储
wx.chooseImageAV.File
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: function(res) {
var tempFilePath = res.tempFilePaths[0];
// 使用本地临时文件的路径构造 AV.File
new AV.File('file-name', {
blob: {
uri: tempFilePath,
},
})
// 上传
.save()
// 上传成功
.then(file => console.log(file.url()))
// 上传发生异常
.catch(console.error);
}
});
file.url()
关于文件存储更详细的用法请参考 JavaScript 数据存储开发指南 · 文件。
用户系统
小程序中提供了登录 API 来获取微信的用户登录状态,应用可以访问到用户的昵称、性别等基本信息。但是如果想要保存额外的用户信息,如用户的手机号码、收货地址等,或者需要在其他平台使用该用户登录,则需要使用 LeanCloud 的用户系统。
SDK 提供了一系列小程序特有的用户相关的 API,适用于不同的使用场景:
AV.User.loginWithMiniAppAV.User#loginWithMiniAppAV.User#associateWithMiniApp
AuthInfoAuthInfogetAuthInfoAuthInfogetAuthInfo
下面我们以微信平台为例讨论不同场景下的使用方式。
一键登录
LeanCloud 的用户系统支持一键使用微信用户身份登录。要使用一键登录功能,需要先设置小程序的 AppID 与 AppSecret:
- 登录 微信公众平台,在 设置 > 开发设置 中获得 AppID 与 AppSecret。
- 前往 LeanCloud 控制台 > 内建账户 > 设置 > 第三方集成,启用「微信小程序」后填写 AppID 与 AppSecret。
AV.User.loginWithMiniApp()
AV.User.loginWithMiniApp().then(user => {
this.globalData.user = user;
}).catch(console.error);
openidsession_keyuser.authData.lc_weapp_User
{
"authData": {
"lc_weapp": {
"session_key": "2zIDoEEUhkb0B5pUTzsLVg==",
"expires_in": 7200,
"openid": "obznq0GuHPxdRYaaDkPOHk785DuA"
}
}
}
_Useropenid
AV.User.current()
// 假设已经通过 AV.User.loginWithMiniApp() 登录
// 获得当前登录用户
const user = AV.User.current();
// 调用小程序 API,得到用户信息
wx.getUserInfo({
success: ({userInfo}) => {
// 更新当前用户的信息
user.set(userInfo).save().then(user => {
// 成功,此时可在控制台中看到更新后的用户信息
this.globalData.user = user;
}).catch(console.error);
}
});
authDataopenidsession_key
使用 unionid
微信开放平台使用 unionid 来区分用户的唯一性,也就是说同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的 unionid 都是同一个,而 openid 会是多个。如果你想要实现多个小程序之间,或者小程序与使用微信开放平台登录的应用之间共享用户系统的话,则需要使用 unionid 登录。
在小程序中有很多途径可以 获取到 unionid。不同的 unionid 获取方式,接入 LeanCloud 用户系统的方式也有所不同。
一键登录时静默获取 unionid
AuthInfopreferUnionId
adapters.getAuthInfo({
preferUnionId: true,
}).then(authInfo => {
return AV.User.loginWithMiniApp(authInfo);
});
_weixin_unionidlc_weapp
{
"authData": {
"lc_weapp": {
"session_key": "2zIDoEEUhkb0B5pUTzsLVg==",
"expires_in": 7200,
"openid": "obznq0GuHPxdRYaaDkPOHk785DuA",
"unionid": "ox7NLs5BlEqPS4glxqhn5kkO0UUo"
},
"_weixin_unionid": {
"uid": "ox7NLs5BlEqPS4glxqhn5kkO0UUo"
}
}
}
用 unionid + openid 登录时,会按照下面的步骤进行用户匹配:
authData._weixin_unionid.uidopenidsession_keyunionidauthData.lc_weappauthData.lc_weapp.openidsession_keyunionidauthData.lc_weappunionidauthData._weixin_unionid.uidsession_keyunionidauthData.lc_weappunionidauthData._weixin_unionid.uid
authData
authData
需要注意的是:
{
"authData": {
"lc_weapp": {
"session_key": "2zIDoEEUhkb0B5pUTzsLVg==",
"expires_in": 7200,
"openid": "obznq0GuHPxdRYaaDkPOHk785DuA",
"unionid": "ox7NLs5BlEqPS4glxqhn5kkO0UUo"
}
}
}
通过其他方式获取 unionid 后登录
AV.User.mergeUnionId()AuthInfo
adapters.getAuthInfo().then(authInfo => {
authInfo = AV.User.mergeUnionId(authInfo, unionid, {
asMainAccount: true
});
return AV.User.loginWithMiniApp(authInfo);
});
通过其他方式获取 unionid 与 openid 后登录
lc_weapp
const unionid = '';
const authData = {
openid: '',
session_key: ''
};
const platform = 'lc_weapp';
AV.User.loginWithAuthDataAndUnionId(authData, platform, unionid, {
asMainAccount: true
}).then(console.log, console.error);
相对上面提到的一些 Weapp 相关的登录 API,loginWithAuthDataAndUnionId 是更加底层的第三方登录接口,不依赖小程序运行环境,因此这种方式也提供了更高的灵活度:
AV.User.loginWithAuthDataAndUnionIdAV.User.loginWithAuthDataAndUnionIdsessionTokensessionToken
关联第二个小程序
这种用法的另一种常见场景是关联同一个开发者帐号下的第二个小程序。
lc_weappauthData.lc_weappAV.User.loginWithAuthDataAndUnionIdlc_weapp
platformopeniduidopeniduid
weapp2
const unionid = '';
const openid = '';
const authData = {
uid: openid,
session_key: ''
};
const platform = 'weapp2';
AV.User.loginWithAuthDataAndUnionId(authData, platform, unionid, {
asMainAccount: true
}).then(console.log, console.error);
获取 unionid 后与现有用户关联
AV.User#associateWithWeappWithUnionId()
const user = AV.User.current(); // 获取当前登录用户
adapters.getAuthInfo().then(authInfo => {
authInfo = AV.User.mergeUnionId(authInfo, unionid, {
asMainAccount: true
});
return user.associateWithMiniApp(authInfo);
});
启用其他登录方式
上述的登录 API 对接的是小程序的用户系统,所以使用这些 API 创建的用户无法直接在小程序之外的平台上登录。如果需要使用 LeanCloud 用户系统提供的其他登录方式,如用手机号验证码登录、邮箱密码登录等,在小程序登录后设置对应的用户属性即可:
// 小程序登录
AV.User.loginWithMiniApp().then(user => {
// 设置并保存手机号
user.setMobilePhoneNumber('13000000000');
return user.save();
}).then(user => {
// 发送验证短信
return AV.User.requestMobilePhoneVerify(user.getMobilePhoneNumber());
}).then({
// 用户填写收到短信验证码后再调用 AV.User.verifyMobilePhone(code) 完成手机号的绑定
// 成功后用户的 mobilePhoneVerified 字段会被置为 true
// 此后用户便可以使用手机号加动态验证码登录了
}).catch(console.error);
绑定现有用户
AV.User#associateWithMiniApp()
// 首先,使用用户名与密码登录一个已经存在的用户
AV.User.logIn('username', 'password').then(user => {
// 将当前的微信用户与当前登录用户关联
return user.associateWithMiniApp();
}).catch(console.error);
即时通讯
要使用 LeanCloud 的即时通讯服务实现聊天等功能,需要使用 LeanCloud 即时通讯 SDK。
安装与初始化
请参阅《JavaScript SDK 安装指南》中对应平台的说明。
app.js
// Realtime 类获取的方式根据不同的安装方式而异,这里假设是通过手动导入文件的方式安装的 SDK
const { Realtime, setAdapters } = require('./libs/im.min.js');
const adapters = require('./libs/leancloud-adapters-weapp.js');
setAdapters(adapters);
const realtime = new Realtime({
appId: '{{appid}}',
appKey: '{{appkey}}',
// 请将 xxx.example.com 替换为你的应用绑定的自定义 API 域名
server: "https://xxx.example.com",
});
RealtimeRealtime
// app.js
const { Realtime, setAdapters } = require('./libs/im.min.js');
const adapters = require('./libs/leancloud-adapters-weapp.js');
setAdapters(adapters);
const realtime = new Realtime({
appId: '{{appid}}',
appKey: '{{appkey}}',
// 请将 xxx.example.com 替换为你的应用绑定的自定义 API 域名
server: "https://xxx.example.com",
});
App({
realtime: realtime,
// ...
});
// some-page.js
const realtime = getApp().realtime;
即时通讯 SDK 的详细用法请参考 即时通讯开发指南。
富媒体消息
要在小程序中使用即时通讯 SDK 的富媒体消息插件,有一些额外的约束:
const AV = require('./libs/leancloud-storage.js');
const IM = require('./libs/leancloud-realtime.js');
const initPlugin = require('./libs/leancloud-realtime-plugin-typed-messages.js');
const { Realtime, setAdapters } = IM;
const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM);
AV.setAdapters(adapters);
setAdapters(adapters);
// 初始化存储 SDK
AV.init({
appId: '{{appid}}',
appKey: '{{appkey}}',
serverURLs: "https://xxx.example.com",
});
// 初始化即时通讯 SDK
const realtime = new Realtime({
appId: '{{appid}}',
appKey: '{{appkey}}',
plugins: [TypedMessagesPlugin], // 注册富媒体消息插件
server: "https://xxx.example.com",
});
// 请将 xxx.example.com 替换为你的应用绑定的自定义 API 域名
数据绑定
ConversationMessageConversationMessage#toJSONjsonifyConversationMessage
支付
配置
在开始之前,请确保已经在微信小程序后台开启了「微信支付」功能,然后按照下面的步骤配置云引擎环境变量:
WEIXIN_APPIDWEIXIN_MCHIDWEIXIN_PAY_SECRETWEIXIN_NOTIFY_URLhttps://your-domain/weixin/pay-callbackyour-domain
查看示例
服务端开发
首先确认本机已经安装 Node.js 运行环境和 LeanCloud 命令行工具,然后执行下列指令下载示例项目:
$ git clone https://github.com/leancloud/weapp-pay-getting-started.git
$ cd weapp-pay-getting-started
安装依赖:
npm install
登录并关联应用:
lean login
lean switch
启动项目:
lean up
之后你就可以在 localhost:3001 调试云函数了。
示例项目中与支付直接相关代码有三部分:
order.jsplacecloud.jsorderopenidrouters/weixin.jspay-callbackSUCCESS
请根据你的业务需要修改代码。参考文档:
完成开发后部署到预备环境(若无预备环境则直接部署到生产环境):
lean deploy
客户端开发
客户端完成一次支付需要分两步:
orderwx.requestPayment
AV.Cloud.run('order').then((data) => {
data.success = () => {
// 支付成功
});
data.fail = ({ errMsg }) => {
// 错误处理
});
wx.requestPayment(data);
}).catch(error => {
// 错误处理
})
客户端的示例代码参见 Demo 打赏功能。参考文档:
FAQ
配置 download 合法域名时显示「该域名因违规被禁止设置。」
请前往 控制台 > 数据存储 > 文件 > 设置 配置你自己的文件域名。
Access denied by api domain white list
Access denied by api domain white list
小程序真机上传数据时,控制台存储中显示的 Class 表名被压缩为单个字母。
AV.Object.register(Todo, 'Todo');
反馈
如果在微信 / QQ 小程序中使用 LeanCloud 时遇到问题,欢迎通过我们的 论坛 进行反馈。


