feat: 接入微信隐私授权API和用户信息获取
- WxSDK 新增隐私授权检查和用户信息获取方法 - StorageManager 新增用户信息本地缓存方法 - PageHome 进入时检查隐私授权状态 - PageWriteLevels 分享时获取用户头像昵称并上传服务端 - ApiConfig 新增用户信息 API 端点 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { _decorator, Node, Button } from 'cc';
|
import { _decorator, Node, Button } from 'cc';
|
||||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||||
import { WxSDK } from 'db://assets/scripts/utils/WxSDK';
|
import { WxSDK, checkPrivacySetting, requirePrivacyAuthorize } from 'db://assets/scripts/utils/WxSDK';
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,6 +23,8 @@ export class PageHome extends BaseView {
|
|||||||
console.log('[PageHome] onViewLoad');
|
console.log('[PageHome] onViewLoad');
|
||||||
this._initButtons();
|
this._initButtons();
|
||||||
this._initWxShare();
|
this._initWxShare();
|
||||||
|
// 检查隐私授权
|
||||||
|
this._checkPrivacyAuthorization();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,6 +38,28 @@ export class PageHome extends BaseView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查隐私授权状态
|
||||||
|
*/
|
||||||
|
private async _checkPrivacyAuthorization(): Promise<void> {
|
||||||
|
if (!WxSDK.isWechat()) {
|
||||||
|
console.log('[PageHome] 非微信环境,跳过隐私授权检查');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { needAuthorization } = await checkPrivacySetting();
|
||||||
|
if (needAuthorization) {
|
||||||
|
console.log('[PageHome] 用户未授权隐私,引导授权');
|
||||||
|
await requirePrivacyAuthorize();
|
||||||
|
} else {
|
||||||
|
console.log('[PageHome] 用户已授权隐私');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('[PageHome] 隐私授权检查异常:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化按钮事件
|
* 初始化按钮事件
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
|||||||
import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager';
|
import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager';
|
||||||
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
||||||
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
|
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
|
||||||
|
import { StorageManager } from 'db://assets/scripts/utils/StorageManager';
|
||||||
|
import { WxSDK, getUserProfile } from 'db://assets/scripts/utils/WxSDK';
|
||||||
|
import { API_ENDPOINTS, API_TIMEOUT } from 'db://assets/scripts/config/ApiConfig';
|
||||||
|
import { HttpUtil } from 'db://assets/scripts/utils/HttpUtil';
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -525,6 +529,10 @@ export class PageWriteLevels extends BaseView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('[PageWriteLevels] 创建分享成功, code:', shareCode);
|
console.log('[PageWriteLevels] 创建分享成功, code:', shareCode);
|
||||||
|
|
||||||
|
// 获取用户头像昵称并上传
|
||||||
|
await this._uploadUserInfo();
|
||||||
|
|
||||||
ShareManager.instance.triggerWxShare(shareTitle, shareCode);
|
ShareManager.instance.triggerWxShare(shareTitle, shareCode);
|
||||||
ToastManager.instance.show('分享创建成功!');
|
ToastManager.instance.show('分享创建成功!');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -550,6 +558,49 @@ export class PageWriteLevels extends BaseView {
|
|||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户头像昵称并上传到服务端
|
||||||
|
*/
|
||||||
|
private async _uploadUserInfo(): Promise<void> {
|
||||||
|
// 先检查本地缓存
|
||||||
|
const cachedUserInfo = StorageManager.getUserInfo();
|
||||||
|
if (cachedUserInfo) {
|
||||||
|
console.log('[PageWriteLevels] 使用缓存的用户信息');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WxSDK.isWechat()) {
|
||||||
|
console.log('[PageWriteLevels] 非微信环境,跳过获取用户信息');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const userInfo = await getUserProfile();
|
||||||
|
|
||||||
|
// 本地缓存
|
||||||
|
StorageManager.setUserInfo(userInfo);
|
||||||
|
|
||||||
|
// 上传到服务端
|
||||||
|
const response = await HttpUtil.post(
|
||||||
|
API_ENDPOINTS.USER_INFO,
|
||||||
|
{
|
||||||
|
avatarUrl: userInfo.avatarUrl,
|
||||||
|
nickName: userInfo.nickName
|
||||||
|
},
|
||||||
|
API_TIMEOUT.DEFAULT
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
console.log('[PageWriteLevels] 用户信息上传成功');
|
||||||
|
} else {
|
||||||
|
console.warn('[PageWriteLevels] 用户信息上传失败:', response.message);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('[PageWriteLevels] 获取用户信息失败:', err);
|
||||||
|
// 不阻断主流程
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onViewHide(): void {
|
onViewHide(): void {
|
||||||
console.log('[PageWriteLevels] onViewHide');
|
console.log('[PageWriteLevels] onViewHide');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const API_ENDPOINTS = {
|
|||||||
USER_GAME_DATA: `${API_BASE}/user/game-data`,
|
USER_GAME_DATA: `${API_BASE}/user/game-data`,
|
||||||
LEVELS: `${API_BASE}/wechat-game/levels`,
|
LEVELS: `${API_BASE}/wechat-game/levels`,
|
||||||
SHARE_CREATE: `${API_BASE}/share`,
|
SHARE_CREATE: `${API_BASE}/share`,
|
||||||
|
USER_INFO: `${API_BASE}/user/info`,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
/** 构建加入分享的 URL */
|
/** 构建加入分享的 URL */
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ export class StorageManager {
|
|||||||
/** 认证 token 存储键 */
|
/** 认证 token 存储键 */
|
||||||
private static readonly KEY_TOKEN = 'auth_token';
|
private static readonly KEY_TOKEN = 'auth_token';
|
||||||
|
|
||||||
|
/** 用户信息存储键 */
|
||||||
|
private static readonly KEY_USER_INFO = 'user_info';
|
||||||
|
|
||||||
/** 默认积分 */
|
/** 默认积分 */
|
||||||
private static readonly DEFAULT_POINTS = 10;
|
private static readonly DEFAULT_POINTS = 10;
|
||||||
|
|
||||||
@@ -264,6 +267,48 @@ export class StorageManager {
|
|||||||
StorageManager.resetPoints();
|
StorageManager.resetPoints();
|
||||||
StorageManager.resetProgress();
|
StorageManager.resetProgress();
|
||||||
StorageManager.clearToken();
|
StorageManager.clearToken();
|
||||||
|
StorageManager.clearUserInfo();
|
||||||
console.log('[StorageManager] 所有数据已重置');
|
console.log('[StorageManager] 所有数据已重置');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 用户信息管理 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息结构
|
||||||
|
*/
|
||||||
|
interface UserInfo {
|
||||||
|
avatarUrl: string;
|
||||||
|
nickName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存用户信息(头像、昵称)
|
||||||
|
* @param userInfo 用户信息对象
|
||||||
|
*/
|
||||||
|
static setUserInfo(userInfo: UserInfo): void {
|
||||||
|
sys.localStorage.setItem(StorageManager.KEY_USER_INFO, JSON.stringify(userInfo));
|
||||||
|
console.log('[StorageManager] 用户信息已保存');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取本地缓存的用户信息
|
||||||
|
* @returns 用户信息对象或 null
|
||||||
|
*/
|
||||||
|
static getUserInfo(): UserInfo | null {
|
||||||
|
const data = sys.localStorage.getItem(StorageManager.KEY_USER_INFO);
|
||||||
|
if (!data) return null;
|
||||||
|
try {
|
||||||
|
return JSON.parse(data) as UserInfo;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除用户信息缓存
|
||||||
|
*/
|
||||||
|
static clearUserInfo(): void {
|
||||||
|
sys.localStorage.removeItem(StorageManager.KEY_USER_INFO);
|
||||||
|
console.log('[StorageManager] 用户信息已清除');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,3 +237,135 @@ export class WxSDK {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 隐私授权相关 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户是否已授权隐私
|
||||||
|
* @returns Promise<{ needAuthorization: boolean }> needAuthorization 为 false 表示已授权
|
||||||
|
*/
|
||||||
|
export async function checkPrivacySetting(): Promise<{ needAuthorization: boolean }> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const wxApi = WxSDK.getWx();
|
||||||
|
if (!wxApi) {
|
||||||
|
// 非微信环境,认为已授权
|
||||||
|
resolve({ needAuthorization: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof wxApi.getPrivacySetting !== 'function') {
|
||||||
|
// 低版本微信,认为已授权
|
||||||
|
console.warn('[WxSDK] 当前微信版本不支持 getPrivacySetting');
|
||||||
|
resolve({ needAuthorization: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxApi.getPrivacySetting({
|
||||||
|
success: (res: any) => {
|
||||||
|
console.log('[WxSDK] 隐私授权检查结果:', res);
|
||||||
|
resolve({ needAuthorization: res.needAuthorization });
|
||||||
|
},
|
||||||
|
fail: (err: any) => {
|
||||||
|
console.warn('[WxSDK] 隐私授权检查失败:', err);
|
||||||
|
// 检查失败时认为需要授权
|
||||||
|
resolve({ needAuthorization: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 引导用户进行隐私授权
|
||||||
|
* 调用后会弹出微信隐私授权弹窗
|
||||||
|
* @returns Promise<void>
|
||||||
|
*/
|
||||||
|
export async function requirePrivacyAuthorize(): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const wxApi = WxSDK.getWx();
|
||||||
|
if (!wxApi) {
|
||||||
|
console.warn('[WxSDK] 非微信环境,跳过隐私授权');
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof wxApi.requirePrivacyAuthorize !== 'function') {
|
||||||
|
console.warn('[WxSDK] 当前微信版本不支持 requirePrivacyAuthorize');
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxApi.requirePrivacyAuthorize({
|
||||||
|
success: () => {
|
||||||
|
console.log('[WxSDK] 用户已授权隐私');
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
fail: (err: any) => {
|
||||||
|
console.warn('[WxSDK] 用户拒绝或授权失败:', err);
|
||||||
|
reject(new Error(err.errMsg || '隐私授权失败'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 用户信息相关 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息(头像、昵称)
|
||||||
|
*/
|
||||||
|
export interface WxUserInfo {
|
||||||
|
avatarUrl: string;
|
||||||
|
nickName: string;
|
||||||
|
country?: string;
|
||||||
|
province?: string;
|
||||||
|
city?: string;
|
||||||
|
gender?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户头像和昵称(需要用户主动授权)
|
||||||
|
* @returns Promise<WxUserInfo>
|
||||||
|
*/
|
||||||
|
export async function getUserProfile(): Promise<WxUserInfo> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const wxApi = WxSDK.getWx();
|
||||||
|
if (!wxApi) {
|
||||||
|
// 非微信环境,返回 mock 数据
|
||||||
|
console.warn('[WxSDK] 非微信环境,返回 mock 用户信息');
|
||||||
|
resolve({
|
||||||
|
avatarUrl: '',
|
||||||
|
nickName: '微信用户'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof wxApi.getUserProfile !== 'function') {
|
||||||
|
console.warn('[WxSDK] 当前微信版本不支持 getUserProfile');
|
||||||
|
reject(new Error('当前微信版本不支持 getUserProfile'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxApi.getUserProfile({
|
||||||
|
desc: '用于完善用户资料',
|
||||||
|
success: (res: any) => {
|
||||||
|
if (res.userInfo) {
|
||||||
|
console.log('[WxSDK] 获取用户信息成功');
|
||||||
|
resolve({
|
||||||
|
avatarUrl: res.userInfo.avatarUrl,
|
||||||
|
nickName: res.userInfo.nickName,
|
||||||
|
country: res.userInfo.country,
|
||||||
|
province: res.userInfo.province,
|
||||||
|
city: res.userInfo.city,
|
||||||
|
gender: res.userInfo.gender
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('[WxSDK] 获取用户信息失败: 无 userInfo');
|
||||||
|
reject(new Error('获取用户信息失败'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err: any) => {
|
||||||
|
console.error('[WxSDK] 获取用户信息失败:', err);
|
||||||
|
reject(new Error(err.errMsg || '获取用户信息失败'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user