Swift中如何在指定SpriteKit场景展示AdMob横幅广告
解决SpriteKit游戏中AdMob横幅广告仅在指定场景显示的问题
我明白你现在遇到的问题:广告在所有场景都显示,移除后又无法重新添加。核心问题在于你试图在Scene(非ViewController类)中直接操作广告视图,而AdMob的GADBannerView需要依赖UIViewController作为上下文。下面是一套简单可靠的解决方案:
核心思路
不要移除广告视图,而是通过隐藏/显示来控制广告的可见性,同时让GameViewController统一管理广告的状态。各个Scene通过通知中心告诉ViewController何时显示或隐藏广告,这样就避免了在Scene中处理广告视图的创建和布局问题。
步骤1:修改GameViewController代码
让ViewController负责广告的初始化、布局和显示隐藏逻辑,同时监听来自各个Scene的通知:
import GoogleMobileAds import SpriteKit class GameViewController: UIViewController, GADBannerViewDelegate { private var bannerView: GADBannerView! override func viewDidLoad() { super.viewDidLoad() // 初始化广告视图,默认隐藏 setupBannerView() // 注册通知监听:接收来自Scene的显示/隐藏广告指令 NotificationCenter.default.addObserver( self, selector: #selector(showBannerAd), name: NSNotification.Name("ShowBannerAd"), object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(hideBannerAd), name: NSNotification.Name("HideBannerAd"), object: nil ) // 加载主菜单场景 if let view = self.view as? SKView { if let scene = MainMenuScene(fileNamed: "MainMenuScene") { scene.scaleMode = .resizeFill view.presentScene(scene) } view.ignoresSiblingOrder = true view.showsFPS = true view.showsNodeCount = true } } // 初始化广告视图并添加到界面(默认隐藏) private func setupBannerView() { bannerView = GADBannerView(adSize: kGADAdSizeBanner) bannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716" bannerView.rootViewController = self bannerView.delegate = self bannerView.isHidden = true // 默认隐藏 bannerView.load(GADRequest()) // 添加布局约束 addBannerViewToView(bannerView) } // 广告视图布局方法 private func addBannerViewToView(_ bannerView: GADBannerView) { bannerView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(bannerView) NSLayoutConstraint.activate([ bannerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), bannerView.centerXAnchor.constraint(equalTo: view.centerXAnchor) ]) } // 显示广告 @objc func showBannerAd() { bannerView.isHidden = false // 可选:如果需要重新加载广告,可在这里调用 bannerView.load(GADRequest()) } // 隐藏广告 @objc func hideBannerAd() { bannerView.isHidden = true } // 可选:实现广告加载状态回调 func bannerViewDidReceiveAd(_ bannerView: GADBannerView) { print("广告加载成功") } func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) { print("广告加载失败:\(error.localizedDescription)") } }
步骤2:在各Scene中发送显示/隐藏通知
1. 主菜单场景(MainMenuScene)
进入场景时显示广告,切换到游戏场景前隐藏广告:
import SpriteKit class MainMenuScene: SKScene { override func didMove(to view: SKView) { // 进入主菜单时显示广告 NotificationCenter.default.post(name: NSNotification.Name("ShowBannerAd"), object: nil) } // 假设这是开始游戏按钮的点击事件 @objc func startGameTapped() { // 切换场景前隐藏广告 NotificationCenter.default.post(name: NSNotification.Name("HideBannerAd"), object: nil) let gameScene = GameScene(fileNamed: "GameScene")! gameScene.scaleMode = .resizeFill view?.presentScene(gameScene) } }
2. 游戏场景(GameScene)
进入场景时隐藏广告,游戏结束切换到结束场景前显示广告:
import SpriteKit class GameScene: SKScene { override func didMove(to view: SKView) { // 进入游戏场景时隐藏广告 NotificationCenter.default.post(name: NSNotification.Name("HideBannerAd"), object: nil) } // 游戏结束逻辑 func gameOver() { // 切换到结束场景前显示广告 NotificationCenter.default.post(name: NSNotification.Name("ShowBannerAd"), object: nil) let gameOverScene = GameOverScene(fileNamed: "GameOverScene")! gameOverScene.scaleMode = .resizeFill view?.presentScene(gameOverScene) } }
3. 游戏结束场景(GameOverScene)
进入场景时显示广告:
import SpriteKit class GameOverScene: SKScene { override func didMove(to view: SKView) { // 进入结束场景时显示广告 NotificationCenter.default.post(name: NSNotification.Name("ShowBannerAd"), object: nil) } }
为什么你的原有方法失效?
admobBanner == nil警告:你把admobBanner声明为非可选的UIView,所以它永远不可能为nil,这个判断毫无意义。addBannerViewToView未定义:这个方法是GameViewController的私有方法,Scene无法直接调用。delegate = self错误:GADBannerViewDelegate需要的是一个UIViewController类型的对象,而Scene是SKScene子类,无法作为代理。
通过让ViewController统一管理广告,你可以避免这些上下文冲突问题,同时让代码结构更清晰。
内容的提问来源于stack exchange,提问作者Alex Pharaon
相关产品推荐
相关产品推荐

