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
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
|
|
};
|
|
}
|