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.
AdLike2048/assets/script/sdk/functions/InterstitialAd.ts

173 lines
5.2 KiB

3 weeks ago
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?.();
}
}