Using AdMob interstitial ads in iOS game applications and Swift - ios

Okay, I've spent days now doing this. I've gone through admob's tutorials, youtube, stack exchange, everything and I cannot find a solution to my problem.
I'm trying to implement admob's interstitial ads into my iOS game application. The code compiles, builds, runs, the game is played, but ads will not show up. This is my GameViewController.swift
import UIKit
import SpriteKit
import GoogleMobileAds
class GameViewController: UIViewController, GADInterstitialDelegate {
//AD STUFF-----------------------------vBELOWv----------------------------------------------
//AD STUFF-----------------------------vBELOWv----------------------------------------------
var interstitialAd: GADInterstitial?
func createInterstitialAd() -> GADInterstitial {
let request = GADRequest()
let interstitial = GADInterstitial(adUnitID: "ca-app-pub-******")
request.testDevices = [kGADSimulatorID, "C966DEAC-A2FD-4FBA-80B5-802B7E394C6D", "F3E1897A-3556-4704-9C85-3D70B4672F44","090DCEE5-6B1C-4DFB-83CE-FE800A242008", "1B93E43B-E9B3-4482-8B11-4F3614A26EA2"]
interstitial.delegate = self
interstitial.loadRequest(request)
return interstitial
}
//func to show the ad
func showAd() {
if interstitialAd != nil {
if interstitialAd!.isReady{
interstitialAd?.presentFromRootViewController(self)
}
else {print("found not ready")}
}
}
//func to pre-load new ad - calls automatically when closes an ad
func interstitialWillDismissScreen(ad: GADInterstitial!) {
interstitialAd = createInterstitialAd()
}
//AD STUFF--------------------------^ABOVE^--------------------------------------------------
//AD STUFF--------------------------^ABOVE^--------------------------------------------------
override func viewDidLoad() {
super.viewDidLoad()
interstitialAd = createInterstitialAd()
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
scene.size = self.view.bounds.size
skView.presentScene(scene)
}
}
This is how I'm calling it to my GameScene
//makes the restart button appear
func createRestartBTN(){
restartBTN = SKSpriteNode(color: SKColor.clearColor(), size: CGSize(width: 200, height: 100))
restartBTN.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
restartBTN.zPosition = 10
addChild(restartBTN)
createReplayText()
varForGVC.showAd()
}
So when the game is over, a function makes a restart button appear. Then I want my interstitial ad to pop up so the user has to exit the interstitial ad to hit the replay button. That variable varForGVC is an implemented earlier in the GameScene.swift by varForGVC = GameViewController()
I have my app synced with Firebase and admob. I have the GoogleService-Info.plist in my root. I have the list of required frameworks for admob in my root as well. I have pod installed with Firebase. I've tried putting the code I'm using in my GameViewController into my GameScene.swift and it did not work there either. I don't know if this matters, but my game has a Main Screen, a Rules screen only accessible via the main screen, then the user hits a Play button to begin playing the game in another Screen (the GameScene). My check for .isReady does not return found not ready. I need some help with this issue. For now, I'm going to try to reinstall the frameworks and see if that's it.

This is how I work with interstitial ads from AdMob - using extension. I think it's way more clean solution. Hope it will help you!
GameViewController.swift
class GameViewController: UIViewController {
var interstitial: GADInterstitial?
override func viewDidLoad() {
createInterstitial()
}
func presentInterstitial() {
guard let interstitial = self.interstitial where interstitial.isReady else {
return
}
dispatch_async(dispatch_get_main_queue(), {
interstitial.presentFromRootViewController(self)
})
}
}
GameViewController+GADInterstitialDelegate.swift
import GoogleMobileAds
extension GameViewController: GADInterstitialDelegate {
func interstitial(ad: GADInterstitial!, didFailToReceiveAdWithError error: GADRequestError!) {
print("\(#function): \(error.localizedDescription)")
}
func interstitialDidDismissScreen(ad: GADInterstitial!) {
// Recycle interstitial
createInterstitial()
unpauseGame() // Some method from GameViewController
}
func interstitialWillPresentScreen(ad: GADInterstitial!) {
pauseGame() // Some method from GameViewController
}
func createInterstitial() {
interstitial = GADInterstitial(adUnitID: interstitialAdUnitID)
interstitial!.loadRequest(AdMobHelper.createRequest())
interstitial!.delegate = self
}
}
And the last part - AdMobHelper.swift
import GoogleMobileAds
let interstitialAdUnitID = "Some Id"
class AdMobHelper {
static func createRequest() -> GADRequest {
let request = GADRequest()
request.testDevices = ["Check this in your logs"]
return request
}
}

