6.0 KiB
6.0 KiB
"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 通常表示:
-
广告展示频率限制
- SDK 有频率控制(如:同一广告 X 分钟内只能展示一次)
- 该广告最近刚展示过
-
广告已过期
- 虽然
isAdReady()返回 true - 但在调用
showAd()时广告已失效 - Load 到 Show 的时间间隔过长
- 虽然
-
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)%")
✅ 总结
现在的系统能够:
- ✅ 捕获所有展示失败
- ✅ 自动重新加载失败的广告
- ✅ 自动尝试其他可用广告
- ✅ 完整的日志追踪
- ✅ 自动轮换展示机制
重新编译运行后,即使某个广告展示失败,系统也会:
- 立即尝试展示其他广告
- 在后台重新加载失败的广告
- 下一轮继续尝试
这样大大提高了广告展示的成功率!🎉
修复时间: 2025-01-04
问题类型: SDK 展示频率限制
解决方案: 自动重新加载 + 轮换展示