import { MiniGamePf } from '../../../mx/tools/MiniGameHostInfo'; /** 插屏广告实例 */ interface InterstitialAdInst { load?: () => Promise; show: () => Promise; destroy?: () => void; onClose?: (cb: () => void) => void; onError?: (cb: (err: unknown) => void) => void; offClose?: (cb: () => void) => void; offError?: (cb: (err: unknown) => void) => void; } /** * 插屏广告。快手无 load,每次 create 新实例;iOS 不支持(-10005)。 */ export class InterstitialAd { private static _keys: string[] = []; private static _pt: Record | null = null; private static _pf: ReturnType = null; private static _ad: InterstitialAdInst | null = null; private static _onAdClose: Function | undefined; private static _onFail: Function | undefined; private static _onSuccess: Function | undefined; private static _done = false; /** 初始化广告位 */ static init(keys: string[]): void { this._keys = keys?.filter(Boolean) ?? []; this._pf = MiniGamePf.id(); this._pt = MiniGamePf.api(); } /** * 展示插屏。快手直接 show;其余有 load 则先 load。 * @param onAdClose 用户关闭 * @param onFail 加载/展示失败(含频控、iOS 不支持) * @param onSuccess 展示成功 */ static showInterstitialAd(onAdClose?: Function, onFail?: Function, onSuccess?: Function): void { this._onAdClose = onAdClose; this._onFail = onFail; this._onSuccess = onSuccess; this._done = false; if (this._pt == null) { onAdClose?.(true); return; } if (this._keys.length === 0) { onAdClose?.(false); return; } const createFn = this._pt.createInterstitialAd as ((opts: { adUnitId: string }) => InterstitialAdInst) | undefined; if (!createFn) { console.warn('[InterstitialAd] createInterstitialAd 不支持'); onFail?.(); return; } const keyIndex = Math.floor(Math.random() * this._keys.length); let ad: InterstitialAdInst | null = null; try { ad = createFn({ adUnitId: this._keys[keyIndex] }) ?? null; } catch (e) { console.warn('[InterstitialAd] create 失败', String(e)); onFail?.(); return; } if (!ad?.show) { console.warn('[InterstitialAd] 实例无效'); onFail?.(); return; } this._ad = ad; ad.onClose?.(this._handleClose); ad.onError?.(this._handleError); if (this._pf !== 'ks' && typeof ad.load === 'function') { const loadRet = ad.load(); if (loadRet && typeof loadRet.then === 'function') { loadRet.then(this._handleLoadOk).catch(this._handleLoadFail); return; } } this._showAd(); } /** 用户关闭插屏 */ private static _handleClose = (): void => { InterstitialAd._finishClose(); }; /** 插屏错误 */ private static _handleError = (err: unknown): void => { console.log('[InterstitialAd] onError', String(err)); InterstitialAd._finishFail(); }; /** load 成功后 show */ private static _handleLoadOk = (): void => { InterstitialAd._showAd(); }; /** load 失败 */ private static _handleLoadFail = (err: unknown): void => { console.log('[InterstitialAd] load 失败', String(err)); InterstitialAd._finishFail(); }; /** show 成功 */ private static _handleShowOk = (): void => { InterstitialAd._onSuccess?.(); }; /** show 失败(频控 / iOS -10005) */ private static _handleShowFail = (err: unknown): void => { const rec = err as { code?: number; errCode?: number }; const code = rec?.code ?? rec?.errCode; if (code === -10005) { console.warn('[InterstitialAd] 当前版本不支持插屏(如 iOS)', String(err)); } else { console.log('[InterstitialAd] show 失败', String(err)); } InterstitialAd._finishFail(); }; /** 调用 show */ private static _showAd(): void { const ad = this._ad; if (!ad?.show) { this._finishFail(); return; } const ret = ad.show(); if (ret && typeof ret.then === 'function') { ret.then(this._handleShowOk).catch(this._handleShowFail); } } /** 解绑并 destroy */ private static _unbind(): void { const ad = this._ad; if (!ad) return; ad.offClose?.(this._handleClose); ad.offError?.(this._handleError); try { ad.destroy?.(); } catch { /* ignore */ } this._ad = null; } /** 关闭完成 */ private static _finishClose(): void { if (this._done) return; this._done = true; this._unbind(); this._onAdClose?.(); } /** 失败完成 */ private static _finishFail(): void { if (this._done) return; this._done = true; this._unbind(); this._onFail?.(); } }