iOS端Google AdMob RewardedAd安全区适配问题求助
iPhone 上 Google AdMob RewardedAd 安全区失效导致关闭按钮无法点击的解决方法
问题描述
在iPhone设备上,Google AdMob RewardedAd偶尔会拉伸至屏幕边缘,忽略安全区域,导致关闭按钮与控制中心触发区域重叠,无法被点击。已尝试修改展示广告所用的currentUiViewController的安全区行为(忽略/遵循两种模式),但问题仍存在。
当前展示广告的核心代码片段:
extension UIApplication { var keyWindow: UIWindow? { connectedScenes .compactMap { $0 as? UIWindowScene } .flatMap { $0.windows } .first { $0.isKeyWindow } } public var rootViewController: UIViewController? { guard let keyWindow = UIApplication.shared.keyWindow, let rootViewController = keyWindow.rootViewController else { return nil } return rootViewController } public func topViewController(controller: UIViewController? = UIApplication.shared.rootViewController) -> UIViewController? { if controller == nil { return topViewController(controller: rootViewController) } if let navigationController = controller as? UINavigationController { return topViewController(controller: navigationController.visibleViewController) } if let tabController = controller as? UITabBarController { if let selectedViewController = tabController.selectedViewController { return topViewController(controller: selectedViewController) } } if let presentedViewController = controller?.presentedViewController { return topViewController(controller: presentedViewController) } return controller } } guard let currentUiViewController = UIApplication.shared.topViewController() else { return } rewardedAd.present(fromRootViewController: currentUiViewController) { let reward = rewardedAd.adReward self.rewardAdPlaybackCallbacks?.onUserEarnedReward(rewardAdHandle: self.currentRewardAdHandle!) }
可行的解决思路
1. 使用自定义容器ViewController承载广告
创建一个专门的容器VC,强制其遵循安全区规则,再将广告展示在这个容器上,避免直接使用顶层VC带来的适配问题:
class AdContainerViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .black if #available(iOS 11.0, *) { // 强制开启安全区布局 view.insetsLayoutMarginsFromSafeArea = true view.layoutMargins = UIEdgeInsets( top: view.safeAreaInsets.top, left: 0, bottom: view.safeAreaInsets.bottom, right: 0 ) } } override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } } // 展示广告时替换原有逻辑 guard let topVC = UIApplication.shared.topViewController() else { return } let adContainerVC = AdContainerViewController() topVC.present(adContainerVC, animated: false) { self.rewardedAd.present(fromRootViewController: adContainerVC) { let reward = self.rewardedAd.adReward self.rewardAdPlaybackCallbacks?.onUserEarnedReward(rewardAdHandle: self.currentRewardAdHandle!) // 广告结束后关闭容器VC adContainerVC.dismiss(animated: false) } }
2. 检查AdMob SDK版本与广告单元配置
- 确保使用最新版本的Google Mobile Ads SDK,旧版本可能存在安全区适配的已知Bug;
- 登录AdMob后台,检查对应广告单元的设置,尝试关闭自适应广告相关选项,强制广告使用固定尺寸适配安全区。
3. 手动调整广告关闭按钮的布局约束
通过遍历广告视图层级,找到关闭按钮的容器视图,手动添加安全区偏移约束(注意:此方法依赖AdMob SDK的视图结构,可能随版本变化失效):
// 广告展示后延迟执行,确保视图已加载完成 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { guard let adRootView = self.rewardedAd.rootViewController?.view else { return } // 递归查找可能的关闭按钮容器(需根据实际视图结构调整判断条件) func findCloseButtonContainer(in view: UIView) -> UIView? { if view.frame.minY < view.safeAreaInsets.top { return view } for subview in view.subviews { if let container = findCloseButtonContainer(in: subview) { return container } } return nil } if let container = findCloseButtonContainer(in: adRootView), #available(iOS 11.0, *) { container.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ container.topAnchor.constraint(equalTo: adRootView.safeAreaLayoutGuide.topAnchor), container.trailingAnchor.constraint(equalTo: adRootView.trailingAnchor, constant: -16) ]) } }
4. 临时禁用控制中心触发(不推荐)
如果以上方案都无法快速生效,可临时在广告展示期间禁用控制中心下拉手势,但此方法会影响用户体验,仅作为应急方案:
// 展示广告前禁用交互(仅针对全屏广告场景) UIApplication.shared.windows.first?.isUserInteractionEnabled = false guard let currentUiViewController = UIApplication.shared.topViewController() else { UIApplication.shared.windows.first?.isUserInteractionEnabled = true return } rewardedAd.present(fromRootViewController: currentUiViewController) { let reward = self.rewardedAd.adReward self.rewardAdPlaybackCallbacks?.onUserEarnedReward(rewardAdHandle: self.currentRewardAdHandle!) // 广告结束后恢复交互 UIApplication.shared.windows.first?.isUserInteractionEnabled = true }
内容的提问来源于stack exchange,提问作者rdsarna
相关产品推荐
相关产品推荐

