260 lines
6.0 KiB
Markdown
260 lines
6.0 KiB
Markdown
# "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 展示频率限制
|
||
**解决方案:** 自动重新加载 + 轮换展示
|