You need to enable JavaScript to run this app. Swift中Admob插页式广告回调触发不稳定 脱离Xcode运行时完全失效
优惠活动
大模型
产品
解决方案
定价
更多

Swift中Admob插页式广告回调触发不稳定 脱离Xcode运行时完全失效

核心故障原因分析

1. 广告管理类的生命周期持有失效

  • 你将Interstitial(引用类型)直接作为SwiftUI值类型View的成员变量,且没有通过@StateObject做长期强引用。SwiftUI的View是值语义,每次视图重绘、视图销毁时,这个引用类型成员的强引用会随View实例一起释放,导致Interstitial实例在广告加载完成、回调触发前就被系统回收——对象回收后,原本作为GADFullScreenContentDelegate的回调自然无法执行,通知也无法发送。
  • 这种生命周期的不稳定性,直接导致了回调“时灵时不灵”的现象。

2. 脱离Xcode环境时,线程违规导致回调静默失效

  • 谷歌AdMob的所有广告相关回调,默认是在后台线程触发的。你直接在回调方法里postUserClosedAd通知,没有切换到主线程执行;而SwiftUI的.onReceive修饰符要求必须在主线程处理视图状态更新。
  • 当连接Xcode调试时,系统会对后台线程触发的UI操作做拦截提示,但不会直接中断流程;当脱离Xcode环境时,这种跨线程的状态更新会直接触发运行时崩溃,且崩溃发生在后台线程、没有用户可见的异常提示,就会表现为“回调完全不生效”。

3. SwiftUI App生命周期下的根视图获取逻辑失效

  • 你使用的UIApplication.shared.windows.first?.rootViewController是基于UIKit生命周期、SceneDelegate管理window的旧实现,在纯SwiftUI App生命周期下,这个API在iOS15+已经被标记废弃,多数场景下返回值为nil。
  • 当获取到的根视图控制器为nil时,你代码中的root!强解包会直接触发崩溃;即便没有解包崩溃,广告的present操作也因为没有有效的锚点视图控制器完全无法执行,自然不会触发后续的广告展示、关闭回调。

4. 通知订阅的生命周期缺失

  • 你在View结构体中直接创建NotificationCenter.default.publisher(...)实例,没有将对应的Combine订阅通过AnyCancellable做长期持有。由于SwiftUI View是值类型,每次视图重绘时这个publisher实例会被重新创建,之前的订阅会立即被释放,导致通知post出去后根本没有有效的订阅者接收,.onReceive的回调逻辑自然无法触发。

5. 冗余协议继承带来的额外风险

  • 你让Interstitial类遵循UIApplicationDelegate协议,但这个类本身并不是App的代理实现(App代理是SwiftUI App入口的类型),多余的协议遵循会导致类的方法调用链出现异常,进一步降低回调的稳定性。
针对性修正方向
  • 将Interstitial改造为遵循ObservableObject的类,在View中通过@StateObject修饰符持有实例,确保SwiftUI对这个对象的长期强引用,避免对象被提前回收。
  • 所有广告回调、状态变更逻辑,统一通过DispatchQueue.main.async切换到主线程执行,禁止在后台线程做视图操作、状态更新。
  • 替换根视图控制器的获取逻辑:通过遍历当前活跃的UIWindowScene,找到对应场景的keyWindow获取其根视图控制器,去掉强解包,对nil场景做兜底处理。
  • 去掉跨层的NotificationCenter通信,改用@Published属性在Interstitial类中对外暴露广告的加载、关闭、展示状态,让View直接订阅这个状态值,从根源上避免通知发/收不匹配的问题。
  • 移除Interstitial类上冗余的UIApplicationDelegate协议遵循,减少不必要的协议方法依赖。

内容的提问来源于stack exchange,提问作者Onnwen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 06:15:02