uniapp 提供了获取手机号的 button 组件:
<button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">获取手机号</button>
uniapp 提供了新旧两种版本的接口:
接口类型 | 前端返回参数 | 后端解密方式 | 适用场景 |
---|---|---|---|
旧版接口 | encryptedData , iv | 使用 session_key 解密 | 兼容低版本微信客户端 |
新版接口 | 动态 code | 直接调用微信接口换取手机号 | 仅需支持微信 7.0.0+ 版本 |
动态令牌
code
与登录code
的区别:
- 登录
code
:通过wx.login()
获取,用于换取session_key
。- 动态令牌
code
:通过wx.getPhoneNumber()
返回(旧版接口返回encryptedData
,新版返回动态code
)。
下面我们来分别看一下👇
旧版接口
前端:调用 uni.getPhoneNumber
获取加密手机号数据(encryptedData 和 iv),并将 uni.login 生成的 code 发送给后端,以便后端生成 session_key 用来解密。
后端:使用 session_key、encryptedData 和 iv 解密获取真实手机号。
前端-核心代码:
getPhoneNumber(e) { // 底部弹起用户手机号授权弹窗
if (e.detail.errMsg == 'getPhoneNumber:ok') {
const encryptedData = e.detail.encryptedData;
const iv = e.detail.iv;
// 优先使用之前保存的code
const code = this.data.code || '';
// 如果没有有效的code,则重新调用login获取
if (!code) {
wx.login({
success: (loginRes) => {
// 调用后端手机号解密接口,将 encryptedData、iv、code 发送到后端解密获取手机号
api.decryptPhone({ encryptedData, iv, code })
}
});
} else {
api.decryptPhone({ encryptedData, iv, code })
}
} else {
// 用户拒绝授权
console.log('用户拒绝授权获取手机号');
}
}
新版接口
前端:点击按钮生成动态 code,传给后端;
后端:直接用此 code
调用微信接口 phonenumber.getPhoneNumber
换取手机号(无需 session_key 解密,微信服务器直接返回明文手机号)。
前端-核心代码:
getPhoneNumber(e) {
const code = e.detail.code;
if (code) {
// 调用后端获取手机号接口,传入动态code即可
api.getPhone({ code });
}
}
【附录】---------------------------------------
(旧版)前端完整代码:
// 1. 先检查session_key是否有效
wx.checkSession({
success() {
// session_key有效,直接获取手机号
getPhoneNumber();
},
fail() {
// session_key已过期,重新登录获取code
wx.login({
success: function(res) {
if (res.code) {
// 保存新的code,后续用于获取session_key
const code = res.code;
getPhoneNumber(code);
}
}
});
}
});
// 2. 获取手机号的函数
function getPhoneNumber(existCode) {
wx.getUserProfile({
desc: '用于完善会员资料',
success: function(userRes) {
// 显示获取手机号的按钮
wx.showModal({
title: '提示',
content: '需要获取您的手机号以完成注册',
success: function(modalRes) {
if (modalRes.confirm) {
// 点击确定,显示获取手机号按钮
wx.navigateTo({
url: '/pages/bindPhone/bindPhone'
});
}
}
});
}
});
}
// 3. 在绑定手机号页面的js中
onGetPhoneNumber: function(e) {
if (e.detail.errMsg === 'getPhoneNumber:ok') {
const encryptedData = e.detail.encryptedData;
const iv = e.detail.iv;
// 优先使用之前保存的code
const code = this.data.code || '';
// 如果没有有效的code,则重新调用login获取
if (!code) {
wx.login({
success: (loginRes) => {
this.sendPhoneData(loginRes.code, encryptedData, iv);
}
});
} else {
this.sendPhoneData(code, encryptedData, iv);
}
} else {
wx.showToast({
title: '授权失败',
icon: 'none'
});
}
},
sendPhoneData: function(code, encryptedData, iv) {
wx.request({
url: 'https://your-server.com/api/decryptPhone',
method: 'POST',
data: {
code: code,
encryptedData: encryptedData,
iv: iv
},
success: (res) => {
if (res.data.success) {
const phoneNumber = res.data.phoneNumber;
// 处理手机号,如保存到本地或进行登录操作
wx.setStorageSync('phoneNumber', phoneNumber);
wx.showToast({
title: '绑定成功',
success: () => {
wx.navigateBack();
}
});
} else {
wx.showToast({
title: res.data.message || '解密失败',
icon: 'none'
});
}
},
fail: () => {
wx.showToast({
title: '网络错误',
icon: 'none'
});
}
});
}
(新版)前端完整代码:
onGetPhoneNumber(e) {
if (e.detail.code) {
// 获取到动态令牌code,发送到后端
wx.request({
url: 'https://your-server.com/api/getPhoneNumber',
method: 'POST',
data: {
code: e.detail.code,
// 可选:传递用户标识(如openid)
openid: wx.getStorageSync('openid')
},
success: (res) => {
if (res.data.success) {
const phoneNumber = res.data.phoneNumber;
wx.showToast({
title: `获取成功: ${phoneNumber}`,
icon: 'none'
});
} else {
wx.showToast({
title: res.data.message || '获取失败',
icon: 'none'
});
}
},
fail: () => {
wx.showToast({
title: '网络错误',
icon: 'none'
});
}
});
} else {
wx.showToast({
title: '用户拒绝授权',
icon: 'none'
});
}
}