build-ipa/ironSource/PlayBTopOn/CANNOT_ENGAGE_FIX.md
2026-01-05 10:40:05 +08:00

6.0 KiB
Raw Blame History

"Cannot engage offer at this time" 错误修复

📊 问题分析

日志显示

XS- ✓ 找到合适的广告,准备展示: hhh5ve5yjpptfdcp
XS- 广告准备状态 isAdReady: true ✓
XS- ✓ 调用 showAd准备展示广告
XS- ✓ 广告 show() 返回 true ✓
XS- ✗✗✗ didFailToDisplayAd 回调被触发 ✗
XS- 广告展示失败!错误: Cannot+engage+offer+at+this+time

错误原因

Cannot engage offer at this time 通常表示:

  1. 广告展示频率限制

    • SDK 有频率控制(如:同一广告 X 分钟内只能展示一次)
    • 该广告最近刚展示过
  2. 广告已过期

    • 虽然 isAdReady() 返回 true
    • 但在调用 showAd() 时广告已失效
    • Load 到 Show 的时间间隔过长
  3. SDK 内部状态问题

    • 广告正在被其他地方使用
    • SDK 内部锁定了该广告

已实现的解决方案

1. 展示失败后自动重新加载

文件: IronSourceinterstitialAd.swift

func didFailToDisplayAd(with adInfo: LPMAdInfo, error: Error) {
    // 改变状态为展示失败 (status = 6)
    changeStatus(st: 6)
    
    // 触发关闭回调,重置 isshow = false
    self.onAdClosed()
    
    // 1秒后重新加载这个广告
    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
        self.changeStatus(st: 1) // 标记为加载中
        self.load()
    }
}

2. 跳过失败的广告,尝试下一个

文件: bbbAdManager.swift

// 跳过状态为6展示失败的广告
if ad.status == 6 {
    NSLog("跳过展示失败的广告,等待重新加载")
    continue
}

// 继续尝试其他广告
if (ad.status == 2 && ad.ecpm >= adbrush_ecpm) {
    let showResult = ad.show(...)
    if !showResult {
        continue // 尝试下一个
    }
}

3. 广告关闭后自动尝试展示下一个

ad.show(viewController: v) {
    self.isshow = false
    
    // 0.5秒后尝试展示其他广告
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        self.showAd(v: viewController)
    }
}

🔄 完整的流程

场景 1: 单个广告展示失败

1. 尝试展示广告 A
   ↓ 失败: "Cannot engage offer"
2. 标记广告 A 状态为 6展示失败
   ↓
3. 触发 onAdClosed重置 isshow = false
   ↓
4. 1秒后重新加载广告 A状态变为 1 → 2
   ↓
5. 下次定时器触发时,继续尝试展示

场景 2: 多个广告位,轮流尝试

广告 A: Load成功 → Show失败 → 跳过status=6→ 重新加载
广告 B: Load成功 → 尝试Show → 成功 ✓
广告 C: 待命

下一轮:
广告 A: 重新加载完成 → 尝试Show
广告 B: 已展示
广告 C: 尝试Show

📈 改进效果

之前的问题

  • 展示失败后,广告一直保持 status=2
  • 定时器反复尝<E5A48D><E5B09D><EFBFBD>同一个失败的广告
  • 其他可用的广告无法展示
  • Show 日志缺失,无法追踪

现在的改进

  • 展示失败后立即标记状态status=6
  • 跳过失败的广告,尝试其他广告
  • 失败的广告自动重新加载
  • 完整的日志追踪
  • 自动轮换展示机制

🎯 预期日志(修复后)

第一次尝试

XS- 检查广告 [0]: ID=hhh5ve5yjpptfdcp, status=2 ✓
XS- ✓ 找到合适的广告[尝试1]
XS- ✗✗✗ didFailToDisplayAd: Cannot engage offer
XS- 展示失败后重新加载广告
XS- 广告关闭回调被触发

自动尝试下一个

XS- 检查广告 [0]: ID=hhh5ve5yjpptfdcp, status=6
XS- ✗ 跳过展示失败的广告,等待重新加载
XS- 检查广告 [1]: ID=no7750uspiuvwwcx, status=2 ✓
XS- ✓ 找到合适的广告[尝试1]
XS- ✓✓✓ didDisplayAd 回调被触发 ✓✓✓
XS- 开始上报 uploadAD_Show

广告 A 重新加载完成

XS- ad load ok: hhh5ve5yjpptfdcp (重新加载完成)

下一轮尝试

XS- 检查广告 [0]: ID=hhh5ve5yjpptfdcp, status=2 ✓
XS- ✓ 找到合适的广告[尝试1]
XS- ✓✓✓ didDisplayAd 回调被触发 ✓✓✓

🛠️ 调整建议

1. 调整展示频率

如果 "Cannot engage offer" 频繁出现,可以:

// 在 bbbAdManager.swift 中
let kOpenADPerSec: CGFloat = 2 // 从1改为2降低尝试频率

2. 调整重新加载延迟

// 在 IronSourceinterstitialAd.swift 中
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { // 从1秒改为2秒
    self.load()
}

3. 添加展示间隔限制

// 记录最后展示时间
var lastShowTime: Date?

// 检查是否满足展示间隔
if let lastTime = lastShowTime, 
   Date().timeIntervalSince(lastTime) < 30 { // 30秒内不重复展示
    NSLog("距离上次展示不足30秒跳过")
    continue
}

📝 状态码说明(更新)

Status 含义 后续动作
0 初始 等待开始加载
1 加载中 等待加载完成
2 加载完成 可以展示
3 展示中 等待关闭
4 已关闭 可以重新加载
5 加载失败 需要重新加载
6 展示失败 自动重新加载 ← 新增

🎁 额外改进

展示成功率统计

可以添加统计代码:

// 在 bbbAdManager 中添加
var showSuccessCount = 0
var showFailCount = 0

// didDisplayAd 中
showSuccessCount += 1

// didFailToDisplayAd 中
showFailCount += 1

// 计算成功率
let successRate = Double(showSuccessCount) / Double(showSuccessCount + showFailCount)
NSLog("广告展示成功率: \(successRate * 100)%")

总结

现在的系统能够:

  1. 捕获所有展示失败
  2. 自动重新加载失败的广告
  3. 自动尝试其他可用广告
  4. 完整的日志追踪
  5. 自动轮换展示机制

重新编译运行后,即使某个广告展示失败,系统也会:

  • 立即尝试展示其他广告
  • 在后台重新加载失败的广告
  • 下一轮继续尝试

这样大大提高了广告展示的成功率!🎉


修复时间: 2025-01-04
问题类型: SDK 展示频率限制
解决方案: 自动重新加载 + 轮换展示