Why is my interstitial Ad Producing an error? - swift

I am trying to show an interstitial Ad whenever the game over scene is displayed and I am just getting in error. I have searched for answers but they produced the same result. I am using the Notification Center method and it is not working. My banner view is working just fine though.
I am getting this error:
CoreAnimation: [EAGLContext renderbufferStorage:fromDrawable:] was
called from a non-main thread in an implicit transaction! Note that
this may be unsafe without an explicit CATransaction or a call to
[CATransaction flush]. 2017-10-01 09:28:00.631015-0500
Split[868:273850] CoreAnimation: [EAGLContext
renderbufferStorage:fromDrawable:] was called from a non-main thread
in an implicit transaction! Note that this may be unsafe without an
explicit CATransaction or a call to [CATransaction flush].
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.loadAndShow), name: NSNotification.Name(rawValue: "loadAndShow"), object: nil)
let request = GADRequest()
request.testDevices = [kGADSimulatorID, "49d92844bdbdf74dac25e343b377744f"]
bannerView = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
self.view?.addSubview(bannerView)
bannerView.adUnitID = "ca-app-pub-9408273734198014/6590781864"
bannerView.rootViewController = self
bannerView.load(GADRequest())
bannerView.delegate = self
interstitialView = GADInterstitial(adUnitID: "ca-app-pub-9408273734198014/7472368678")
interstitialView.load(request)
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "StartScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
#objc func loadAndShow() {
interstitialView = GADInterstitial()
let request = GADRequest()
interstitialView.setAdUnitID("ca-app-pub-9408273734198014/7472368678")
interstitialView.delegate = self
interstitialView.load(request)
}
func showInterstitial(ad: GADInterstitial!) {
if (self.interstitialView.isReady) {
interstitialView.present(fromRootViewController: self)
}
}

So, as mentioned in error, you are calling interstitialView.present(fromRootViewController: self) in non main thread, it is called from a thread that was used to load the interstitial.
To fix it just present it in main queue.
DispatchQueue.main.async {
self.interstitialView.present(fromRootViewController: self)
}

Related

Crashes with completion handler in GameViewController

Want to preload textureAtlases before game starts, so I decided to put scene starter code into completion handler, but for some reason app crashes. Here is my code:
import UIKit
import SpriteKit
import GameplayKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let gpuAtlas = SKTextureAtlas(named: "GP")
let ppAtlas = SKTextureAtlas(named: "PP")
SKTextureAtlas.preloadTextureAtlases([gpuAtlas, ppAtlas]) {
if let view = self.view as? SKView {
let scene = GameScene(size: self.view.bounds.size)
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
override var prefersStatusBarHidden: Bool {
return true
}
}
If I remove preload texture atlas method everything will work as usual, but I want preload textures to have a change to get rid of first keyframe freeze because of loading textures in cache.
Error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Update:
It crashes on GameScene.swift file in method didSimulatePhysics.
What I do wrong guys?
Try this (use main thread for manipulation with view and weak self):
SKTextureAtlas.preloadTextureAtlases([gpuAtlas, ppAtlas]) { [weak self] in
guard let gameView = self?.view as? SKView else { return }
DispatchQueue.main.async {
let scene = GameScene(size: gameView.bounds.size)
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
gameView.presentScene(scene)
gameView.ignoresSiblingOrder = true
gameView.showsFPS = true
gameView.showsNodeCount = true
}
}
Did you check if scene is optional? If so:
guard let scene = GameScene(size: gameView.bounds.size) else { return }
This
let gpuAtlas = SKTextureAtlas(named: "GP")
let ppAtlas = SKTextureAtlas(named: "PP")
SKTextureAtlas.preloadTextureAtlases([GP, PP]) {}
should not compile - the variables are named gpuAtlas and ppAtlas and not GP and PP.

Displaying interstitial admob when the game is over with Sprite Kit and iOS

I have been trying to display adds when the game is over for my game app. I have created a game over variable on GameScene.swift and I call that variable in the GameViewController.swift. However, the add is displayed shortly after the game starts. Could anyone point out what am I doing wrong? Here is my code:
import UIKit
import SpriteKit
import GoogleMobileAds
private var interstitial: GADInterstitial?
class GameViewController: UIViewController, GADInterstitialDelegate {
private var interstitial: GADInterstitial?
override func viewDidLoad() {
super.viewDidLoad()
interstitial = createInterstitial()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
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
skView.presentScene(scene)
}
}
override func prefersStatusBarHidden() -> Bool {
return true
}
private func createInterstitial() -> GADInterstitial {
let interstitial = GADInterstitial(adUnitID: "ca-app-pub-5713504307801022/7610056592")
interstitial.delegate = self
let request = GADRequest()
request.testDevices = ["ca-app-pub-5713504307801022/7610056592"]
interstitial.loadRequest(request)
return interstitial
}
func interstitialDidDismissScreen(ad: GADInterstitial!) {
interstitial = createInterstitial()
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
if (interstitial!.isReady) {
if gameOver1 == true {
self.interstitial!.presentFromRootViewController(self)
interstitial = createInterstitial()
}
}
}
}
First - this is how you should load and recycle AdMob interstitials -https://stackoverflow.com/a/37938286/2405378
Second - viewWillLayoutSubviews can be called multiple times and each time this method creates new instance of the GameScene - with gameOver1 being false?

