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

SwiftUI中展示GADInterstitialAd时如何避免MainView重载

解决SwiftUI展示插页广告时MainView重载的问题

问题根源在于你使用fullScreenCover的方式——SwiftUI的全屏模态展示会强制触发底层MainView的onDisappear回调,关闭广告后又会触发onAppear,这是模态视图的默认生命周期行为。要避免视图重载,你可以直接在UIKit层级从MainView对应的UIViewController展示广告,完全绕过SwiftUI的模态修饰符。

具体实现方案

1. 桥接SwiftUI与UIKit,获取当前视图控制器引用

创建一个隐藏的桥接视图,用来在SwiftUI中拿到对应的UIKit视图控制器实例:

struct ViewControllerHolder: UIViewControllerRepresentable {
    @Binding var viewController: UIViewController?
    
    func makeUIViewController(context: Context) -> UIViewController {
        UIViewController()
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        DispatchQueue.main.async {
            // 获取当前SwiftUI视图对应的父级UIViewController
            self.viewController = uiViewController.parent
        }
    }
}

2. 封装广告管理逻辑

把广告加载、展示的逻辑单独封装成一个可观察对象,方便在SwiftUI中调用:

import GoogleMobileAds

class InterstitialAdManager: ObservableObject {
    private(set) var interstitialAd: GADInterstitialAd?
    
    // 加载插页广告
    func loadAd(withUnitID unitID: String) {
        GADInterstitialAd.load(withAdUnitID: unitID, request: GADRequest()) { ad, error in
            if let error = error {
                print("广告加载失败: \(error.localizedDescription)")
                return
            }
            self.interstitialAd = ad
            print("广告加载完成")
        }
    }
    
    // 直接从指定视图控制器展示广告
    func showAd(from viewController: UIViewController?, completion: @escaping () -> Void) {
        guard let vc = viewController, let ad = interstitialAd else {
            print("广告未准备就绪或无可用视图控制器")
            completion()
            return
        }
        
        ad.present(fromRootViewController: vc)
        completion()
        print("广告已展示")
        // 广告展示后清空引用,下次需重新加载
        self.interstitialAd = nil
    }
}

3. 在MainView中集成使用

不再依赖fullScreenCover,直接通过广告管理器展示广告:

struct MainView: View {
    @StateObject private var adManager = InterstitialAdManager()
    @State private var currentViewController: UIViewController?
    
    var body: some View {
        // 你的主视图内容
        VStack(spacing: 20) {
            Text("主视图核心内容")
                .font(.title)
            
            Button("展示插页广告") {
                adManager.showAd(from: currentViewController) {
                    // 广告展示完成后的后续逻辑
                }
            }
            .buttonStyle(.borderedProminent)
        }
        .onAppear {
            // 页面加载时预加载广告
            adManager.loadAd(withUnitID: "你的广告单元ID")
        }
        // 嵌入桥接视图,悄悄获取当前UIViewController引用
        .background(ViewControllerHolder(viewController: $currentViewController))
    }
}

方案优势说明

直接调用UIKit的present方法展示广告,完全绕过了SwiftUI的模态视图机制,MainView不会感知到广告的展示/关闭,自然不会触发onDisappear和onAppear回调,也就避免了视图重载问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 14:16:21