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

如何设置根视图控制器状态栏隐藏以解决AdMob开屏广告报错?

解决SwiftUI中AdMob开屏广告状态栏无法隐藏的问题

在SwiftUI应用中集成Google AdMob开屏广告时,控制台持续抛出以下错误:

Status bar could not be hidden for full screen ad. Ensure that your app is configured to allow full screen ads to control the status bar. For example, consider whether you need to set the childViewControllerForStatusBarHidden property on your ad's rootViewController.

问题原因

SwiftUI默认使用UIHostingController作为根视图控制器,该控制器默认不会将状态栏的控制权交给子控制器(比如AdMob的广告控制器),导致开屏广告无法隐藏状态栏触发报错。

解决方案

我们需要让根视图控制器允许子控制器接管状态栏的控制权限,以下两种方式均可实现:

方式一:自定义UIHostingController子类

创建自定义的UIHostingController,重写状态栏相关属性,将控制权交给当前子控制器:

class HostingController<Content: View>: UIHostingController<Content> {
    override var childForStatusBarHidden: UIViewController? {
        presentedViewController
    }
    
    override var childForStatusBarStyle: UIViewController? {
        presentedViewController
    }
}

随后在App入口替换默认的HostingController:

@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            HostingController(rootView: ContentView())
        }
    }
}

方式二:展示广告时动态设置根控制器属性

如果不想修改根控制器类型,可在展示广告前临时给根控制器添加权限设置:
修改OpenAd类中showAdForFirstLaunch和tryToPresentAd方法的present逻辑:

// 展示广告前添加以下代码
let rootVC = UIApplication.shared.getRootViewController()
rootVC.childForStatusBarHidden = appOpenAd?.presentedViewController
rootVC.setNeedsStatusBarAppearanceUpdate()

appOpenAd?.present(fromRootViewController: rootVC)

修改后的完整代码示例

// 自定义HostingController(方式一使用)
class HostingController<Content: View>: UIHostingController<Content> {
    override var childForStatusBarHidden: UIViewController? {
        presentedViewController
    }
    
    override var childForStatusBarStyle: UIViewController? {
        presentedViewController
    }
}

// 获取根视图控制器的扩展
extension UIApplication {
    func getRootViewController() -> UIViewController {
        guard let scene = self.connectedScenes.first as? UIWindowScene else {
            return .init()
        }
                                    
        guard let root = scene.windows.first?.rootViewController else {
            return .init()
        }
                
        return root
    }
}

final class OpenAd: NSObject, GADFullScreenContentDelegate {
    var appOpenAd: GADAppOpenAd?
    var loadTime = Date()
    
    func currentDeviceOrientation() -> UIInterfaceOrientation {
        let currentOrientation = UIDevice.current.orientation
        
        switch currentOrientation {
        case .unknown:
            return .unknown
        case .portrait:
            return .portrait
        case .portraitUpsideDown:
            return .portraitUpsideDown
        case .landscapeLeft:
            return .landscapeLeft
        case .landscapeRight:
            return .landscapeRight
        case .faceUp:
            return .portrait
        case .faceDown:
            return .portrait
        @unknown default:
            return .unknown
        }
    }
    
    func showAdForFirstLaunch() {
        let request = GADRequest()
        GADAppOpenAd.load(withAdUnitID: "ca-app-pub-3940256099942544/5662855259",
                          request: request,
                          orientation: UIInterfaceOrientation.portrait,
                          completionHandler: { (appOpenAdIn, _) in
            self.appOpenAd = appOpenAdIn
            self.appOpenAd?.fullScreenContentDelegate = self
            self.loadTime = Date()
            
            // 方式二代码(使用方式一则删除这段)
            let rootVC = UIApplication.shared.getRootViewController()
            rootVC.childForStatusBarHidden = self.appOpenAd?.presentedViewController
            rootVC.setNeedsStatusBarAppearanceUpdate()
            
            self.appOpenAd?.present(fromRootViewController: rootVC)
        })
    }
    
    func requestAppOpenAd() {
        let request = GADRequest()
        GADAppOpenAd.load(withAdUnitID: "ca-app-pub-3940256099942544/5662855259",
                          request: request,
                          orientation: UIInterfaceOrientation.portrait,
                          completionHandler: { (appOpenAdIn, _) in
            self.appOpenAd = appOpenAdIn
            self.appOpenAd?.fullScreenContentDelegate = self
            self.loadTime = Date()
            print("[OPEN AD] Ad is ready")
        })
    }
    
    func tryToPresentAd() {
        if let gOpenAd = self.appOpenAd, wasLoadTimeLessThanNHoursAgo(thresholdN: 4) {
            // 方式二代码(使用方式一则删除这段)
            let rootVC = UIApplication.shared.getRootViewController()
            rootVC.childForStatusBarHidden = gOpenAd.presentedViewController
            rootVC.setNeedsStatusBarAppearanceUpdate()
            
            gOpenAd.present(fromRootViewController: rootVC)
        } else {
            self.requestAppOpenAd()
        }
    }
    
    func wasLoadTimeLessThanNHoursAgo(thresholdN: Int) -> Bool {
        let now = Date()
        let timeIntervalBetweenNowAndLoadTime = now.timeIntervalSince(self.loadTime)
        let secondsPerHour = 3600.0
        let intervalInHours = timeIntervalBetweenNowAndLoadTime / secondsPerHour
        return intervalInHours < Double(thresholdN)
    }
    
    func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
        print("[OPEN AD] Failed: \(error)")
        requestAppOpenAd()
    }
    
    func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
        requestAppOpenAd()
        print("[OPEN AD] Ad dismissed")
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 18:25:49