由于微信小程序在2022年11月8日24时调整了获取用户信息的接口,导致wx.getUserProfile()这个方法返回的用户头像和用户昵称都变成匿名的状态,如果想要获取用户的头像和昵称,必须让用户自己去填写。相关链接
调整背景
在小程序内,开发者可以通过 wx.login 接口直接获取用户的 openId 与 unionId 信息,实现微信身份登录,支持开发者在多个小程序或其它应用间匿名关联同一用户。
同时,为了满足部分小程序业务中需要创建用户的昵称与头像的诉求,平台提供了 wx.getUserProfile 接口,支持在用户授权的前提下,快速使用自己的微信昵称头像。
但实践中发现有部分小程序,在用户刚打开小程序时就要求收集用户的微信昵称头像,或者在支付前等不合理路径上要求授权。如果用户拒绝授权,则无法使用小程序或相关功能。在已经获取用户的 openId 与 unionId 信息情况下,用户的微信昵称与头像并不是用户使用小程序的必要条件。为减少此类不合理的强迫授权情况,作出如下调整。
代码调整
如果开发还是想要用户的昵称和头像作为友好的展示,就不得不改动现有的逻辑。
基本操作示例
以下代码是使用uni-app框架来开发,用的是vue3 typescript的语法,其中也用到了几个云函数
getSessionKey
这个云函数用来call 微信的restful API获取用户的sessionKey和openId
// getSessionKey
'use strict';
const appid = 'your app id'
const secret = 'your app secret'
exports.main = async (event, context) => {
const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&secret=${secret}&js_code=${event.code}&grant_type=authorization_code`
const { data } = await uniCloud.httpclient.request(url)
return data
};
arrayBufferToString
上一个API返回的数据是以buffer的形式传回的,所以需要把数据转换成对象去保存。这个函数是把获得的数据转变成string。
export function arrayBufferToString(buffer: ArrayBuffer): string {
const view = new Uint8Array(buffer);
let str = '';
for (let i = 0; i < view.length; i++) {
str += String.fromCharCode(view[i]);
}
return str;
}
业务流程
uni.login({
provider: 'weixin',
success: async (res) => {
// get session_key
const { result } = await database.callFunction({
name: 'getSessionKey',
data: {
code: res.code
}
})
// transform buffer to json
const data = arrayBufferToString(result.data)
const { openid, session_key } = JSON.parse(data)
// save openid and session_key
// ...
}
})
额外操作
不满足只有openId的小程序就需要使用以下的方法继续获取用户的信息。实现方式是用户主动去填写的。
头像选择
需要将 button 组件 open-type 的值设置为 chooseAvatar,当用户选择需要使用的头像之后,可以通过 bindchooseavatar 事件回调获取到头像信息的临时路径。文档链接
getAuthorization方法是promise版的判断用户照相簿权限的函数,具体实现如下:
async function getAuthorization() {
return new Promise((resolve, reject) => {
uni.getSetting({
success(res) {
if (!res.authSetting[`scope.writePhotosAlbum`]) {
// user have writePhotosAlbum scope
uni.authorize({
// let user to authorize this scope
scope: `scope.writePhotosAlbum`,
success(e) {
resolve(true);
},
fail() {
reject(false);
}
});
} else {
resolve(true);
}
},
fail() {
reject(false);
}
});
});
}
头像云端保存
uploadFile云函数是把用户头像保存在云端用户数据库中,注意的是当使用fileSystemManager.readFileSync返回的是数据是buffer形式,需要转换后才能传入云函数,这里把数据指定为base64的格式后上传。然后使用unicloud.uploadFile来上传到云端。这里还要注意的一点就是这个函数需要的fileContent的类型是Buffer,就是需要再把base64的数据再转回来。
<template>
<button class="avatar-wrapper" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<image class="avatar" :src="avatarUrl"></image>
</button>
<template>
<script lang="ts" setup>
const onChooseAvatar = async (e: any) => {
const isauth = await getAuthorization()
if (isauth) {
const fileSystemManager = uni.getFileSystemManager()
const fileContent = fileSystemManager.readFileSync(e.target.avatarUrl, 'base64')
// save avatar to database
const { result } = await database.callFunction({
name: 'uploadFile',
data: {
fileName: 'avatar',
fileContent: fileContent,
type: e.type
}
})
console.log(result)
// ...
}
else {
// ...
}
}
<script>
// uploadFile
'use strict';
exports.main = async (event, context) => {
// base64 to buffer
const fileData = Buffer.from(event.fileContent, 'base64')
try {
const res = await uniCloud.uploadFile({
fileContent: fileData,
cloudPath: event.fileName + '.jpg'
});
return {
success: true,
data: res,
errorMsg: ''
}
} catch (error) {
return {
success: false,
data: fileData,
errorMsg: error
}
}
};
昵称保存
这里获取昵称的方法没什么特别的,就是用个<input>
组件让用户输入,然后和之前的头像一起上传处理就行了。
总结
随着时代的进步,用户数据变得越来越重要,相信微信的这次改动也是由于信息的滥用不得已而为之的,数据安全是开发者不得不考虑的问题,作为开发者自身必须要确保数据安全的前提下,同时要具备有对数据使用的道德准则。