SwiftUI集成AdMob插页广告仅iOS 16崩溃问题排查与修复
崩溃原因与修复方案
崩溃原因
报错信息明确指出:UIViewControllerRepresentables must be value types: InterstitialAdView,说明你的InterstitialAdView是用**class(引用类型)**定义的,而SwiftUI的UIViewControllerRepresentable协议要求实现者必须是值类型(struct或enum)。iOS 15对这个规则的检查不严格,所以能正常运行,但iOS 16强化了该约束,直接触发崩溃。
修复步骤
1. 将InterstitialAdView从class改为struct
把原有的class实现替换为struct,遵循UIViewControllerRepresentable协议的要求。
2. 抽离广告状态到ObservableObject类
由于struct是值类型,无法长期持有GADInterstitialAd实例(每次视图更新都会重新创建struct实例),因此需要单独创建一个ObservableObject类来管理广告的加载、展示状态。
完整修复代码示例
广告管理类(负责广告加载与展示)
import GoogleMobileAds import SwiftUI class InterstitialAdManager: ObservableObject { @Published var isAdReady = false private var interstitialAd: GADInterstitialAd? private let adUnitId = "你的AdMob广告单元ID" // 加载插页广告 func loadAd() { GADInterstitialAd.load(withAdUnitID: adUnitId, request: GADRequest()) { [weak self] ad, error in guard let self = self else { return } if let error = error { print("插页广告加载失败: \(error.localizedDescription)") self.isAdReady = false return } self.interstitialAd = ad self.interstitialAd?.fullScreenContentDelegate = self self.isAdReady = true } } // 展示插页广告 func showAd(from viewController: UIViewController) { guard let ad = interstitialAd, isAdReady else { print("广告未准备就绪,自动重新加载") loadAd() return } ad.present(fromRootViewController: viewController) isAdReady = false } } // 扩展实现广告全屏代理方法 extension InterstitialAdManager: GADFullScreenContentDelegate { func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) { // 广告关闭后重新加载下一条 loadAd() } func adDidFailToPresentFullScreenContent(_ ad: GADFullScreenPresentingAd, error: Error) { print("广告展示失败: \(error.localizedDescription)") isAdReady = false loadAd() } }
正确的UIViewControllerRepresentable实现(struct)
import SwiftUI import GoogleMobileAds struct InterstitialAdView: UIViewControllerRepresentable { @ObservedObject var adManager: InterstitialAdManager func makeUIViewController(context: Context) -> UIViewController { // 仅作为承载广告的空视图控制器,实际展示逻辑由adManager处理 UIViewController() } func updateUIViewController(_ uiViewController: UIViewController, context: Context) { // 无需额外更新逻辑,广告展示由外部事件触发 } }
在SwiftUI视图中使用
struct ContentView: View { @StateObject private var adManager = InterstitialAdManager() var body: some View { VStack(spacing: 20) { Button("展示插页广告") { // 获取当前根视图控制器用于展示广告 guard let rootVC = UIApplication.shared.connectedScenes .compactMap({ $0 as? UIWindowScene }) .first?.windows .first?.rootViewController else { return } adManager.showAd(from: rootVC) } .disabled(!adManager.isAdReady) // 放置广告视图容器(不影响布局) InterstitialAdView(adManager: adManager) .frame(width: 0, height: 0) } .onAppear { // 页面加载时初始化广告 adManager.loadAd() } } }
额外注意事项
- 确保
Google-Mobile-Ads-SDK版本兼容iOS 16(你当前使用的9.11.0版本是支持的) - 广告单元ID需替换为你在AdMob后台创建的真实ID
- 避免在
InterstitialAdView的struct中直接持有GADInterstitialAd实例,防止值类型更新导致状态丢失
内容的提问来源于stack exchange,提问作者Pandruz
相关产品推荐
相关产品推荐

