前言
用Unity
开发微信小游戏过程中,想要获取用户信息,遇到了许多坑位,这里记录一下
待实现效果
- 初次进入游戏,询问是否同意隐私协议
- 接着查询用户信息授权情况
- 已授权,直接获取用户信息
- 未授权,创建授权按钮
实现步骤
以下步骤仅提供参考
有些细则可在官方文档或官方Demo查看,可能隐藏较深,需耐心翻找,并且很多适配API的文档需在源码注释里找
设置
用户信息属于敏感数据,想获取需要授权,而想授权成功则需要同意隐私协议。所以,需要到微信公众号平台设置隐私协议
PS:坑位一,这些在官方文档几乎没提到,不然就是隐藏极深
- 登录微信公众平台
- 点击
设置 > 服务内容声明
Unity操作
- 在场景里新建一个空对象,这里取名为
Loader
- 新建一个脚本,绑定给
Loader
- 在场景里新建一个按钮,文本设置为
Start Game
,用于表示开始游戏 - 为按钮的点击事件绑定
Loader
脚本的函数
- 最终界面如下
其中,按钮作用主要是为了引导用户点击授权区域
脚本编写
以下是脚本内容,具体可看代码注释
大致的步骤是
- 初始化SDK
- 询问隐私协议授权情况
- 未授权则弹出询问隐私协议
- 询问用户信息授权情况
- 已授权,直接获取用户信息
- 未授权,创建授权点击区域
PS:坑位二,在Unity中,WX.CreateUserInfoButton创建的是一个透明区域,透明啊!!!这两个字只在官方Demo及源码注释中提了一嘴,不知道还以为没生效呢,这也是为什么需要一个按钮来引导点击的原因
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using WeChatWASM;
public class LoaderTest : MonoBehaviour
{
/// <summary>
/// 用户信息
/// 获取到用户信息后可根据需要存云端或本地持久存储
/// </summary>
public WXUserInfo userInfo;
/// <summary>
/// 是否获取用户信息
/// </summary>
private bool infoFlag = false;
/// <summary>
/// 头像材质
/// </summary>
public Texture2D avatarTexture;
// Start is called before the first frame update
void Start()
{
// 初始化微信SDK
WX.InitSDK((code) =>
{
Debug.Log("init WXSDK code: " + code);
// 加载用户信息
this.LoaderWXMess();
});
}
/// <summary>
/// 加载微信授权相关信息
/// </summary>
private void LoaderWXMess()
{
// 1. 询问隐私协议授权情况
WX.GetPrivacySetting(new GetPrivacySettingOption()
{
success = (res) =>
{
/**
* needAuthorization - 含义
* 是否需要用户授权隐私协议(如果开发者没有在[mp后台-设置-服务内容声明-用户隐私保护指引]中声明隐私收集类型则会返回false;
* 如果开发者声明了隐私收集,且用户之前同意过隐私协议则会返回false;
* 如果开发者声明了隐私收集,且用户还没同意过则返回true;
* 如果用户之前同意过、但后来小程序又新增了隐私收集类型也会返回true)
*/
// 询问成功
if (res.needAuthorization)
{
// 有隐私协议,且未授权
// 2. 发起隐私协议授权
// 弹出隐私协议询问弹窗
WX.RequirePrivacyAuthorize(new RequirePrivacyAuthorizeOption()
{
success = (res) =>
{
Debug.Log("同意隐私协议:" + JsonUtility.ToJson(res, true));
// 用户同意隐私协议
// 3. 获取用户信息
this.GetScopeInfoSetting();
// 将 信息获取标志 标记为true
this.infoFlag = true;
},
fail = (err) =>
{
Debug.Log("拒绝隐私协议:" + JsonUtility.ToJson(res, true));
},
complete = (res) =>
{
Debug.Log("询问隐私协议结束");
}
});
}
},
fail = (err) => { },
complete = (res) =>
{
// 处理询问隐私协议失败或之前已经同意但未授权用户信息的情况
if (!this.infoFlag)
{
this.GetScopeInfoSetting();
}
}
});
}
/// <summary>
/// 点击开始游戏
/// </summary>
public void StartGame()
{
Debug.Log("start game");
Debug.Log("用户信息:" + JsonUtility.ToJson(this.userInfo, true));
}
/// <summary>
/// 获取授权
/// </summary>
private void GetScopeInfoSetting()
{
// 询问用户信息授权情况
WX.GetSetting(new GetSettingOption()
{
success = (res) =>
{
Debug.Log("获取用户信息授权情况成功: " + JsonUtility.ToJson(res.authSetting, true));
// 判断用户信息的授权情况
if (!res.authSetting.ContainsKey("scope.userInfo") || !res.authSetting["scope.userInfo"])
{
// 3.1 未授权,创建授权按钮区
// 需引导用户点击所创建的区域,这里的做法是将开始游戏的按钮放在该区域
this.CreateUserInfoButton();
}
else
{
// 3.2 已授权,直接获取用户信息
this.GetUserInfo();
// 这里也可以先不获取,留到点击开始游戏按钮再获取,但没必要,先获取后存起来即可
}
},
fail = (err) =>
{
Debug.Log("获取用户信息授权情况失败:" + JsonUtility.ToJson(err, true));
}
});
}
/// <summary>
/// 创建用户信息授权点击区域
/// </summary>
private void CreateUserInfoButton()
{
Debug.Log("create userinfo button area");
/**
* 方法一:创建用户信息获取按钮,在底部区域创建一个300高度的 透明!!! 区域
* 首次获取会弹出用户授权窗口, 可通过右上角-设置-权限管理用户的授权记录
* 可根据需要设置不同高度,使用屏幕还有其它点击热区的情况
*/
// 获取屏幕信息
// var systemInfo = WX.GetSystemInfoSync();
// var canvasWith = (int)(systemInfo.screenWidth * systemInfo.pixelRatio);
// var canvasHeight = (int)(systemInfo.screenHeight * systemInfo.pixelRatio);
// var buttonHeight = (int)(canvasWith / 1080f * 300f);
// 很容易被误导,与其叫按钮,不如叫热区
// WXUserInfoButton btn = WX.CreateUserInfoButton(0, canvasHeight - buttonHeight, canvasWith, buttonHeight, "zh_CN", false);
/**
* 方法二:创建布满整个屏幕的授权按钮区
*/
WXUserInfoButton btn = WX.CreateUserInfoButton(0, 0, Screen.width, Screen.height, "zh_CN", false);
// 监听授权区域的点击
btn.OnTap((res) =>
{
Debug.Log("click userinfo btn: " + JsonUtility.ToJson(res, true));
if (res.errCode == 0)
{
// 用户已允许获取个人信息,返回的 res.userInfo 即为用户信息
Debug.Log("userinfo: " + JsonUtility.ToJson(res.userInfo, true));
// 将用户信息存入成员变量,以待后用
this.userInfo = res.userInfo;
// 展示,只是为了测试看到
this.ShowUserInfo(res.userInfo.avatarUrl, res.userInfo.nickName);
}
else
{
Debug.Log("用户拒绝获取个人信息");
}
// 最后隐藏授权区域,防止阻塞游戏继续
btn.Hide();
Debug.Log("已隐藏热区");
});
}
/// <summary>
/// 调用Api获取用户信息
/// </summary>
private void GetUserInfo()
{
WX.GetUserInfo(new GetUserInfoOption()
{
lang = "zh_CN",
success = (res) =>
{
Debug.Log("获取用户信息成功(API): " + JsonUtility.ToJson(res.userInfo, true));
// 将用户信息存入成员变量,或存入云端,方便后续使用
this.userInfo = this.ConvertUserInfo(res.userInfo);
this.ShowUserInfo(res.userInfo.avatarUrl, res.userInfo.nickName);
},
fail = (err) =>
{
Debug.Log("获取用户信息失败(API): " + JsonUtility.ToJson(err, true));
}
});
}
/// <summary>
/// 展示用户信息,对头像、昵称展示的整合
/// ps: 测试用
/// </summary>
/// <param name="avatarUrl"></param>
/// <param name="nickName"></param>
private void ShowUserInfo(string avatarUrl, string nickName)
{
StartCoroutine(LoadAvatar(avatarUrl));
showNickname(nickName);
}
/// <summary>
/// 展示用户头像
/// ps: 测试用
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
IEnumerator LoadAvatar(string url)
{
// 加载头像图片
UnityWebRequest request = new UnityWebRequest(url);
DownloadHandlerTexture texture = new DownloadHandlerTexture(true);
request.downloadHandler = texture;
yield return request.SendWebRequest();
if (string.IsNullOrEmpty(request.error))
{
avatarTexture = texture.texture;
}
Sprite sprite = Sprite.Create(avatarTexture, new Rect(0, 0, avatarTexture.width, avatarTexture.height), new Vector2(0.5f, 0.5f));
// 场景中图片对象名称为Avatar
Image tempImage = GameObject.Find("Avatar").GetComponent<Image>();
tempImage.sprite = sprite;
}
/// <summary>
/// 展示用户昵称
/// ps: 测试用
/// </summary>
/// <param name="name"></param>
void showNickname(string name)
{
// 场景中文本对象名称为Nickname
Text nickname = GameObject.Find("Nickname").GetComponent<Text>();
nickname.text = name;
}
/// <summary>
/// 将UserInfo对象转为WXUserInfo
/// ps: 不知为何,相同结构要搞两个对象
/// </summary>
/// <param name="userInfo"></param>
/// <returns></returns>
WXUserInfo ConvertUserInfo(UserInfo userInfo)
{
return new WXUserInfo()
{
nickName = userInfo.nickName,
avatarUrl = userInfo.avatarUrl,
country = userInfo.country,
province = userInfo.province,
city = userInfo.city,
language = userInfo.language,
gender = (int)userInfo.gender
};
}
}
注意: 如游戏内需展示头像,最好将头像的域名在微信公众平台内设置为合法域名