import { IAdsInitParams, IAdConfigParams, IAdBreakParams, IAdUnitParams, JoliboxAdsForGame, IPlacementInfo } from '@jolibox/ads'; import { IAdsHandler } from '../ads'; import { track } from '../../report'; enum HuaweiQuickAdsEventEnum { INIT = 'huawei_quick_ads_init', AD_CONFIG = 'huawei_quick_ads_ad_config', AD_BREAK = 'huawei_quick_ads_ad_break', AD_UNIT = 'huawei_quick_ads_ad_unit', AD_OPERATION = 'huawei_quick_ads_ad_operation' } enum HuaweiQuickAdsOnMessageEventEnum { INIT = 'huawei_quick_ads_on_message_init', AD_CONFIG = 'huawei_quick_ads_on_message_ad_config', AD_BREAK = 'huawei_quick_ads_on_message_ad_break', AD_UNIT = 'huawei_quick_ads_on_message_ad_unit' } interface HuaweiQuickAdsEventMap { [HuaweiQuickAdsEventEnum.INIT]: IAdsInitParams | undefined; [HuaweiQuickAdsEventEnum.AD_CONFIG]: IAdConfigParams; [HuaweiQuickAdsEventEnum.AD_BREAK]: IAdBreakParams; [HuaweiQuickAdsEventEnum.AD_UNIT]: IAdUnitParams; [HuaweiQuickAdsEventEnum.AD_OPERATION]: undefined; } // 通用事件接口 interface HuaweiQuickAdsEvent { type: T; data?: HuaweiQuickAdsEventMap[T]; } interface HuaweiQuickAdsCallbackMap { onReady?: () => void; adBreakDone?: (placementInfo: IPlacementInfo) => void; beforeAd?: () => void; afterAd?: () => void; beforeReward?: (showAdFn: () => void) => void; adDismissed?: () => void; adViewed?: () => void; breakType?: string; breakName?: string; breakFormat?: 'interstitial' | 'reward'; } export default class HuaweiQuickAdsHandler implements IAdsHandler { private static instance: HuaweiQuickAdsHandler; private callbacksId: number; private callbackMap: Map; private constructor() { this.callbacksId = 0; this.callbackMap = new Map(); this.initOnMessage(); } public static getInstance(): HuaweiQuickAdsHandler { if (!HuaweiQuickAdsHandler.instance) { HuaweiQuickAdsHandler.instance = new HuaweiQuickAdsHandler(); } return HuaweiQuickAdsHandler.instance; } private initOnMessage() { window.addEventListener('message', (event) => { // const { data, origin, source } = event; console.log(`HuaweiQuickAdsHandler,event => ${event}`); if (event.origin != window.location.origin) return; // console.log(`data => ${event.data}`); if (event.data && event.data.type == null) { const data = JSON.parse(event.data); console.log(`HuaweiQuickAdsHandler type => ${data.type}`); switch (data.type) { case HuaweiQuickAdsOnMessageEventEnum.INIT: console.log('HuaweiQuickAdsHandler window.addEventListener init', data); break; case HuaweiQuickAdsOnMessageEventEnum.AD_CONFIG: { const callbackId = data.callbackId; if (callbackId) { const callbacks = this.callbackMap.get(callbackId); callbacks?.onReady?.(); } console.log('HuaweiQuickAdsHandler window.addEventListener adConfig', data); } break; case HuaweiQuickAdsOnMessageEventEnum.AD_BREAK: { const callbackId = data.callbackId; if (callbackId) { const callbacks = this.callbackMap.get(callbackId); let adsRes: | 'notReady' | 'timeout' | 'error' | 'noAdPreloaded' | 'frequencyCapped' | 'ignored' | 'other' | 'dismissed' | 'viewed' = 'noAdPreloaded'; let isBreakDone = false; switch (data.adsRes) { case 'viewed': adsRes = 'viewed'; callbacks?.adViewed?.(); isBreakDone = false; break; case 'dismissed': adsRes = 'dismissed'; callbacks?.adDismissed?.(); isBreakDone = false; break; case 'notReady': case 'timeout': case 'error': case 'noAdPreloaded': case 'frequencyCapped': case 'ignored': case 'other': adsRes = data.adsRes; isBreakDone = true; break; case 'breakDone': adsRes = data.params; isBreakDone = true; break; case 'beforeReward': callbacks?.beforeReward?.(() => { // this.sendPostMessage(HuaweiQuickAdsEventEnum.AD_OPERATION, undefined, undefined); window.system.postMessage( JSON.stringify({ type: HuaweiQuickAdsEventEnum.AD_OPERATION }) ); console.log('HuaweiQuickAdsHandler beforeReward postMessage AD_OPERATION'); }); isBreakDone = false; break; case 'beforeAd': track('HuaweiQuickAdsAdBreakBeforeAd', { type: 'beforeAd', format: callbacks?.breakType === 'reward' ? 'reward' : 'interstitial' }); callbacks?.beforeAd?.(); isBreakDone = false; break; case 'afterAd': callbacks?.afterAd?.(); isBreakDone = false; break; } isBreakDone && callbacks?.adBreakDone?.({ breakType: callbacks.breakType ?? '', breakName: callbacks.breakName, breakFormat: callbacks.breakFormat ?? 'interstitial', breakStatus: adsRes }); } console.log('HuaweiQuickAdsHandler window.addEventListener adBreak', data); } break; case HuaweiQuickAdsOnMessageEventEnum.AD_UNIT: console.log('HuaweiQuickAdsHandler window.addEventListener adUnit', data); break; default: break; } } }); } getAdsInstance(): JoliboxAdsForGame { return HuaweiQuickAdsHandler.getInstance() as unknown as JoliboxAdsForGame; } init(config?: IAdsInitParams): void { try { this.sendPostMessage(HuaweiQuickAdsEventEnum.INIT, undefined, config); } catch (e) { console.error('init failed', e); } } adConfig(params: IAdConfigParams): void { try { let callbackId = undefined; if (params.onReady) { callbackId = ++this.callbacksId; this.callbackMap.set(callbackId, { onReady: params.onReady }); } this.sendPostMessage(HuaweiQuickAdsEventEnum.AD_CONFIG, callbackId, params); } catch (e) { console.error('adConfig failed', e); } } adBreak(params: IAdBreakParams): void { try { const callbackId = ++this.callbacksId; const callbacks: HuaweiQuickAdsCallbackMap = {}; callbacks.breakType = params.type; if (params.type !== 'preroll' && params.name) callbacks.breakName = params.name; callbacks.breakFormat = params.type === 'reward' ? 'reward' : 'interstitial'; if (params.adBreakDone) callbacks.adBreakDone = params.adBreakDone; if (params.type !== 'preroll' && params.beforeAd) callbacks.beforeAd = params.beforeAd; if (params.type !== 'preroll' && params.afterAd) callbacks.afterAd = params.afterAd; if (params.type === 'reward' && params.beforeReward) callbacks.beforeReward = params.beforeReward; if (params.type === 'reward' && params.adDismissed) callbacks.adDismissed = params.adDismissed; if (params.type === 'reward' && params.adViewed) callbacks.adViewed = params.adViewed; this.callbackMap.set(callbackId, callbacks); track('HuaweiQuickAdsAdBreak', { type: params.type, format: params.type === 'reward' ? 'reward' : 'interstitial' }); this.sendPostMessage(HuaweiQuickAdsEventEnum.AD_BREAK, callbackId, params); } catch (e) { params.adBreakDone?.({ breakType: params.type, breakName: params.type === 'preroll' ? undefined : params.name, breakFormat: params.type === 'reward' ? 'reward' : 'interstitial', breakStatus: 'noAdPreloaded' }); } } adUnit(params: IAdUnitParams): void { try { this.sendPostMessage(HuaweiQuickAdsEventEnum.AD_UNIT, undefined, params); } catch (e) { console.error('adUnit failed', e); } } private sendPostMessage( type: T, callbackId?: number, data?: HuaweiQuickAdsEventMap[T] ): void { try { if (!window.system?.postMessage) { throw new Error('window.system.postMessage is not available'); } const message: HuaweiQuickAdsEvent = { type, ...(callbackId !== undefined && { callbackId }), ...(data !== undefined && { data }) }; window.system.postMessage(JSON.stringify(message)); } catch (e) { console.error('sendPostMessage failed', e); throw e; } } }