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.
172 lines
5.2 KiB
172 lines
5.2 KiB
import { MiniGamePf } from '../../../mx/tools/MiniGameHostInfo';
|
|
|
|
/** 插屏广告实例 */
|
|
interface InterstitialAdInst {
|
|
load?: () => Promise<unknown>;
|
|
show: () => Promise<unknown>;
|
|
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<string, any> | null = null;
|
|
private static _pf: ReturnType<typeof MiniGamePf.id> = 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?.();
|
|
}
|
|
}
|
|
|