【BUG反馈】关于部分ios用户看广告会白屏的反馈报告
04/13145 浏览
iOS 激励广告白屏问题报告
游戏: 全村最好的剑
报告日期: 2026-04-13
════════════════════════════════════════════════════════════════
【问题描述】
用户在 iOS 设备上观看激励广告后,游戏画面变为白屏,无法恢复操作,只能强制杀进程重启。问题在同一设备上稳定复现,单次会话中观看 1~4 次广告后均可能触发。
【环境信息】
设备: iPhone 13
系统: iOS 17.5.1
引擎运行时: SCE runtime 2.15.0
游戏引擎: UrhoX (NanoVG 渲染)
广告调用方式: sdk.ShowRewardVideoAd()
广告场景: shop_ad_short / shop_free
【复现步骤】
1. 进入游戏 → 商店页面
2. 点击观看广告获取奖励
3. 单次会话中观看 1~4 次广告后触发(不固定)
4. 广告结束后画面变白,无法操作,只能强制退出
════════════════════════════════════════════════════════════════
【排查过程】
我们通过在 Lua 层植入持久化诊断日志(写入文件,下次启动时上报),进行了 3 轮渐进式排查,共收集 5 份白屏反馈。
---- 第一轮:每帧 GL blend 状态自愈(version=1)----
假设: NanoVG 渲染的 GL blend 状态被广告 SDK 破坏,导致后续绘制全白。
措施:
- 植入持久化诊断日志,记录 APP_START、AD_START、AD_CALLBACK 时间戳
- 在 NanoVGRender 事件中增加每帧 glBlendFunc 重置
结果: 白屏仍然发生(feedback_1236 证明),排除了 GL blend 状态假设。
---- 第二轮:墙钟超时 + 心跳诊断(version=3)----
假设: 引擎主循环(HandleUpdate)在广告展示期间可能被暂停,导致基于帧 dt 累加的超时计时器无法工作。
措施:
- 使用 os.time() 记录广告开始的墙钟时间
- HandleUpdate 中添加心跳日志 AD_HEARTBEAT(广告期间每 3 秒写入一条)
- 墙钟超时 10 秒 + 帧累加超时 8 秒双重保护
结果: feedback_1238 中无任何 AD_HEARTBEAT 日志,证明 HandleUpdate 在广告期间完全没有被调用。
════════════════════════════════════════════════════════════════
【5 份反馈日志详细分析】
---- feedback_1234 ——"白屏"(无诊断版本)----
预诊断构建,无 version 标记。仅包含正常启动日志,无上次会话记录。
确认白屏问题存在,但无诊断数据。
---- feedback_1235 ——"白屏02"(version=1)----
上次会话日志:
21:39:06 APP_START version=1
21:39:20 AD_START scene=shop_ad_short state=mainmenu
21:40:10 AD_CALLBACK scene=shop_ad_short success=true ← 第1次广告成功
21:40:16 AD_START scene=shop_ad_short state=mainmenu
21:40:48 AD_CALLBACK scene=shop_ad_short success=true ← 第2次广告成功
21:40:59 AD_START scene=shop_ad_short state=mainmenu
21:41:40 AD_CALLBACK scene=shop_ad_short success=true ← 第3次广告成功
21:41:52 AD_START scene=shop_ad_short state=mainmenu ← 第4次广告开始
(无 AD_CALLBACK —— 白屏,用户强退)
结论: 前 3 次广告正常,第 4 次 AD_START 后无回调,广告 SDK 未触发 callback。
---- feedback_1236 ——"白屏03"(version=1,含每帧 GL 自愈)----
上次会话日志:
21:52:25 APP_START version=1
21:52:33 AD_START scene=shop_ad_short state=mainmenu ← 第1次广告开始
(无 AD_CALLBACK —— 白屏,用户强退)
结论: 首次广告即白屏。此版本已包含每帧 GL blend 修复,仍然无效。
排除了 GL 状态被污染的假设。
---- feedback_1237 ——"白屏04"(version=1)----
上次会话日志:
22:05:29 APP_START version=1
22:05:38 AD_START scene=shop_ad_short state=mainmenu
22:06:17 AD_CALLBACK scene=shop_ad_short success=true ← 第1次广告成功
22:06:20 AD_START scene=shop_free state=mainmenu ← 第2次广告开始
(无 AD_CALLBACK —— 白屏,用户强退)
结论: 第 1 次成功,第 2 次 AD_START 后无回调。
---- feedback_1238 ——"白屏05"(version=3,关键证据)----
上次会话日志:
22:18:26 APP_START version=3 ← 确认最新诊断版本
22:18:34 AD_START scene=shop_free state=mainmenu ← 第1次广告开始
(无 AD_HEARTBEAT —— HandleUpdate 未运行)
(无 AD_RECOVER —— 墙钟超时未触发)
(无 AD_TIMEOUT —— 帧累加超时未触发)
(无 AD_CALLBACK —— 白屏,用户 22:19:09 强退重启)
关键分析:
- 从 AD_START(22:18:34) 到用户重启(22:19:09),间隔 35 秒,远超 10 秒墙钟超时阈值
- version=3 的心跳诊断设计:AD_START 后每 3 秒在 HandleUpdate 中写入 AD_HEARTBEAT
35 秒内应有约 11 条心跳日志
- 实际结果:0 条心跳日志
- 结论:AD_START 之后 HandleUpdate 完全没有被调用,引擎主循环被广告 SDK 阻塞
════════════════════════════════════════════════════════════════
【证据链总结】
feedback_1234 → 确认白屏问题存在(无诊断数据)
↓
feedback_1235 → AD_START 后无 AD_CALLBACK,确认广告回调丢失
↓
feedback_1236 → 每帧 GL blend 修复无效,排除 GL 状态假设
↓
feedback_1237 → 再次确认 AD_START 后回调丢失模式
↓
feedback_1238 → 墙钟超时 + 心跳诊断均未触发
→ 确认 HandleUpdate 在广告期间完全被阻塞
→ 确认问题在引擎/SDK 原生层,非 Lua 层可修
════════════════════════════════════════════════════════════════
【根因结论】
调用 sdk.ShowRewardVideoAd() 后,广告 SDK 在 iOS 上弹出原生 UIViewController(全屏覆盖游戏画面)。此时:
1. 引擎的主循环(HandleUpdate / NanoVGRender 等事件)完全停止执行
2. 广告 SDK 的 ViewController 在某些情况下未能正确 dismiss
3. SDK 的 reward callback(success/fail)未被触发
4. 游戏画面被广告 SDK 的白色 ViewController 覆盖,用户看到白屏
5. 由于引擎主循环被阻塞,Lua 层的所有超时检测、心跳诊断、GL 恢复逻辑均无法执行
已排除的方案:
每帧 GL blend 状态重置
→ 失败原因: 问题不是 GL 状态被污染,而是引擎主循环整体被阻塞
帧累加超时(HandleUpdate 中 dt 累加)
→ 失败原因: HandleUpdate 不运行,timer 不推进
墙钟超时(os.time 检测)
→ 失败原因: HandleUpdate 不运行,检测代码不执行
心跳诊断
→ 失败原因: 确认了 HandleUpdate 不运行,但无法作为解决方案
此问题无法从 Lua 游戏代码层面解决。所有 Lua 层的恢复机制都依赖于引擎主循环(HandleUpdate)被调用,而在白屏发生时主循环已被完全阻塞。
════════════════════════════════════════════════════════════════
【建议排查方向】
1. 广告 SDK 的 ViewController 生命周期管理
iOS 上 ShowRewardVideoAd 弹出的 ViewController 是否正确处理了 dismiss?
ViewController dismiss 失败时是否有 fallback 机制?
2. 引擎主循环与广告 ViewController 的关系
广告 ViewController 展示期间,引擎的 CADisplayLink / RunLoop 是否被暂停?
是否可以在原生层(ObjC/Swift)增加 watchdog 计时器,独立于引擎主循环检测广告超时?
3. 广告回调的可靠性
SDK 的 reward callback 是否存在已知的丢失场景?
是否存在广告加载失败但未触发 failure callback 的边界情况?
4. 建议的原生层解决方案
在原生层(独立于引擎主循环)启动 dispatch_after 或 NSTimer,
检测广告 ViewController 是否在合理时间内 dismiss。
如果超时,原生层主动 dismiss ViewController 并触发失败回调,
确保引擎主循环在广告结束后能正确恢复。
以上分析来自塔拉拉的排查报告,希望天哥能帮忙看看!
对话链接:TapTap 制造 (测试时间在4/12号晚上,对话比较长需要往上翻一些)


