快手小程序-实现插屏广告的功能

快手小程序-实现插屏广告的功能

1.快手小程序插屏广告官方文档链接:https://open.kuaishou.com/docs/develop/api-next/ad/ks.createInterstitialAd.html

2.ks.getEnterOptionsSync api的官方文档链接:https://open.kuaishou.com/docs/develop/api-next/basic/app/ks.getEnterOptionsSync.html

快手官方说明调用插屏广告的时候为了用户的体验,不能一进页面就显示广告,需要获取广告显示的时间,也就是ks.getEnterOptionsSync 这个api,在这个最早显示时间之后才能进行展示广告。

直接上代码,在插屏广告的js文件中:

javascript 复制代码
let interstitialAd = null;
let appLaunchTime = 0;
let minDisplayTimestamp = 0;

page({
	async onLoad(options) {
    // 记录应用启动时间(如果还没有记录)
    if (!appLaunchTime) {
      appLaunchTime = Date.now();
    }
    // 获取启动参数中的最小展示时间
    try {
      const time = ks.getEnterOptionsSync();
      minDisplayTimestamp = time.minDisplayTimestamp || 0;
    } catch (err) {
      minDisplayTimestamp = 0;
    }
  },

  onUnload() {
    interstitialAd?.destroy();
    interstitialAd = null;
  },

  // 检查是否到达可展示时间
  checkAdDisplayTime() {
    const now = Date.now();

    // 如果 minDisplayTimestamp 存在且大于当前时间,说明还不能展示
    if (minDisplayTimestamp && minDisplayTimestamp > now) {
      const waitTime = minDisplayTimestamp - now;
      // console.log(`需要等待 ${waitTime}ms 后才能展示广告`);
      return waitTime;
    }

    // 默认最小等待时间(应用启动后至少5秒,页面加载后至少3秒)
    const minWaitAfterLaunch = 5000; // 5秒
    const timeSinceLaunch = now - appLaunchTime;

    if (timeSinceLaunch < minWaitAfterLaunch) {
      const waitTime = minWaitAfterLaunch - timeSinceLaunch;
      // console.log(`应用启动后需要等待 ${waitTime}ms`);
      return waitTime;
    }

    return 0; // 可以立即展示
  },

  // 加载插屏广告(优化版)
  adshowLoad() {
    return new Promise((resolve, reject) => {
      // 如果已有实例,先检查是否已加载
      if (interstitialAd) {
        // 尝试调用 load 确保广告已加载
        interstitialAd.load()
          .then(() => {
            // console.log('插屏广告已重新加载');
            resolve(true);
          })
          .catch((err) => {
            // console.log('插屏广告重新加载失败,创建新实例');
            // 如果加载失败,销毁旧实例,创建新的
            interstitialAd.destroy();
            interstitialAd = null;
            this.createInterstitialAd(resolve, reject);
          });
        return;
      }

      // 创建新的广告实例
      this.createInterstitialAd(resolve, reject);
    });
  },

  // 创建插屏广告实例
  createInterstitialAd(resolve, reject) {
    interstitialAd = ks.createInterstitialAd({
      type: 100033847,
      unitId: 100176781,
    });

    let isResolved = false;

    interstitialAd.onLoad(() => {
      // console.log('插屏广告加载成功');
      if (!isResolved) {
        isResolved = true;
        resolve(true);
      }
    });

    interstitialAd.onError(({ errCode, errMsg }) => {
      // console.error('插屏广告加载失败:', errCode, errMsg);
      if (!isResolved) {
        isResolved = true;
        reject(new Error(`错误码: ${errCode}, 错误信息: ${errMsg}`));
      }
    });

    interstitialAd.onClose(() => {
      // console.log('插屏广告已关闭');
      // 广告关闭后延迟销毁
      setTimeout(() => {
        if (interstitialAd) {
          interstitialAd.destroy();
          interstitialAd = null;
        }
      }, 1000);
    });

    // 显式调用 load 方法加载广告
    interstitialAd.load().catch((err) => {
      // console.error('调用 load 方法失败:', err);
      if (!isResolved) {
        isResolved = true;
        reject(err);
      }
    });
  },

  // 安全的广告展示方法
  async safeShowInterstitialAd(retryCount = 0) {
    const maxRetries = 3; // 最大重试次数
    
    try {
      // 1. 检查广告展示时机
      const waitTime = this.checkAdDisplayTime();

      if (waitTime > 0) {
        // console.log(`广告展示时机未到,等待 ${waitTime}ms`);
        await new Promise(resolve => setTimeout(resolve, waitTime));
      }

      // 2. 加上用户自定义的延迟
      // if (userDelay > 0) {
      //   console.log(`用户自定义延迟 ${userDelay}秒`);
      //   await new Promise(resolve => setTimeout(resolve, userDelay * 1000));
      // }

      // 3. 加载广告
      await this.adshowLoad();

      // 4. 广告加载成功后,再等待至少2秒(快手要求)
      const minWaitAfterLoad = 2000; // 2秒
      // console.log(`广告加载完成,等待 ${minWaitAfterLoad}ms 后展示`);
      await new Promise(resolve => setTimeout(resolve, minWaitAfterLoad));

      // 5. 再次检查时机(避免加载过程中时间变化)
      const finalCheck = this.checkAdDisplayTime();
      if (finalCheck > 0) {
        // console.log(`最终检查,还需等待 ${finalCheck}ms`);
        await new Promise(resolve => setTimeout(resolve, finalCheck));
      }

      // 6. 展示广告(捕获 show 方法的错误)
      try {
        await interstitialAd?.show();
        return true;
      } catch (showError) {
        // show 方法也可能抛出 1006 错误
        const showErrorMsg = showError.message || '';
        const showErrorCode = showError.errorCode || '';
        
        if ((showErrorCode === 1006 || showErrorMsg.includes('too early')) && retryCount < maxRetries) {
          const retryDelay = (retryCount + 1) * 3000;
          
          await new Promise(resolve => setTimeout(resolve, retryDelay));
          
          // 递归重试
          return await this.safeShowInterstitialAd( retryCount + 1);
        }
        
        // 其他错误直接抛出
        throw showError;
      }
    } catch (error) {
      console.error('展示广告失败:', error);
      
      // 检查是否是 1006 错误(时间太早)
      // const errorMsg = error.message || error.errMsg || '';
      const errorCode = error.errorCode || '';
      
      if ((errorCode === 1006) && retryCount < maxRetries) {
        const retryDelay = (retryCount + 1) * 3000; // 每次重试增加3秒延迟
   
        await new Promise(resolve => setTimeout(resolve, retryDelay));
        
        // 递归重试
        return await this.safeShowInterstitialAd( retryCount + 1);
      }

      return false;
    }
  },

  // 在你的业务逻辑中调用
  async showRewardedVideoAd() {
    // 使用安全的广告展示方法
    const success = await this.safeShowInterstitialAd();
  },
})
相关推荐
用户54277848515401 小时前
JavaScript 闭包详解:由浅入深掌握作用域与内存管理的艺术
前端
用户54277848515401 小时前
闭包在 Vue 项目中的应用
前端
TG:@yunlaoda360 云老大1 小时前
配置华为云国际站代理商OBS跨区域复制时,如何编辑委托信任策略?
java·前端·华为云
计算机毕设指导62 小时前
基于微信小程序的鸟博士系统【源码文末联系】
java·spring boot·mysql·微信小程序·小程序·tomcat·maven
周杰伦fans2 小时前
微信小程序信息提示组件大全
微信小程序·小程序
dlhto2 小时前
前端登录验证码组件
前端
@万里挑一2 小时前
vue中使用虚拟列表,封装虚拟列表
前端·javascript·vue.js
黑臂麒麟2 小时前
Electron for OpenHarmony 跨平台实战开发:Electron 文件系统操作实战
前端·javascript·electron·openharmony
wordbaby2 小时前
Tanstack Router 文件命名速查表
前端