You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:25:35