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

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)
    }
}

为什么你的原有方法失效?

  1. admobBanner == nil警告:你把admobBanner声明为非可选的UIView,所以它永远不可能为nil,这个判断毫无意义。
  2. addBannerViewToView未定义:这个方法是GameViewController的私有方法,Scene无法直接调用。
  3. delegate = self错误:GADBannerViewDelegate需要的是一个UIViewController类型的对象,而Scene是SKScene子类,无法作为代理。

通过让ViewController统一管理广告,你可以避免这些上下文冲突问题,同时让代码结构更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:44:38