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

260 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# "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`
```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`
```swift
// 跳过状态为6展示失败的广告
if ad.status == 6 {
NSLog("跳过展示失败的广告,等待重新加载")
continue
}
// 继续尝试其他广告
if (ad.status == 2 && ad.ecpm >= adbrush_ecpm) {
let showResult = ad.show(...)
if !showResult {
continue // 尝试下一个
}
}
```
### 3. 广告关闭后自动尝试展示下一个
```swift
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" 频繁出现,可以:
```swift
// 在 bbbAdManager.swift 中
let kOpenADPerSec: CGFloat = 2 // 从1改为2降低尝试频率
```
### 2. 调整重新加载延迟
```swift
// 在 IronSourceinterstitialAd.swift 中
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { // 从1秒改为2秒
self.load()
}
```
### 3. 添加展示间隔限制
```swift
// 记录最后展示时间
var lastShowTime: Date?
// 检查是否满足展示间隔
if let lastTime = lastShowTime,
Date().timeIntervalSince(lastTime) < 30 { // 30秒内不重复展示
NSLog("距离上次展示不足30秒跳过")
continue
}
```
## 📝 状态码说明(更新)
| Status | 含义 | 后续动作 |
|--------|------|---------|
| 0 | 初始 | 等待开始加载 |
| 1 | 加载中 | 等待加载完成 |
| 2 | 加载完成 | **可以展示** ✓ |
| 3 | 展示中 | 等待关闭 |
| 4 | 已关闭 | 可以重新加载 |
| 5 | 加载失败 | 需要重新加载 |
| 6 | 展示失败 | **自动重新加载** ← 新增 |
## 🎁 额外改进
### 展示成功率统计
可以添加统计代码:
```swift
// 在 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 展示频率限制
**解决方案:** 自动重新加载 + 轮换展示