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

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

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();
  },
})
相关推荐
wuhen_n13 小时前
网络请求在Vite层的代理与Mock:告别跨域和后端依赖
前端·javascript·vue.js
用户693717500138418 小时前
Google 正在“收紧侧加载”:陌生 APK 安装或需等待 24 小时
android·前端
蓝帆傲亦18 小时前
Web 前端搜索文字高亮实现方法汇总
前端
用户693717500138418 小时前
Room 3.0:这次不是升级,是重来
android·前端·google
漫随流水20 小时前
旅游推荐系统(view.py)
前端·数据库·python·旅游
踩着两条虫21 小时前
VTJ.PRO 核心架构全公开!从设计稿到代码,揭秘AI智能体如何“听懂人话”
前端·vue.js·ai编程
jzlhll1231 天前
kotlin Flow first() last()总结
开发语言·前端·kotlin
用头发抵命1 天前
Vue 3 中优雅地集成 Video.js 播放器:从组件封装到功能定制
开发语言·javascript·ecmascript
蓝冰凌1 天前
Vue 3 中 defineExpose 的行为【defineExpose暴露ref变量】详解:自动解包、响应性与实际使用
前端·javascript·vue.js
奔跑的呱呱牛1 天前
generate-route-vue基于文件系统的 Vue Router 动态路由生成工具
前端·javascript·vue.js