How to add interstitial AdMob in iOS project with SpriteKit

I am trying to implement interstitial AdMob to my game app. But I have not had much luck so far. The code doesn't seem to have a bug but however it does not display the app. Any help would be much appreciate it. Thank you!
Here is my code:
import UIKit
import SpriteKit
import GoogleMobileAds
class GameViewController: UIViewController, GADInterstitialDelegate {
var interstitial: GADInterstitial!
override func viewDidLoad() {
super.viewDidLoad()
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
skView.presentScene(scene)
}
interstitial = GADInterstitial(adUnitID: "ca-app-pub-5713504307801022/7610056592")
let request = GADRequest()
interstitial.loadRequest(request)
func CreateAD() -> GADInterstitial {
let interstital = GADInterstitial(adUnitID: "ca-app-pub-5713504307801022/7610056592")
interstitial.loadRequest(GADRequest())
return interstital
}
if gameOver == true {
if (interstitial.isReady){
interstitial.presentFromRootViewController(self)
interstitial = CreateAD()
}
}
}

Hiding or Showing Google Ad View in Swift with Sprite Kit

In my game I would like there to be an Google Banner View in the main menu scene and game over scene. Here's what I have in the GameViewController:
override func viewWillLayoutSubviews(){
super.viewWillLayoutSubviews()
let skView = self.view as! SKView
googleBannerView = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
googleBannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716"
googleBannerView.rootViewController = self
var request: GADRequest = GADRequest()
googleBannerView.loadRequest(request)
googleBannerView.frame = CGRectMake(0, skView.bounds.height - googleBannerView.frame.size.height, googleBannerView.frame.size.width, googleBannerView.frame.size.height)
self.view.addSubview(googleBannerView!)
if skView.scene == nil{
let mainMenuScene = MainMenuScene(size: skView.bounds.size)
mainMenuScene.scaleMode = SKSceneScaleMode.AspectFill
mainMenuScene.backgroundColor = UIColor.whiteColor()
skView.presentScene(mainMenuScene)
}
}
func showBanner(){
if googleBannerView != nil{
self.googleBannerView!.hidden = false
var request: GADRequest = GADRequest()
self.googleBannerView.loadRequest(request)
}
}
func hideBanner(){
println("hideBanner() called")
self.googleBannerView.hidden = true
}
In the GameScene I have this:
override init(size: CGSize) {
super.init(size: size)
let gameViewController = GameViewController()
gameViewController.hideBanner()
When I run this it starts up fine, but when I press play it crashes and says: fatal error: unexpectedly found nil while unwrapping an Optional value. This doesn't make much sense because it can't be nil because I know there is an ad banner, right? What I am doing wrong. Thank you in advance.
-Vinny
There could possibly be an error in your show banner function. Try taking out the exclamation in:
self.googleBannerView!.hidden = false
If the banner view is not nil, then it doesn't need to unwrapped

Prioritizing iAd over adMob SpriteKit / Swift

I integrated both iAd and adMob into my game, with adMob code only running when iAd fails to load. If the iAd does not fail loading the first ad, it works fine. Admob works like it should when iAd fails to load. However, when iAd fails but then loads the next ad, the adMob banner still exists and the iAd is not shown. How do I make it so that iAd loads even when adMob already is. Also, the iAd banner loads fine after failing to load when the adMob code is commented out. On an unrelated note, how do change the fill rate of adMob ads in the simulator? Thanks. This is my code in my GameViewController (iAd is called in gameScene):
import UIKit
import SpriteKit
import iAd
import GoogleMobileAds
class GameViewController: UIViewController, ADBannerViewDelegate {
var SH = UIScreen.mainScreen().bounds.height
let transition = SKTransition.fadeWithDuration(1)
var UIiAd: ADBannerView = ADBannerView()
var googleBannerView: GADBannerView!
override func viewWillAppear(animated: Bool) {
/* var BV = UIiAd.bounds.height
UIiAd.delegate = self
UIiAd.frame = CGRectMake(0, SH + BV, 0, 0)
self.view.addSubview(UIiAd) */
UIiAd.setTranslatesAutoresizingMaskIntoConstraints(false)
UIiAd.delegate = self
self.view.addSubview(UIiAd)
let viewsDictionary = ["bannerView":UIiAd]
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[bannerView]|", options: .allZeros, metrics: nil, views: viewsDictionary))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[bannerView]|", options: .allZeros, metrics: nil, views: viewsDictionary))
}
override func viewWillDisappear(animated: Bool) {
UIiAd.delegate = nil
UIiAd.removeFromSuperview()
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
var BV = UIiAd.bounds.height
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1) // Time it takes the animation to complete
UIiAd.alpha = 1 // Fade in the animation
UIView.commitAnimations()
println("iAd work")
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1)
UIiAd.alpha = 0
UIView.commitAnimations()
googleBannerView = GADBannerView(adSize: kGADAdSizeSmartBannerLandscape)
googleBannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716"
googleBannerView.rootViewController = self
var request: GADRequest = GADRequest()
googleBannerView.loadRequest(request)
googleBannerView.frame = CGRectMake(0, view.bounds.height - googleBannerView.frame.size.height, googleBannerView.frame.size.width, googleBannerView.frame.size.height)
self.view.addSubview(googleBannerView!)
println("iAd fail")
}
func showBannerAd() {
UIiAd.hidden = false
var BV = UIiAd.bounds.height
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1) // Time it takes the animation to complete
UIiAd.frame = CGRectMake(0, SH - BV, 2048, 0) // End position of the animation
UIView.commitAnimations()
}
func hideBannerAd() {
UIiAd.hidden = true
var BV = UIiAd.bounds.height
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1) // Time it takes the animation to complete
UIiAd.frame = CGRectMake(0, SH + BV, 0, 0) // End position of the animation
UIView.commitAnimations()
}
override func viewDidLoad() {
super.viewDidLoad()
self.UIiAd.hidden = true
self.UIiAd.alpha = 0
NSNotificationCenter.defaultCenter().addObserver(self, selector: "hideBannerAd", name: "hideadsID", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "showBannerAd", name: "showadsID", object: nil)
let scene = GameScene(size: CGSize(width: 2048, height: 1356))
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = SKSceneScaleMode.AspectFill
skView.presentScene(scene)
}
func bannerViewActionShouldBegin(banner: ADBannerView!, willLeaveApplication willLeave: Bool) -> Bool {
println("Clicked")
// let skView: SKView = self.view as! SKView
// skView.scene!.paused = true
return true
}
/* func bannerViewActionDidFinish(banner: ADBannerView!) {
let skView: SKView = self.view as! SKView
skView.scene!.paused = false
} */
override func prefersStatusBarHidden() -> Bool {
return true
}
}
You're not hiding your AdMob banner when iAd receives an ad in your bannerViewDidLoadAd(banner: ADBannerView!). So, your iAd banner is actually being displayed behind your AdMob banner.
Alternatively, you could create both your iAd and AdMob banners once in your viewDidLoad and hide or show them depending on if iAd receives an ad or not. Your iAd delegate methods would end up looking similar to this:
func bannerViewDidLoadAd(banner: ADBannerView!) {
UIView.beginAnimations(nil, context: nil)
// Show iAd
UIiAd.alpha = 1.0
// Hide AdMob
googleBannerView.alpha = 0.0
UIView.commitAnimations()
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
UIView.beginAnimations(nil, context: nil)
// Hide iAd
UIiAd.alpha = 0.0
// Show AdMob
googleBannerView.alpha = 1.0
UIView.commitAnimations()
}
Check my answer here for a complete implementation.
I made an ad helper for swift, why don't you check it out, it does exactly what you want. It was primarily made for SpriteKit.
https://github.com/crashoverride777/Swift-iAds-and-AdMob-Helper