大侠
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

573 lines
18 KiB

/**
* IAA插件SDK - 参考OceanOld实现模式
* 用于微信小游戏环境中的IAA功能接入
*/
class IAA_SDK {
constructor() {
this.isInitialized = false;
this.miniGameCommon = null;
this.adDataCache = new Map(); // 缓存广告数据
this.recentScene = null; // 记录最近的广告场景
this.recentSceneTime = 0; // 记录最近场景的时间
this.config = {
delayTime: 30000, // 延迟30秒请求预测
enableDebugLog: true
};
this.callbacks = {
onPredictionReceived: null,
onError: null
};
this.init();
}
/**
* 初始化IAA插件
*/
init() {
try {
if (typeof requirePlugin !== 'undefined') {
const createMiniGameCommon = requirePlugin('MiniGameCommon', {
enableRequireHostModule: true,
customEnv: {
wx
}
}).default;
this.miniGameCommon = createMiniGameCommon();
if (typeof this.miniGameCommon === 'undefined' || typeof this.miniGameCommon.canIUse === 'undefined') {
this.log('IAA插件创建失败', 'error');
} else {
this.isInitialized = true;
this.log('IAA插件初始化成功');
}
} else {
this.log('requirePlugin不存在,可能不在微信环境', 'warn');
}
} catch (e) {
this.log('IAA插件初始化异常:', e, 'error');
}
}
/**
* 设置配置参数
* @param {Object} config
*/
setConfig(config) {
this.config = Object.assign(this.config, config);
this.log('IAA配置更新:', this.config);
}
/**
* 记录视频广告观看
* @param {string} scene 广告场景
* @param {Object} data 广告相关数据
*/
videoAdd(data = {}) {
let scene = 'default'
try {
this.log(`开始记录视频观看 - 场景: ${scene}, 数据:`, data);
// 更新最近场景信息
this.recentScene = scene;
this.recentSceneTime = Date.now();
// 持久化保存最近场景信息
this.saveRecentScene();
const today = this.getTodayKey();
const cacheKey = `${scene}_${today}`;
// 获取或创建今日数据
let todayData = this.adDataCache.get(cacheKey) || {
scene: scene,
date: today,
clickCount: 0,
successCount: 0,
lastAdTime: 0,
data: data
};
// 更新观看次数
todayData.successCount++;
todayData.lastAdTime = Date.now();
todayData.data = data; // 更新数据
// 保存到缓存
this.adDataCache.set(cacheKey, todayData);
this.log(`视频观看记录成功: ${scene}, 今日次数: ${todayData.successCount}, 今日点击: ${todayData.clickCount}`);
// 每次观看完成后都延迟上报IAA
setTimeout(() => {
this.reportToIAA(scene, todayData);
}, this.config.delayTime);
// 持久化存储
this.saveToStorage();
} catch (e) {
this.log('videoAdd异常:', e, 'error');
}
}
/**
* 记录广告点击(在广告展示前调用)
* @param {string} scene 广告场景
* @param {Object} data 广告相关数据
*/
videoClick(data = {}) {
var scene = 'default'
try {
const today = this.getTodayKey();
const cacheKey = `${scene}_${today}`;
let todayData = this.adDataCache.get(cacheKey) || {
scene: scene,
date: today,
clickCount: 0,
successCount: 0,
lastAdTime: 0,
data: data
};
todayData.clickCount++;
this.adDataCache.set(cacheKey, todayData);
this.log(`视频点击记录: ${scene}, 今日点击: ${todayData.clickCount}`);
} catch (e) {
this.log('videoClick异常:', e, 'error');
}
}
/**
* 手动获取预测档位
* @param {string|null} scene 场景名称,如果不传或传null,则使用最近的场景
* @param {Function} callback 回调函数
*/
getUserLabel(scene = null, callback = null) {
if (!this.isInitialized) {
this.log('IAA插件未初始化', 'error');
callback && callback({ success: false, error: 'IAA插件未初始化' });
return;
}
// 如果没有传scene,使用最近的场景
if (!scene || scene === 'default') {
this.log(`没有指定场景,当前最近场景: ${this.recentScene}, 最近场景时间: ${this.recentSceneTime ? new Date(this.recentSceneTime).toLocaleString() : '无'}`);
if (this.recentScene) {
scene = this.recentScene;
this.log(`使用最近的场景: ${scene}`);
} else {
// 如果没有最近场景,尝试从缓存中找一个有数据的场景
const availableScenes = this.getAllAvailableScenes();
this.log(`可用场景列表: ${availableScenes.join(', ')}`);
if (availableScenes.length > 0) {
scene = availableScenes[0];
this.log(`没有最近场景,使用第一个可用场景: ${scene}`);
} else {
scene = 'default';
this.log(`没有任何场景数据,使用默认场景: ${scene}`);
}
}
}
const today = this.getTodayKey();
const cacheKey = `${scene}_${today}`;
let todayData = this.adDataCache.get(cacheKey);
// 如果没有找到数据,创建一个基础的数据结构
if (!todayData) {
this.log(`没有找到场景 ${scene} 的广告数据,创建基础数据结构`, 'warn');
todayData = {
scene: scene,
date: today,
clickCount: 0,
successCount: 0,
lastAdTime: 0,
data: {}
};
// 保存到缓存
this.adDataCache.set(cacheKey, todayData);
}
this.log(`请求预测档位 - 场景: ${scene}, 点击次数: ${todayData.clickCount}, 成功次数: ${todayData.successCount}`);
this.requestPrediction(scene, todayData, callback);
}
/**
* 上报IAA数据(不获取预测结果)
* @param {string} scene 场景
* @param {Object} adData 广告数据
*/
reportToIAA(scene, adData) {
if (!this.isInitialized) {
this.log('IAA插件未初始化,跳过数据上报', 'warn');
return;
}
try {
// 构建上报数据
const reportData = JSON.stringify({
"gift_scene": this.getGiftScene(scene),
"gift_name": this.getGiftName(scene, adData.data),
"gift_value": adData.clickCount,
"gift_value_success": adData.successCount
});
this.log('上报IAA数据:', { scene, reportData });
// 通过getUserLabel接口上报数据(但不处理返回结果)
this.miniGameCommon.getUserLabel({
reportData: reportData,
labelId: 'iaa_feature'
}).then(() => {
this.log('IAA数据上报成功:', scene);
}).catch((error) => {
this.log('IAA数据上报失败:', error, 'error');
});
} catch (e) {
this.log('reportToIAA异常:', e, 'error');
}
}
/**
* 请求IAA预测档位
* @param {string} scene 场景
* @param {Object} adData 广告数据
* @param {Function} callback 回调函数
*/
requestPrediction(scene, adData, callback = null) {
if (!this.isInitialized) {
this.log('IAA插件未初始化,无法请求预测', 'error');
return;
}
try {
// 构建上报数据
const reportData = JSON.stringify({
"gift_scene": this.getGiftScene(scene),
"gift_name": this.getGiftName(scene, adData.data),
"gift_value": adData.clickCount,
"gift_value_success": adData.successCount
});
this.log('开始请求IAA预测:', { scene, reportData });
// 调用IAA插件API
this.miniGameCommon.getUserLabel({
reportData: reportData,
labelId: 'iaa_feature'
}).then((res) => {
this.log('getUserLabel成功:', res);
const result = {
success: true,
scene: scene,
timestamp: Date.now(),
encryptedData: res.encryptedData,
iv: res.iv,
cloudID: res.cloudID,
rawData: res
};
// 存储结果
this.savePredictionResult(scene, result);
// 触发回调
if (callback) {
callback(result);
} else if (this.callbacks.onPredictionReceived) {
this.callbacks.onPredictionReceived(result);
}
}).catch((error) => {
this.log('getUserLabel失败:', error, 'error');
const errorResult = {
success: false,
scene: scene,
error: error,
timestamp: Date.now()
};
if (callback) {
callback(errorResult);
} else if (this.callbacks.onError) {
this.callbacks.onError(errorResult);
}
});
} catch (e) {
this.log('requestPrediction异常:', e, 'error');
}
}
/**
* 获取最新的预测结果
* @param {string} scene 场景名称
* @returns {Object|null} 预测结果
*/
getLatestPrediction(scene = 'default') {
try {
const key = `iaa_prediction_${scene}`;
const stored = wx.getStorageSync(key);
return stored ? JSON.parse(stored) : null;
} catch (e) {
this.log('获取预测结果异常:', e, 'error');
return null;
}
}
/**
* 获取今日广告统计
* @param {string} scene 场景名称
* @returns {Object} 统计数据
*/
getTodayAdStats(scene = 'default') {
const today = this.getTodayKey();
const cacheKey = `${scene}_${today}`;
return this.adDataCache.get(cacheKey) || {
scene: scene,
date: today,
clickCount: 0,
successCount: 0,
lastAdTime: 0
};
}
/**
* 设置回调函数
* @param {string} type 回调类型:'prediction' 或 'error'
* @param {Function} callback 回调函数
*/
setCallback(type, callback) {
if (type === 'prediction') {
this.callbacks.onPredictionReceived = callback;
} else if (type === 'error') {
this.callbacks.onError = callback;
}
}
/**
* 获取最近的广告场景
* @returns {string|null} 最近的场景名称
*/
getRecentScene() {
return this.recentScene;
}
/**
* 获取所有有数据的场景列表
* @returns {Array} 场景名称数组
*/
getAllAvailableScenes() {
const today = this.getTodayKey();
const scenes = [];
this.adDataCache.forEach((value, key) => {
if (key.endsWith(`_${today}`)) {
const scene = key.replace(`_${today}`, '');
scenes.push(scene);
}
});
return scenes;
}
/**
* 获取今日所有场景的统计信息
* @returns {Object} 所有场景的统计数据
*/
getAllTodayStats() {
const today = this.getTodayKey();
const stats = {};
this.adDataCache.forEach((value, key) => {
if (key.endsWith(`_${today}`)) {
const scene = key.replace(`_${today}`, '');
stats[scene] = {
scene: scene,
clickCount: value.clickCount,
successCount: value.successCount,
lastAdTime: value.lastAdTime
};
}
});
return stats;
}
/**
* 调试方法:显示所有缓存的数据
*/
debugShowAllData() {
this.log('=== IAA SDK 缓存数据调试信息 ===');
this.log('插件初始化状态:', this.isInitialized);
this.log('最近场景:', this.recentScene);
this.log('最近场景时间:', this.recentSceneTime ? new Date(this.recentSceneTime).toLocaleString() : '无');
this.log('缓存数据数量:', this.adDataCache.size);
this.log('可用场景:', this.getAllAvailableScenes());
this.log('今日统计:', this.getAllTodayStats());
if (this.adDataCache.size === 0) {
this.log('缓存中没有任何数据');
} else {
this.adDataCache.forEach((value, key) => {
this.log(`缓存键: ${key}`, value);
});
}
this.log('=== 调试信息结束 ===');
}
/**
* 快速状态检查
*/
quickStatus() {
const status = {
initialized: this.isInitialized,
recentScene: this.recentScene,
recentSceneTime: this.recentSceneTime,
availableScenes: this.getAllAvailableScenes(),
todayStats: this.getAllTodayStats()
};
this.log('IAA SDK 快速状态:', status);
return status;
}
// ============ 工具方法 ============
getTodayKey() {
const now = new Date();
return `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
}
getGiftScene(scene) {
const sceneMap = {
'game_revive': '复活场景',
'get_power': '获取体力',
'game_use_prop': '游戏道具',
'unlock_theme': '解锁主题',
'signin_reward': '签到奖励',
'level_reward': '通关奖励',
'daily_reward': '每日奖励'
};
return sceneMap[scene] || '其他场景';
}
getGiftName(scene, data) {
if (scene === 'game_revive') {
return '复活道具';
} else if (scene === 'get_power') {
return '体力道具';
} else if (scene === 'game_use_prop') {
return data && data.propType ? `${data.propType}道具` : '通用道具';
} else if (scene === 'default'){
return data && data.type ? `${data.type}` : '其他视频';
}
return '游戏道具';
}
savePredictionResult(scene, result) {
try {
const key = `iaa_prediction_${scene}`;
wx.setStorageSync(key, JSON.stringify(result));
} catch (e) {
this.log('保存预测结果异常:', e, 'error');
}
}
saveToStorage() {
try {
const dataToSave = {};
this.adDataCache.forEach((value, key) => {
dataToSave[key] = value;
});
wx.setStorageSync('iaa_ad_cache', JSON.stringify(dataToSave));
} catch (e) {
this.log('保存广告缓存异常:', e, 'warn');
}
}
loadFromStorage() {
try {
const stored = wx.getStorageSync('iaa_ad_cache');
if (stored) {
const data = JSON.parse(stored);
Object.keys(data).forEach(key => {
this.adDataCache.set(key, data[key]);
});
}
} catch (e) {
this.log('加载广告缓存异常:', e, 'warn');
}
// 加载最近场景信息
this.loadRecentScene();
}
saveRecentScene() {
try {
const recentSceneData = {
scene: this.recentScene,
time: this.recentSceneTime
};
wx.setStorageSync('iaa_recent_scene', JSON.stringify(recentSceneData));
this.log(`保存最近场景: ${this.recentScene}`);
} catch (e) {
this.log('保存最近场景异常:', e, 'warn');
}
}
loadRecentScene() {
try {
const stored = wx.getStorageSync('iaa_recent_scene');
if (stored) {
const recentSceneData = JSON.parse(stored);
this.recentScene = recentSceneData.scene;
this.recentSceneTime = recentSceneData.time;
this.log(`加载最近场景: ${this.recentScene}, 时间: ${new Date(this.recentSceneTime).toLocaleString()}`);
}
} catch (e) {
this.log('加载最近场景异常:', e, 'warn');
}
}
log(message, data = '', level = 'info') {
if (!this.config.enableDebugLog) return;
const prefix = '[IAA-SDK]';
if (level === 'error') {
console.error(prefix, message, data);
} else if (level === 'warn') {
console.warn(prefix, message, data);
} else {
console.log(prefix, message, data);
}
}
}
// 创建全局实例
const iaaSDK = new IAA_SDK();
// 加载存储的数据
iaaSDK.loadFromStorage();
// 导出方式1:模块导出
module.exports = {
default: iaaSDK,
IAA_SDK: IAA_SDK
};
// 导出方式2:挂载到全局(类似OceanOld)
if (typeof window !== 'undefined') {
window.IAASDK = {
default: iaaSDK
};
}