提前说下:
写这两篇笔记,纯看文档,没有实践、测试代码,是否正确,错误的地方可能会很多!只是帮我梳理了下小程序文档。
笔记个别重点:
1.自定义组件
Component 构造器,该页面的 Component() 方法的参数并不全,需要看的是:
框架 -> 框架接口 -> 自定义组件 -> Component
2.多线程
1>app.json 中配置 'Worker' 代码放置的目录
{
"workers": "workers"
}
2>在上面定义的目录下,我们就可以创建我们想要的 worker 线程文件(任意创建,也可以创建其他文件,例如:utils.js)
workers/index.js
workers/utils.js
workers/request/index.js
workers/response/index.js
...
3>编写 worker 线程文件,例如:workers/request/index.js
const utils = require('../utils.js')
// worker 线程文件,会自动暴露一个 'worker' 对象,我们直接使用即可
// (worker 线程文件有一个 worker 对象,我们直接使用)
// 1.接收消息(接收主线程的消息)
worker.onMessage(function(res){
console.log(res)
})
// 2.发送消息(给主线程发送消息)
worker.postMessage({
msg: '你好,主线程'
})
4>在主线程,初始化我们定义好的 worker 线程(主线程就是目前的微信小程序线程,可以理解为在 app.js 文件中)
// 参数为:我们定义的 worker 线程文件(绝对路径)
const worker = wx.createWorker('workers/request/index.js')
// 1.主线程向 worker 线程发送消息
worker.postMessage({
msg: '你好,worker 线程'
})
// 2.主线程接收 worker 线程的消息
worker.onMessage(function(res){
console.log(res);
})
// 3.worker 线程的最大并发数量为 1,所以,要切换其他 worker 线程,需要结束之前创建的 worker 线程
// (只有主线程可以调用)
worker.terminate()
5>注意点:
1.worker 线程最大并发数量为 1,创建另外线程,需结束之前的线程
2.worker 文件中,只能 require 我们定义的 worker 目录下的文件
3.worker 内不支持 wx 系列的 API
3.服务端能力
1>服务端 API
2>消息推送
类似我们之前开发的微信公众号的消息系统(消息和事件)
4.自定义 tabBar
如果我们不想要小程序默认的 'tabBar',我们可以使用 '自定义 tabBar' 来接管。所有 tabBar 的页面,只能使用同一个 '自定义 tabBar'。(这个也是正确的)
对于我们可能希望,不同的大的模块内部,也有自己的 '底部导航',我们可以当做页面的底部(这种并非是 'tabBar',不过非常类似),就是正常的页面结构就可以了,只不过模拟成 tabBar 的感觉。
'自定义 tabBar' 需要配置:
1>app.json 中指定 『"custom": true』,表示使用 '自定义 tabBar'
2>其余的 tabBar 配置项,依旧得完整填写,为了兼容旧版。
3>所有的 tab 页,还需配置『"usingComponents": {}』,简单的写法是,直接在 app.json 中配置 『"usingComponents": {}』(不过不推荐,不清晰)
5.优化
1>setData 原理
WebView(视图层) 和 JavascriptCore(逻辑层),都是独立的模块,不具备数据直接共享的通道,两边是通过 evaluateJavascript 实现。
evaluateJavascript 实现是:将用户传输的数据,转为 '字符串' 进行传递,传递完成后,再拼接成 'js 脚本',然后执行 'js 脚本' 来达到数据传递。
所以 setData 不能过于频繁、不能单次传递大量数据,同时,页面进入后台,不可进行 setData。
2>图片资源
大图片和长列表图片(很长的列表页,列表中的每项,都带有图片),对内存和页面切换,都有很大影响
https://sevencai.github.io/2018/03/22/%E9%95%BF%E5%88%97%E8%A1%A8%E5%9B%BE%E7%89%87%E4%BC%98%E5%8C%96%E6%96%B9%E5%BC%8F/
再次链接到了 '张鑫旭' 博客了,好久没看他的文章了...
https://www.zhangxinxu.com/php/myRecomm
'掘金' 看来也不错,有时间看看
https://juejin.im/
3>代码包大小
1.尽量不包含图片,放到 CDN
2.及时清理不用的代码,类库引用等都得注意
6.调试
1>vConsole
2>Source Map(方便排错,同时只作用域 '开发版',无需担心 '线上版')
在开发者工具中开启 ES6 转 ES5、代码压缩时,会生成 Source Map 的 .map 文件。开发版小程序中,基础库会使用代码包中的 .map 文件,对 vConsole 中展示的错误信息堆栈进行重新映射
7.低版本兼容
1>版本号比较
1.微信客户端和小程序基础库的版本号风格为:Major.Minor.Patch(主版本号.次版本号.修订版本号)
2.组件、API等,都有要求的 '最低基础库版本号',判断当前版本号是否达到要求,达不到需进行处理,是否升级等
3.通过 wx.getSystemInfo 或 wx.getSystemInfoSync 的 SDKVersion 来获取当前小程序运行的基础库的版本号
4.版本号比较,不要直接使用 '字符串比较'。官方给我们提供了一个 compareVersion() 函数,看文档
2>API 存在判断
对于新增的 API,可以判断 API 是否存在,来进行兼容处理
if(wx.openBluetoothAdapter){
//存在
}else{
// 不存在
}
3>wx.canIUse
通过 wx.canIUse,可以判断以下内容,是否可以在当前版本的基础库使用
1.API 参数或返回值的参数
wx.showModal({
success(res){
if(wx.canIUse('showDodal.cancel')){
// 可以使用
}
}
})
2.组件或组件的属性
wx.canIUse('cover-view')
4>小程序后台,可以设置 '基础库最低版本',强制用户来升级 '微信客户端'
8.转发
1>2种方式:
1.右上角转发菜单
2.页面内转发按钮
<button open-type="share"></button>
2>必须设置页面的 Page.onShareAppMessage() 事件,它监听用户转发的行为,并自定义转发内容
onShareAppMessage(res){
// res.from - 转发事件来源(button - 页面内转发按钮 | menu - 右上角转发菜单)
// res.target - from 的值是 button,target 为转发按钮 <button> | from 的值为 menu,target 为 null
// res.webViewUrl - 页面中包含 <web-view> 组件时,返回当前 <web-view> 的 url
return {
title: '转发标题,默认值:当前小程序名称',
path: '转发路径,默认值:当前页面 path,必须是以 "/" 开头的完整路径',
imageUrl: '自定义图片路径,默认值:当前页面的截图'
}
}
3>API -> 转发
wx.showShareMenu - 显示当前页面的转发按钮
wx.showShareMenu({
withShareTicket: true // 是否使用带 ShareTicket 的转发详情
})
wx.hideShareMenu - 隐藏转发按钮
wx.getShareInfo - 获取转发详细信息(目前应该只是为了获取,转发的群ID - openGid)
wx.getShareInfo({
shareTicket: 'xxx',
success: function(res){
// res.errMsg
// res.encryptedData, // 完整转发数据,openGid
// res.iv
}
})
wx.updateShareMenu - (貌似和 '动态消息' 有关)
4>组件 -> 开放能力 -> open_data
通过 openGid,可以获取 '群名'
<open-data type="groupName" open-gid="xxxxxx"></open-data>
5>转发的流程,以及 API 的使用,应该是这样,猜测
// 1.显示页面的转发按钮,主要是 '使用带 ShareTicket 的转发详情'(不知道会不会将按钮的转发,也支持 ShareTicket)
wx.showShareMenu({
withShareTicket: true
})
// 2.设置 Page.onShareAppMessage(),自定义转发内容
Page({
onShareAppMessage(res){
return {
title: '转发标题,默认值:当前小程序名称',
path: '转发路径,默认值:当前页面 path,必须是以 "/" 开头的完整路径',
imageUrl: '自定义图片路径,默认值:当前页面的截图'
}
}
});
// 3.其他用户通过转发,打开小程序,在 App.onLaunch 或 App.onShow 可以获取到 ShareTicket,然后调用 wx.getShareInfo() 得到 openGid
App({
onLaunch(){
// options.shareTicket
if(options.shareTicket){
wx.getShareInfo({
shareTicket: 'xxx',
success: function(res){
// res.errMsg
// res.encryptedData, // 完整转发数据,openGid
// res.iv
}
})
}
}
})
6>动态消息
动态消息的特点:
1.消息发送出去,可以修改部分消息内容
2.消息有对应的提醒按钮,用户点击...
使用方法:
1.创建 activity_id
服务端 -> 动态消息 -> createActivityId
GET https://api.weixin.qq.com/cgi-bin/message/wxopen/activityid/create?access_token=ACCESS_TOKEN
得到 activity_id
2.转发之前,声明动态消息
API -> 转发
wx.updateShareMenu({
withShareTicket: true, // 是否使用带 ShareTicket 的转发详情(默认值为 false)
isUpdatableMessage: true, // 是否是动态消息(默认值为 false)
activityId: '', // 动态消息 ID
templateInfo: { // 动态消息的模板信息(目前只参数列表)
parameterList: [{
name: 'member_count',
value: '1'
}, {
name: 'room_limit',
value: '3'
}]
}
})
templateInfo
parameterList
{
name: '',
value: ''
}
状态:
0 - 应该是未开始,文字内容:"成员正在加入,当前 {member_count}/{room_limit} 人"
1 - 已开始,文字内容:"已开始"
状态参数(上面参数列表中的 name 的类型):
member_count - 状态 0 有效,模板中的 member_count 的值
room_limit - 状态 0 有效,模板中的 room_limit 的值
path - 状态 1 有效,点击 '进入' 启动小程序时使用的 '路径'
version_type - 状态 1 有效,点击 '进入' 启动小程序时使用的 '版本':develop、trial、release
3.转发动态消息后,可以修改消息内容
服务端 -> 动态消息 -> setUpdatableMsg
POST https://api.weixin.qq.com/cgi-bin/message/wxopen/updatablemsg/send?access_token=ACCESS_TOKEN
9.模板消息
同 '微信公众号' 的模板消息很类似,简单总结下异同点:
相同点:
都是从模板库中,选择自己的模板,没有则新添加,然后审核、通过
通过接口或直接在管理面板来管理 '我的模板'
不同点:
1>推送位置
公众号:是在公众号内
小程序:所有小程序的模板消息,都在微信消息的 '服务通知'
2>下发条件
公众号:可以随意发送
小程序:只有 2 种情况:1.支付 2.提交表单
1.支付完成,会有 'prepay_id'(一次支付,最多可发送 3 条模板消息)
2.提交表单(一次提交,只能发送 1 条模板消息)
页面的 <form> 组件,report-submit 为 true 时,表示需要发送模板消息,提交表单可以获取 formId
3>发送数量
公众号:一次操作,可以发多条
小程序:一次支付,最多可发送 3 条模板消息;一次提交,只能发送 1 条模板消息
4>模板跳转能力
公众号:任意链接,可以外链
小程序:只能本小程序内的各个页面
发送步骤:
1.选择模板
2.得到相关的下发参数
支付 - prepay_id
提交表单 - formId
3.调用 templateMessage.send 接口
10.统一服务消息
服务端 -> 统一服务消息 -> uniformMessage.send
一个接口,同时发送 '公众号模板消息' 和 '小程序模板消息',跟单独发,没啥区别,得分别定义各自的模板消息数据
11.客服消息
所有小程序的 '客服消息' 都展示在微信消息的 '小程序客服消息'
'客服消息' 就是小程序的消息系统。
指南 -> 服务端能力 -> 消息推送(需要我们在后台配置消息推送地址)
1>用户进入客服消息
1.在页面中,点击 '客服会话按钮' 进入
<button open-type="contact" bindcontact="handleContact"></button>
open-type 为 contact,可用的属性有:
session-from - 会话来源(用户进入客服会话,发送的 '事件消息' 的 SessionFrom 参数)
send-message-title - 会话内消息卡片标题(默认:当前标题)
send-message-path - 会话内消息卡片点击跳转小程序路径(默认:当前分享路径)
send-message-img - 会话内消息卡片图片(默认:当前页面截图)
show-message-card - 是否显示会话内消息卡片,设置为 true,用户进入客服会话会在右下角显示 '可能要发送的小程序' 提示,用户点击后,可以快速发送小程序消息(默认:false)
bindcontact - 客服消息回调
如果用户在会话中点击了小程序消息,则会返回到小程序,我们可以通过 bindcontact 事件回调,获取用户所点消息的页面路径 path 和对应的参数 query
/*
这里提到了:用户在会话中,点击了 '小程序消息'。
小程序消息来源:
1>我们后台可以给用户,发送 '小程序类型的消息'
2>上面的几个 '*-message-*' 属性,其实就定义了 '小程序消息',而不需要后台发送(相当于前台发送了)
*/
page({
handleContact(e){
// e.path
// e.query
}
})
2.在微信的 '小程序客服消息' 列表中,进入指定的 '小程序' 的客服消息
2>用户主动发送消息
1.文本消息
MsgType - text
Content - 文本内容
2.图片消息
MsgType - image
PicUrl - 图片链接(由系统生成)
MediaId - 图片消息媒体id,可以调用 getTempMedia 接口来获取图片内容
3.小程序卡片消息
MsgType - miniprogrampage
Title - 标题
AppId - 小程序 appid
PagePath - 小程序页面路径
ThumbUrl - 封面图片的临时 cdn 链接
ThumbMediaId - 封面图片的临时素材 id(应该跟 image 消息的 MediaId 一样,可以通过接口获取图片内容)
3>用户触发事件消息
1.用户在页面中,点击 '客服会话按钮' 进入客服会话,触发事件
MsgType - event
Event - user_enter_tempsession
SessionFrom - sessionFrom(开发者在客服会话按钮设置的 session-from 属性)
4>服务器给用户发送消息
不能主动给用户发送客服消息,只有当用户和小程序客服产生特定动作交互时,开发者才可给用户发送消息。
目前允许的动作有:
用户发送消息 - 允许服务器向用户 | 下发条数限制 - 5 | 下发时限 - 48小时
1.文本消息
msgtype - text
text: {
content - 文本内容
}
// 发送文本消息,支持添加可跳转小程序的文字链接(在网上搜了下,没人知道怎么实现...)
/*
点击下方,跳转到我的小程序(这里是我们的文本内容)
<a
href="http://www.qq.com"
data-miniprogram-appid="appid"
data-miniprogram-path="pages/index/index"
>
点击跳小程序
</a>
*/
2.图片消息
msgtype - image
image: {
media_id - 图片媒体id,通过 '新增素材接口' 上传图片文件获得
}
3.图文链接
msgtype - link
link: {
title - 消息标题
description - 描述
url - 消息被点击后跳转的链接
thumb_url - 图片链接,支持 jpg、png,较好的效果为,大图 - 640x320 | 小图 - 80x80
}
4.小程序卡片
msgtype - miniprogrampage
miniprogrampage: {
title - 消息标题
pagepath - 小程序的页面路径,跟 app.json 对齐,支持参数,例如:pages/index/index?foo=bar
thumb_media_id - 小程序消息卡片的封面,image 类型的 media_id,由 '新增素材接口' 上传图片文件获得,建议大小为:520x416
}
5>转发客服消息
不太懂...
6>下发客服输入状态
就是在客服消息页面中,给用户展示 '正在输入'
服务端 -> 客服消息 -> customerServiceMessage.setTyping
参数:
access_token
touser - 用户的 openId
command - 命令
Typing - 对用户下发 '正在输入' 状态
CancelTyping - 取消对用户的 '正在输入' 状态
7>临时素材
开发者可在接收和发送客服消息的过程中,获取或上传临时素材
1.获取客服消息内的临时素材(下载临时的多媒体文件)
服务端 -> 客服消息 -> customerServiceMessage.getTempMedia
参数:
access_token
media_id - 媒体文件 id
2.上传媒体文件(用于发送客服消息,或被动恢复用户消息)
服务端 -> 客服消息 -> customerServiceMessage.uploadTempMedia
参数:
access_token
type - 文件类型(目前只有 image)
media - FormData,form-data 中媒体文件标识,有 filename、filelength、content-type 等信息
12.生成小程序码
1>小程序码的优势:
1.具有更好的辨识度,美观
2.拥有展示 '公众号关注组件' 等高级能力
组件 -> 开放能力 -> official-account
当用户扫 '小程序码' 打开小程序时,开发者可在小程序内配置 '公众号关注组件',方便用户快捷关注公众号。
几点注意事项:
1.设置的公众号需要和小程序在同一个主体下
2.组件限定最小宽度为 300px,高度为 84px
3.每个页面只能配置一个该组件(类似页面上的一个 view 结构)
<official-account></official-account>
属性:
bindload - 组件加载成功时触发
binderror - 组件加载失败时触发
2>生成 '小程序码' 接口
1.适用于需要的码数量较少的业务场景。永久有效,和 wxacode.createQRCode 生成的二维码总数限制 100000 个
服务端 -> 小程序码 -> wxacode.get
参数:
access_token
page -
width -
auto_color -
line_color -
is_hyaline -
2.适用于需要的码数量极多的业务场景。永久有效,数量暂无限制
服务端 -> 小程序码 -> wxacode.getUnlimited
参数:
access_token
scene -
page -
width -
auto_color -
line_color -
is_hyaline -
3>生成 '小程序' 的 '二维码' 接口(这个接口专门单独出来,是生成普通的二维码,并非是 '小程序码',没有上面提到的优势)
1.适用于需要的码数量较少的业务场景。永久有效,和 wxacode.get 生成的二维码总数限制 100000 个
服务端 -> 小程序码 -> wxacode.createQRCode
参数:
access_token
page -
width -
13.小程序登录
小程序可以通过微信官方提供的登录能力,方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系
登录流程分 2 步:
1.小程序前端,调用 wx.login() API,来获取临时登录凭证 code
API -> 开放接口 -> 登录 -> wx.login
wx.login
参数:
timeout - 超时时间
success -
fail -
complete -
sucess 回调函数的参数:
code - 用户登录凭证(有效期:5分钟)
/*
还有一个相关的接口:
wx.checkSession() - 检查登录态是否过期
参数:
success -
fail -
complete -
很多时候,需要 session_key 来进行解密,如果 session_key 过期,会导致失败。我们需要判断用户是否仍旧登录着,不登录则重新登录
wx.checkSession({
success(){
// 出于登录状态
},
fail(){
// session_key 已过期,需要重新登录
wx.login()
}
})
*/
2.通过上面获取到的 code,请求我们的开发服务器,开发服务器调用 '服务端接口' 的 'auth.code2Session',换取用户唯一标识 'open_id' 和 会话秘钥 'session_key'
服务端 -> 开发接口 -> 登录 -> code2Session
code2Session
get https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
请求参数:
appid - 小程序 appId
secret - 小程序 appSecret
js_code - wx.login() 得到的 code
grant_type - 授权类型,目前只有:authorization_code
返回值:
openid - 用户 open_id
session_key - 会话秘钥
unionid - 用户 unionid,微信开放平台绑定了小程序
errcode - 错误码
errmsg - 错误信息
注意:
1.会话秘钥 session_key 是对用户数据进行 '机密签名' 的秘钥。为了安全,需要保存在服务器。
2.临时登录凭证 code 只能使用一次
/*
考虑:
1.上面的登录流程,是微信的登录流程,并未对接到我们的业务系统用户,我们还需要和业务系统的用户进行绑定关联!
user_binds - 用户绑定表
id
user_id - 用户id
type - 类型:qq、aliyun、wechat_official_account、wechat_miniprogram
unique_identifier - unionid
attach_identifier - openid
nick_name - 暱称
gender - 性别
...
session_key 也得保存,用于解密,只有临时数据,redis 中比较合适,和 open_id 关联上就行
2.我们的系统,是否应该采用微信这套 '登录状态' 体系?
我感觉不太合适,还是后端来存储比较合适。小程序只是提供一个快捷入口,直接登录,首次需要和用户 id 绑定下,以后就关联登录了
*/
14.授权
部分接口需要经过用户授权同意后,才能使用。
1>如果用户未接受或拒绝过此权限,会弹窗询问用户,用户点击同意后方可调用接口
2>如果用户已授权,可以直接调用接口
3>如果用户已拒绝授权,则不会出现弹窗,直接进入接口 fail 回调(我们需要做用户拒绝授权的处理)
1>获取用户授权设置
API -> 设置 -> wx.getSetting
获取用户的当前设置(返回值中,只会出现小程序已经向用户请求过的权限 - 这个意思是,我们项目里可能涉及了好多授权的权限,但是用户目前只访问到其中的部分,就只会显示这部分的权限)
wx.getSetting({
success(res){
res.authSetting = {
"scope.userInfo": true,
"scope.userLocation": true,
}
}
})
2>打开设置界面
打开设置界面有 2 种方式:
1.小程序设置界面:「右上角」 - 「关于」 - 「右上角」 - 「设置」
2.开发者可以调用 wx.openSetting 打开设置界面
/*
参考:https://developers.weixin.qq.com/community/develop/doc/000cea2305cc5047af5733de751008
之前,可以直接调用该接口,后来微信为了避免此接口的滥用,调整了调用方式:
1>使用 <button> 组件来调用
<button open-type="openSetting" bindopensetting="callback">打开设置页</button>
2>由点击行为,触发 wx.openSetting 接口
<button bindtap="openSetting">打开设置页</button>
Page({
openSetting(e){
wx.openSetting()
}
})
*/
// 参数&返回结果和 'wx.getSetting' 一致
wx.openSetting({
success(res){
res.authSetting = {
"scope.userInfo": true,
"scope.userLocation": true,
}
}
})
3>发起用户授权
API -> 授权 -> wx.authorize
提前向用户发起授权请求。调用后,会立刻弹窗询问用户是否同意授权。如果之前已同意授权,则不会出现弹窗,直接返回成功
wx.authorize({
// scope - 需要获取权限的 scope
// success - 成功
// fail - 失败
// complete - 成功、失败都执行
})
4>scope 列表
scope.userInfo - 用户信息(接口:wx.getUserInfo)
scope.userLocation - 地理位置(接口:wx.getLocation, wx.chooseLocation)
scope.address - 通讯地址(接口:wx.chooseAddress)
scope.invoiceTitle - 发票擡头(接口:wx.chooseInvoiceTitle)
scope.invoice - 获取发票(接口:wx.chooseInvoice)
scope.werun - 微信运动步数(接口:wx.getWeRunData)
scope.record - 录音功能(接口:wx.startRecord)
scope.writePhotosAlbum - 保存到相册(接口:wx.saveImageToPhotosAlbum, wx.saveVideoToPhotosAlbum)
scope.camera - 摄像头(<camera> 组件)
注意:
1.wx.authorize({ scope: "scope.userInfo" }) // 不会出现授权窗口,需要使用 <button open-type="getUserInfo"></button>
2.scope.userLocation,必须配置 '地理位置说明用途'
/*
框架 -> 小程序配置 -> 全局配置 -> permission
"permission": {
"scope.userLocation": {
"desc": "小程序获取权限时展示的接口用途说明,最长 30 个字符"
}
}
*/
5>AuthSetting
用户授权设置信息
wx.getSetting({
success(res){
// 返回 authSetting,
// res.authSetting
// 是否授权了 '录音功能'
if( ! res.authSetting['scope.record']){
}
}
})
{
"scope.userInfo": true,
"scope.userLocation": true,
...
对应上面的 scope 列表
...
}
15.获取手机号
1>调用须知
1.获取微信用户绑定的手机号,需要先调用 'wx.login' 接口
2.需要用户主动触发,才能发起获取手机的接口。所以不能通过 API 调用,得使用 '<button>' 组件
3.只对企业开发者,且完成了认证的小程序开放
2>使用
1.<button> 组件,open-type 设置为 'getPhoneNumber',用户点击并同意后,通过 bindgetphonenumber 事件回调微信返回的加密数据
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
2.在 '事件回调' 中,通过微信返回的加密数据,调用开发服务器的接口,结合服务器上存储的 session_key 和 app_id 来解密数据,得到用户手机号(需要 session_key,所以之前必须调用了 'wx.login')
Page({
getPhoneNumber(e) {
console.log(e.detail.errMsg)
console.log(e.detail.iv)
console.log(e.detail.encryptedData)
// 调用服务器接口
wx.request({
})
}
})
/*
注意:
在回调中调用 wx.login 登录,可能会刷新登录态。此时服务器使用 code 换取的 sessionKey 不是加密时使用的 sessionKey,导致解密失败。
建议开发者提前进行 login;或者在回调中先使用 checkSession 进行登录态检查,避免 login 刷新登录态。
*/
3>返回参数说明
encryptedData - 包括敏感数据在内的完整用户信息的加密数据
iv - 加密算法的初始向量
encryptedData 解密后的 json 结构为:
{
"phoneNumber": "13580006666", // 用户绑定的手机号(国外手机号会有区号)
"purePhoneNumber": "13580006666", // 没有区号的手机号
"countryCode": "86", // 区号
"watermark": {
"appid": "APPID",
"timestamp": TIMESTAMP
}
}