I figured it out finally. I used NSNotifcationCenter. I put in an observer in my GameViewController.swift in my viewDidLoad function, then a receiver where I wanted it to pop up.

Related

Admob Interstitial ad not showing fullScreen on devices iOS

I made a game using spritekit and implement admob interstitial ad following the documentation provided by google. Everything works fine in the simulator, the ad presents fullscreen as expected in the right time. The problem is that when I run in my iPhone 6s the ad doesn't fill the entire screen, just a small part of it on a black screen. I've implemented all the admob code on my gameviewController and call it in a gameScene using a observer.
class GameViewController: UIViewController {
var interstitial: GADInterstitial!
override func viewDidLoad() {
super.viewDidLoad()
interstitial = createAndLoadInterstitial()
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.showIntersticialAd), name: Notification.Name("showIntersticialAd"), object: nil)
if let view = self.view as! SKView? {
let scene = MenuScene(size: view.bounds.size)
scene.scaleMode = .aspectFill
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
}
}
#objc func showIntersticialAd() {
if interstitial.isReady {
interstitial.present(fromRootViewController: self)
} else {
print("Ad not ready")
}
}
}
extension GameViewController: GADInterstitialDelegate {
func createAndLoadInterstitial() -> GADInterstitial {
let interstitial = GADInterstitial(adUnitID: "ca-app-pub-4828696079960529/6898313363")
interstitial.delegate = self
interstitial.load(GADRequest())
return interstitial
}
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
interstitial = createAndLoadInterstitial()
}
}
I've searched a lot in the internet and in the admob documentation but didn't figure out why this is happening.
#objc func showIntertialAds() {
if !interstitial.isReady{
interstitial.load(GADRequest())
} if interstitial.isReady {
interstitial.present(fromRootViewController:(UIApplication.shared.keyWindow?.rootViewController)!)
}
}

SKScene switches when displaying interstitial ad with admob with Swift

I am making a game with SpriteKit in Swift and I am having trouble when displaying the ad. The ad shows up when the player dies, as it is supposed to, but instead of staying in the current scene (GameScene) when I close it, it switches out to the MainMenu scene for some reason. Actually, if you watch closely, you can see that the "game over" text appears and as the ad slides up to display, it switches to the MainMenu scene. I saw the post here and tried what the answers said (moving everything from ViewWillLayoutSubviews to ViewDidLoad, etc) and it didn't work. Any ideas? Thanks.
Here is all of the code involving the ad in GameViewController:
class GameViewController: UIViewController, UIAlertViewDelegate, GADInterstitialDelegate {
var musicPlayer = AVAudioPlayer()
var musicUrl = Bundle.main.url(forResource: "Loops2.mp3", withExtension: nil)
var interstitial: GADInterstitial!
override func viewDidLoad() {
super.viewDidLoad()
interstitial = loadAd()
NotificationCenter.default.addObserver(self, selector: #selector(self.playerDied), name: NSNotification.Name("ShowAd"), object: nil)
NotificationCenter.default.post(name: NSNotification.Name("ShowingAd"), object: nil)
super.viewWillLayoutSubviews()
let skView = self.view as! SKView
skView.ignoresSiblingOrder = true
skView.showsFPS = true
skView.showsNodeCount = true
let mainMenu = MainMenu()
mainMenu.scaleMode = .aspectFill
mainMenu.size = view.bounds.size
skView.presentScene(mainMenu)
}
func playerDied() {
if self.interstitial.isReady {
self.interstitial.present(fromRootViewController: self)
}
}
func loadAd() -> GADInterstitial {
let interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/1033173712")
interstitial.delegate = self
interstitial.load(GADRequest())
return interstitial
}
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
NotificationCenter.default.post(name: NSNotification.Name("AdDismissed"), object: nil)
interstitial = loadAd()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let url = musicUrl {
try! musicPlayer = AVAudioPlayer(contentsOf: url)
musicPlayer.numberOfLoops = -1
musicPlayer.prepareToPlay()
musicPlayer.play()
}
}
I use the NotificationCenter to signal GameViewController when to display the ad. I don't think that the code from GameScene is needed, but if you think it would be helpful, just ask. Thanks!

AdMob Interstitial Ad in SpriteKit Game

I am trying to show an AdMob Interstitial ad every time my game transitions to the GameOver Scene. However, the ad will only appear if I put its initializing function in my viewDidLoad() function in my view controller. I have a notification center set up on the game, and have tried to send a notification upon entering the GameOver Scene, to trigger the function that initializes the ad, yet that did not do the trick. I was wondering how I can trigger it from a scene at any given time instead of showing it immediately upon launch of the app, which is what putting it in my viewDidLoad function of the view controller.
In my GameViewController are these two functions:
public func initAdMobInterstitial() {
adMobInterstitial = GADInterstitial(adUnitID: AD_MOB_INTERSTITIAL_UNIT_ID)
adMobInterstitial.delegate = self
let request = GADRequest()
request.testDevices = ["ddee708242e437178e994671490c1833"]
adMobInterstitial.load(request)
}
func interstitialDidReceiveAd(_ ad: GADInterstitial) {
ad.present(fromRootViewController: self)
}
Here I have commented out initAdMobInterstitial, however when it is uncommented the ad pops up and works properly. This popup occurs as soon as the app launches the first time.
override func viewDidLoad() {
super.viewDidLoad()
//initAdMobInterstitial()
initAdMobBanner()
NotificationCenter.default.addObserver(self, selector: #selector(self.handle(notification:)), name: NSNotification.Name(rawValue: socialNotificationName), object: nil)
let scene = Scene_MainMenu(size: CGSize(width: 1024, height: 768))
let skView = self.view as! SKView
skView.isMultipleTouchEnabled = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .aspectFill
_ = SGResolution(screenSize: view.bounds.size, canvasSize: scene.size)
skView.presentScene(scene)
}
Now, in one of my scenes, entitled GameOver, I want the ad to pop up. I would like it to come up every time the scene is presented, so every time the player loses and hits game over. Using the notification center you can see in my view controller class, i have tried to send a notification and have it handled...
override func didMove(to view: SKView) {
self.sendNotification(named: "interNotif")
}
...by this function, also found in the view controller class
func handle(notification: Notification) {
if (notification.name == NSNotification.Name(rawValue: interstitialNotificationName)) {
initAdMobInterstitial()
}
}
Also as a note, in my view controller I have declared interstitialNotificationName equal to the string "interNotif" to match the notification sent.
Do not present the GADInterstitial as soon as it loads. Your notification func should be presenting it. Then, once the user dismisses the ad request another one. For example:
override func viewDidLoad() {
super.viewDidLoad()
// Load the ad
initAdMobInterstitial()
}
func interstitialDidReceiveAd(_ ad: GADInterstitial) {
// Do not present here
// ad.present(fromRootViewController: self)
}
func handle(notification: Notification) {
if (notification.name == NSNotification.Name(rawValue: interstitialNotificationName)) {
// Check if the GADInterstitial is loaded
if adMobInterstitial.isReady {
// Loaded so present it
adMobInterstitial.present(fromRootViewController: self)
}
}
}
// Called just after dismissing an interstitial and it has animated off the screen.
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
// Request new GADInterstitial here
initAdMobInterstitial()
}
For a complete list of GADInterstitialDelegate ad events refer to AdMob iOS Ad Events.

Presenting an Interstitial Ad in a Game Over Scene linking to GameViewController?

I've integrated a banner view into a scene within my application however I'm failing to integrate a Interstitial ad within another scene.
Here is my code:
import SpriteKit
import GameKit
import GoogleMobileAds
class GameOverMenu: SKScene, GKGameCenterControllerDelegate, UIAlertViewDelegate {
var viewController: GameViewController!
var interstitial: GADInterstitial!
var myTimer = Timer()
override func didMove(to view: SKView) {
createAndLoadInterstitial()
startMyTimer()
}
func createAndLoadInterstitial() {
interstitial = GADInterstitial(adUnitID: "...")
let request = GADRequest()
request.testDevices = [ kGADSimulatorID, "..." ]
interstitial.load(request)
}
func startMyTimer() {
myTimer = Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(GameOverMenu.myFunction), userInfo: nil, repeats: false)
}
func myFunction(){
if interstitial.isReady {
interstitial.present(fromRootViewController: viewController)
} else {
print("Ad wasn't ready")
}
}
It is failing when it tries to load with "fatal error: unexpectedly found nil while unwrapping an Optional value". The problem lies below as if the code is displayed like this and I load the GameOver scene when the application launches it works fine. How can I fix this?
if let view = self.view as! SKView? {
// Load the SKScene from 'MainMenu.sks'
if let scene = MainMenuScene(fileNamed: "MainMenu") {
scene.viewController = self
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
if let scene3 = GameOverMenu(fileNamed: "GameOver") {
scene3.viewController = self
// Set the scale mode to scale to fit the window
scene3.scaleMode = .aspectFill
view.presentScene(scene3)
}
The problem is that when you transition between 2 scenes you loose the reference to GameViewController e.g
scene3.viewController = self
thats why it only works when you launch the application.
You are also using ! on those properties
var viewController: GameViewController!
var interstitial: GADInterstitial!
so if they are nil you will crash. So you should alway use ? when you are not 100% sure that something is there.
var viewController: GameViewController?
var interstitial: GADInterstitial?
and than in your code such as "myFunction" you will use the "?" and "if let" to not crash when the properties are nil.
if let ad = interstitial, let vc = viewController, ad.isReady {
ad.present(fromRootViewController: vc)
} else {
print("Ad wasn't ready")
}
The general fix for your problem is that you should really move all your AdMob code directly into GameViewController. Than you can use something like NotificationCenter or delegation to forward a message from your scenes to your ViewController to show the ad. Its not really the best practice to reference your ViewController in your SKScenes.
So move all the ad code to your ViewController and than in GameViewController outside the class implementation create this extension for the notification key
extension Notification.Name {
static let showAd = Notification.Name(rawValue: "NotificationShowAd")
}
class GameViewController: UIViewController {...
Than in GameViewController in ViewDidLoad you can add the observer
override func viewDidLoad() {
super.viewDidLoad()
createAndLoadInterstitial()
NotificationCenter.default.addObserver(self, selector: #selector(myFunction), name: .showAd, object: nil)
....
}
Now whenever you need to show an ad from any of your SKScenes you can call this
NotificationCenter.default.post(name: .showAd, object: nil)
To make your life even easier have a look at my helper on GitHub
https://github.com/crashoverride777/SwiftyAds
hope this helps

AdMob Banner Ad not Showing Swift 3

I am working on a SpriteKit game and am implementing banner ads via AdMob (Google Firebase). I have followed Google's tutorials here and here on setting up your first ad request, but when I run the app on either the sim or my device (iPhone 6s), the banner does not show up. Per the tutorials, I implemented the banner view via the Storyboard and the rest was set up programmatically. Below is the code of my view controller.
Q: Why isn't my banner showing?
Follow-up Q: Is it possible to show the banner only on certain SKScenes?
import UIKit
import SpriteKit
import GoogleMobileAds
class GameViewController: UIViewController, GADBannerViewDelegate {
#IBOutlet weak var bannerView: GADBannerView!
override func viewDidLoad() {
super.viewDidLoad()
print("Google Mobile Ads SDK version: " + GADRequest.sdkVersion())
bannerView.delegate = self
bannerView.adUnitID = "ca-app-pub-9474695450721030/1823667708"
bannerView.rootViewController = self
let req = GADRequest()
req.testDevices = ["91fbd46dff1179ce0a5e7226cea1ee0b", kGADSimulatorID]
req.tag(forChildDirectedTreatment: true)
bannerView.load(GADRequest())
view.addSubview(bannerView)
showBanner()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let skView = self.view as? SKView {
if skView.scene == nil {
let aspectRatio = view.bounds.size.height / view.bounds.size.width
let scene = MenuScene(size: CGSize(width: 750, height: 750 * aspectRatio))
scene.scaleMode = .aspectFill
skView.ignoresSiblingOrder = true
if kDebug {
skView.showsFPS = true
skView.showsDrawCount = true
skView.showsNodeCount = true
skView.showsPhysics = true
}
let transition = SKTransition.fade(with: SKColor.black, duration: 0.5)
skView.presentScene(scene, transition: transition)
}
}
}
func showBanner() {
bannerView.isHidden = false
let request = GADRequest()
request.testDevices = ["2077ef9a63d2b398840261c8221a0c9b"]
bannerView.load(request)
}
func hideBanner() {
bannerView.isHidden = true
}
}
First of all, you don't need to request a new banner every time you run showAd(). Simply unhide it. The ad you load on launch will remain for the whole lifecycle, and automatically refreshes.
Second, in your viewDidLoad code, you're initializing a banner ad, then loading a completely new one. Make sure that you're loading the same request that you were setting up.
As for calling functions inside your GameViewController from an SKScene, take a look at this: Call GameViewController function from SKScene
Just in case anyone is not seeing the ads after updating the SDK. From my end, I was able to resolve it after much investigation. It is worth noticing that the function name changes after updating the SDK.
The old function is
func adViewDidReceiveAd(_ bannerView: GADBannerView)
The new function is
func bannerViewDidReceiveAd(_ bannerView: GADBannerView)

Resources