Show Admob Interstitial ads between scenes in Swift SpriteKit - ios

I would like to know how to set up Admob Interstitial ads when I present my GameOverScene. What should I do to show the ads only sometimes when the game gets over? And how do I implement this in Swift?
Im referring to this post How to call admob interstitial ad using swift, spritekit and xcode? but i'd like to know how to call the ads in between scenes.
EDIT
Here is the code I used to present the ad
class GameViewController: UIViewController, GADInterstitialDelegate {
var interstitial = GADInterstitial()
var intersitialRecievedAd = false
let defaults = NSUserDefaults.standardUserDefaults()
override func viewDidLoad() {
super.viewDidLoad()
interstitial.delegate = self
self.interstitial = createAndLoadAd()
let timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "checkIfAdIsToBeDisplayed:", userInfo: nil, repeats: true)
//Scene implementation, boring stuff, got nothing to do with the ads...
...
}
func checkIfAdIsToBeDisplayed(timer:NSTimer) {
if defaults.boolForKey("adToBeShown") == true && intersitialRecievedAd == true {
showInterstitial()
defaults.setBool(false, forKey: "adToBeShown")
intersitialRecievedAd = false
} else {
}
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
intersitialRecievedAd = true
}
func createAndLoadAd() -> GADInterstitial {
var ad = GADInterstitial(adUnitID: "...")
ad.delegate = self
let request = GADRequest()
request.testDevices = ["..."]
ad.loadRequest(request)
return ad
}
func showInterstitial(){
if self.interstitial.isReady {
self.interstitial.presentFromRootViewController(self)
self.interstitial = createAndLoadAd()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
This code uses a timer to constantly check whether the gameOverScene has been presented. When the gameOverScene IS presented, I assign true to the "adToBeShown" bool.
This is not the best method, so could anyone tell me how to directly call the ad when a scene is presented?

why dont you use NSNotificationCenter or delegates to call showInterstitial().
For example
In gameViewController add this in viewDidLoad
NSNotificationCenter.defaultCenter().addObserver(self, selector: "showInterstitial"), name:"showInterAdKey", object: nil);
and when you want to show the ad from your scenes you use
NSNotificationCenter.defaultCenter().postNotificationName("showInterAdKey", object: nil)
You could also use something like the helper I posted on github which makes this even easier and your ViewController stays clean https://github.com/crashoverride777/Swift-2-iAds-and-AdMob-Helper

You can also limit the frequency that Admob will show interstitial ads via the Admob website. In the settings for your interstitial advert, there are options to change the frequency of adverts popping up.

Related

Integrating Facebook and Twitter in Xcode Scenes Swift iOS

I have developed a game in Xcode using sprite kit, and scenes. Now I am trying to integrate the functionality to post high scores to twitter and Facebook. I've looked around, and most people say to use SLComposeServiceViewController which is fine, until I try and present it. Because my app really only uses scenes, they never have the member function "presentViewController(....)". Thus, I am unable to ever present it. Anyone know any way around this?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch:UITouch = touches.first!
let touchLocation = touch.location(in: self)
let touchedNode = self.atPoint(touchLocation)
if (touchedNode.name == "tryAgain") {
let nextScene = Scene_LiveGame(size: self.scene!.size)
nextScene.scaleMode = self.scaleMode
self.view?.presentScene(nextScene, transition: SKTransition.fade(withDuration: 0.5))
}
else if (touchedNode.name == "share") {
if SLComposeViewController.isAvailable(forServiceType: SLServiceTypeFacebook) {
let fShare = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
self.presentViewController(fShare!, animated: true, completion: nil)
//^This is where my problem is. Xcode is telling me that self has no member function presentViewController which I totally understand, because its a scene and thus doesn't share those functions. But every resource online has shown me this is the only way to do it
}
}
Your are getting this error because you need to present a UIViewController from another UIViewController. So
self.presentViewController(...)
will not work because self (SKScene) is not a UIViewController. To present from a SKScene you would have to say this
view?.window?.rootViewController?.presentViewController(fShare!, animated: true, completion: nil)
I would recommend that you do not use those APIs anymore. Its better to use a UIActivityViewController for your sharing needs. This way you only need one share button in your app and you can share to all sorts of services (email, Twitter, Facebook, iMessage, WhatsApp etc).
Create a new Swift file and add this code.
enum ShareMenu {
static func open(text: String, image: UIImage?, appStoreURL: String?, from viewController: UIViewController?) {
guard let viewController = viewController, let view = viewController.view else { return }
// Activity items
var activityItems = [Any]()
// Text
activityItems.append(text)
// Image
if let image = image {
activityItems.append(image)
}
/// App url
if let appStoreURL = appStoreURL {
let items = ActivityControllerItems(appStoreURL: appStoreURL)
activityItems.append(items)
}
// Activity controller
let activityController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
// iPad settings
if UIDevice.current.userInterfaceIdiom == .pad {
activityController.modalPresentationStyle = .popover
activityController.popoverPresentationController?.sourceView = view
activityController.popoverPresentationController?.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0)
activityController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0)
}
// Excluded activity types
activityController.excludedActivityTypes = [
.airDrop,
.print,
.assignToContact,
.addToReadingList,
]
// Present
DispatchQueue.main.async {
viewController.present(activityController, animated: true)
}
// Completion handler
activityController.completionWithItemsHandler = { (activity, success, items, error) in
guard success else {
if let error = error {
print(error.localizedDescription)
}
return
}
// do something if needed
}
}
}
// MARK: - Activity Controller Items
/**
ActivityControllerItems
*/
private final class ActivityControllerItems: NSObject {
// MARK: - Properties
/// App name
fileprivate let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String ?? "-"
/// App store web url
fileprivate let appStoreURL: String
// MARK: - Init
/// Init
fileprivate init(appStoreURL: String) {
self.appStoreURL = appStoreURL
super.init()
}
}
// MARK: - UIActivityItemSource
/// UIActivityItemSource
extension ActivityControllerItems: UIActivityItemSource {
/// Getting data items
/// Placeholder item
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return ""
}
/// Item for actity type
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
return URL(string: appStoreURL) ?? appName
}
/// Provide info about data items
/// Subject field for services such as email
func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivityType?) -> String {
return appName
}
}
Than when the share button is pressed you can call it like so
ShareMenu.open(
text: "Can you beat my score?",
image: UIImage(...), // set to nil if unused
appStoreURL: "your iTunes app store URL", // set to nil if unused
from: view?.window?.rootViewController
)
Bear in mind that the image and appStoreURL will not show up everywhere, it depends on the sharing service.
You can also use your score value from your scene and add it to the text e.g
ShareMenu.open(
text: "Can you beat my score \(self.score)?",
...
)
Hope this helps
I will not go into SLComposeViewController related code. I will just show you two techniques aside from what crashoverride777 proposed. So the first technique would be using notifications, like this:
GameScene:
import SpriteKit
let kNotificationName = "myNotificationName"
class GameScene: SKScene {
private func postNotification(named name:String){
NotificationCenter.default.post(
Notification(name: Notification.Name(rawValue: name),
object: self,
userInfo: ["key":"value"]))
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.postNotification(named: kNotificationName)
}
}
Here, you post a notification by tapping the screen. A desired view controller class can listen for this notification, like this:
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(self.handle(notification:)),
name: NSNotification.Name(rawValue: kNotificationName),
object: nil)
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = GameScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
}
}
func handle(notification:Notification){
print("Notification : \(notification)")
}
}
Here, we add self as an observer for this notification - means that when notification happens, an appropriate handling method will be called (and that is our custom handle(notification:) method. In that method, you should call your code:
if SLComposeViewController.isAvailable(forServiceType: SLServiceTypeFacebook) {
let fShare = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
self.presentViewController(fShare!, animated: true, completion: nil)
}
Actually, I will write another example for delegation, to keep things clean :)
As I said, this can be done using notifications, like in this answer, or you can go with delegation:
First you should declare the MyDelegate protocol which defines one method called myMethod().
protocol MyDelegate:class {
func myMethod()
}
That method is a requirement that every class must implement if it conforms to this protocl.
In our example, you can look at the scene as a worker, and a view controller as a boss. When the scene finishes its task, it notifies its boss (delegates responsibilities to him) about job completion, so that boss can decide what is next. I mean, I could say : "The scene is a boss, and it delegates responsibilities to his employee, the view controller..." But it doesn't really matter who you consider as a boss... The delegation pattern matters.
So, the view controller, should conform to this protocol, and it will implement the myMethod() (that will be called by the scene later):
class GameViewController: UIViewController, MyDelegate {
override func viewDidLoad() {
super.viewDidLoad()
//MARK: Conforming to MyDelegate protocol
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = GameScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
scene.myDelegate = self
// Present the scene
view.presentScene(scene)
}
}
}
func myMethod(){
print("Do your stuff here")
}
}
And here is a code from the GameScene where you define the myDelegate property that we use to communicate with our view controller:
import SpriteKit
class GameScene: SKScene {
weak var myDelegate:MyDelegate?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.myDelegate?.myMethod()
}
}
To find out when to choose delegation over notifications and vice-versa take a look at this article (or just search SO, there are some nice posts about that).

swift: How to call an ad made in ViewController in game scene

I have an interstitial ad declared in GameViewController and want to call it every few times my game ends. I followed a tutorial where I would call the ad by a button but I need to call from GameScene but I don't know how to call across classes. Could I use a global variable between all classes or something?
Basically I want to call func adButton() in GameScene or maybe there is some better work around.
Also, is there any way to implement reward ads or does anyone have any good tutorial like it?
Thanks very much.
func createAndLoadInterstitial() -> GADInterstitial {
let interstitial = GADInterstitial(adUnitID: " unit id ")
let request1 = GADRequest()
interstitial.delegate = self
request1.testDevices = [ kGADSimulatorID, "2077ef9a63d2b398840261c8221a0c9b" ]
interstitial.loadRequest(request1)
return interstitial
}
func adButton() {
if (self.interstitial.isReady)
{
self.interstitial.presentFromRootViewController(self)
self.interstitial = self.createAndLoadInterstitial()
}
}
Use notifictionCenter to call the function
Add the first function in the viewDidLoad() and the second in the adButton()
In Swift 3
//In the gameviewcontroller
NotificationCenter.default.addObserver(self, selector: #selector(YourFunctionNameHere), name: "NSNotificationCreate" as NSNotification.Name, object: nil)
//In the gameScene use this to call the ad
NotificationCenter.default.post(name: "NSNotificationCreate" as NSNotification.Name, object: nil)
In Swift 2
//In the gameviewcontroller
NSNotificationCenter.defaultCenter().addObserver(self, selector: "YourFunctionNameHere", name: "NSNotificationCreate", object: nil)
//In the gameScene use this to call the ad
NSNotificationCenter.defaultCenter().postNotificationName("NSNotificationCreate", object: nil)

Swift Admob Interstitial Error

This is pretty long but it's probably a really easy fix.
Most of this is code, just skip to the bottom and there'll be a tl;dr
Hey, so I've followed about 10 tutorials on getting Admob interstitials to work in my Swift Spritekit game. Except all the tutorials I've seen use an IBAction with a button.
Currently I would like the ads to pop up every once in a while on the menu. (just to begin with, I might change it later).
This all works perfectly, but once I hit the play button (going to a different scene) and then return to the menu scene. (GameScene) The interstitial function no longer happens. There is no error, it just doesn't do it any more until the app is completely closed and re-opened.
Here's the code.
In my GameViewController class I have:
var interstital: GADInterstitial!
And in the GameViewController did load I have:
if let scene = GameScene(fileNamed:"GameScene") {
let skView = self.view as? SKView
skView!.ignoresSiblingOrder = false
scene.scaleMode = .AspectFill
scene.viewController = self
skView!.presentScene(scene)
interstital = GADInterstitial(adUnitID: "ca-app-pub-9776687746813194/9687097060")
let request = GADRequest()
interstital.loadRequest(request)
Also in the GameViewController class I have these functions:
func ShowAd() {
print("doing the showadfunc now")
if (interstital.isReady) {
print("there is an inter ready")
interstital.presentFromRootViewController(self)
interstital = CreateAd()
}
else{
print("The interstitial wasn't ready.")
}
}
func CreateAd() -> GADInterstitial {
let interstital = GADInterstitial(adUnitID: "ca-app-pub-9776687748683194/9687247060")
interstital.loadRequest(GADRequest())
return interstital
}
In my GameScene's (The menu) class I have:
var viewController: GameViewController!
And in my GameScene's class I have this function for displaying an interstitial ad.
func adThing(){
//viewController?.ShowAd()
print("starting the ad function")
let waitForInterstitial = SKAction.waitForDuration(15.0)
let waitForInterstitialShort = SKAction.waitForDuration(3.0)
let showInterstitialAd = SKAction.runBlock({self.viewController?.ShowAd(); print("the function has been called..")})
let waitThenShowInterstitial = SKAction.sequence([showInterstitialAd,waitForInterstitial])
let waitThenShowInterStitialForever = SKAction.repeatActionForever(waitThenShowInterstitial)
//self.runAction(waitThenShowInterStitialForever)
self.runAction(waitForInterstitialShort, completion: {
print("its waited 3 seconds and will now start the ad thingo")
self.runAction(waitThenShowInterStitialForever)
})
print("done")
}
So, I call the ShowAd function (which is located in gameviewcontroller) in my GameScene every 20 seconds, (I have confirmed it at least thinks it is calling the function.) It works perfectly when the app is opened to begin with. But when I change scene and then return to the menu scene (GameScene), the Prints in my GameScene function keep happening, and my code thinks that it is calling the ShowAd function, but it seems that nothing is happening, no interstitials pop up, not even the prints that are in the ShowAd function in the GameViewController.
So it seems like after I change scenes and return, my game forgets what the GameViewController is. If I refer to the GameViewController without a '?' it will crash my game with the error "unexpectedly found nil while unwrapping an optional." So after changing scenes, maybe GameViewController becomes nil? How can I fix this.
Please help me!!! (I'm new to programming in case you can't tell. I know it must be tempting to make a snide comment about my code, it is really bare bones and not that good at the moment.)
Thank you so much if you can help me, and wow.. thanks for reading all this.. ;)
You problem most likely is that once you transition to a new scene the viewController property is set to nil hence a crash if you use !.
In general its not the best practice to reference the viewController in your SKScenes, you should use Delegation or NSNotification Center.
1) Notification Center (easiest way)
In your ViewController where you have the function to show ads add a NSNotificationCenter observer in ViewDidLoad
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(showAd), name: "ShowInterAdKey", object: nil)
(Selector is the function to call and name is the key to reference this observer)
Than in your SKScenes when you want to show the ad you simply post the notification
NSNotificationCenter.defaultCenter().postNotificationName("ShowInterAdKey", object: nil)
2) For delegation examples check out these articles.
http://stephenradford.me/creating-a-delegate-in-swift/
https://www.natashatherobot.com/ios-weak-delegates-swift/
3) I also noticed that you are not preloading the ads before you show them, which is not very efficient and can cause delays showing ads.
You should call
interstital = CreateAd()
in viewDidLoad so it will load the first ad ASAP. Than you should use the adMob delegate method
func interstitialDidDismissScreen(ad: GADInterstitial!) {
// load next ad
interstital = CreateAd()
to immediately load the next ad once the current one is closed.
To use the delegates you can create an extension in ViewController
extension MyViewController: GADInterstitialDelegate {
func interstitialDidReceiveAd(ad: GADInterstitial!) {
print("AdMob interstitial did receive ad from: \(ad.adNetworkClassName)")
}
func interstitialWillPresentScreen(ad: GADInterstitial!) {
print("AdMob interstitial will present")
// pause game/app
}
func interstitialWillDismissScreen(ad: GADInterstitial!) {
print("AdMob interstitial about to be closed")
}
func interstitialDidDismissScreen(ad: GADInterstitial!) {
print("AdMob interstitial closed, reloading...")
interstitial = createAd()
}
func interstitialWillLeaveApplication(ad: GADInterstitial!) {
print("AdMob interstitial will leave application")
// pause game/app
}
func interstitialDidFailToPresentScreen(ad: GADInterstitial!) {
print("AdMob interstitial did fail to present")
}
func interstitial(ad: GADInterstitial!, didFailToReceiveAdWithError error: GADRequestError!) {
print(error.localizedDescription)
}
}
To make sure these get called go to your createAd function and add this line before returning the ad
let interstitial = ...
interstitial.delegate = self
Finally your showAd method should look like this
func showAd() {
print("doing the showadfunc now")
if (interstital.isReady) {
print("there is an inter ready")
interstital.presentFromRootViewController(self)
} else{
print("The interstitial wasn't ready, reloading again.")
interstital = CreateAd()
}
}
4) You can also check out my helper on gitHub if you are looking for a more reusable solution.
https://github.com/crashoverride777/Swift-AdMob-AppLovinTVOS-CustomAds-Helpers
As a general tip you should also follow the swift naming conventions, your func and properties should start with small letters. Only classes, structs, enums and protocols should start with capital letters.
It makes your code harder to read for yourself and on stackoverflow because it is marked blue but shouldn't. You are sometimes doing and sometimes not.
Hope this helps
I'd bet this is your issue:
if (interstital.isReady) {
print("there is an inter ready")
interstital.presentFromRootViewController(self)
interstital = CreateAd()
You're presenting your interstitial and then immediately overwriting your interstitial. You should be implementing the GADInterstitial's delegate methods and calling your func CreateAd() -> GADInterstitial once func interstitialDidDismissScreen(ad: GADInterstitial!) is called.
if your device keeps crashing because of:
interstitial.delegate = self
then put it in your CreatAndLoadInterstitial(), not your viewDidLoad()

Interstitial iAds in SpriteKit?

I'm using SpriteKit for my iOS app, and need some full-screen (or sometimes called "interstitial" iAds to pop up every so often. I can figure out the code for when it happens, but I need to know how to add iAds without necessarily changing the View Controller.
I tried a [tutorial][1] by Techotopia on Interstitial iAds, but to do it I need to transition between actual View Controllers. Well, I tried this, but whenever transitioning back from the iAd view controller to the GameViewController, it messed it all up. The code in the GameViewController.m says that it is initially set to the main menu of my game (an SKScene). So when I try transitioning back from the iAd, instead of keeping the same SKScene up, it goes strait to my main menu scene.
I need these answers:
Is there some way other than using two View Controllers to show Interstitial iAds?
If not, how can I get around this problem?
Would this problem also occur if I were to change my "Interstitial iAds" to "Pre-roll Video iAds?"
-
EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT!
-
I ended up deciding to use crashoverride777's answer, and creating an Objective-C bridging header to convert his Swift code to Objective-C. But when referencing the Ads.swift's variable presentingViewController, it ends up being nil. Here is my code in GameViewController.m:
// Set up interstitial iAds.
Ads *adsClass = [[Ads alloc] init];
Ads *adsInstance = [Ads sharedInstance];
adsInstance.presentingViewController = self;
This, however, doesn't do anything. The function showInterAd gets called from my GameScene.m like it's supposed to, but no ad appears. In my Ads.swift, I added a log to see if presentingViewController is indeed nil.
print("iAd inter showing")
if (self.presentingViewController != nil) {
print("presentingViewController != nil")
iAdInterAdView.frame = presentingViewController.view.bounds
presentingViewController.view.addSubview(iAdInterAdView)
iAdInterAd!.presentInView(iAdInterAdView)
UIViewController.prepareInterstitialAds()
iAdInterAdView.addSubview(iAdInterAdCloseButton)
} else {
print("presentingViewController == nil")
}
The log comes out like this every time: "presentingViewController == nil". I'm not sure what's going wrong, here.
You can make use of my helper I posted on github. Its was made specifically for spritekit and you can call ads from anywhere without delegates etc or changing view controllers.
https://github.com/crashoverride777/Swift-2-iAds-and-AdMob-Helper
I think having a look at that helper should give you a good idea of where to start. Here is a cut down example of how it could look just for iAds Inter ads.
This is in swift so I am not sure if it is still helpful for you.
import iAd
class Ads: NSObject {
// MARK: - Static Properties
/// Shared instance
static let sharedInstance = Ads()
// MARK: - Properties
/// Presenting view controller
var presentingViewController: UIViewController!
/// iAd inter ad
private var iAdInterAd: ADInterstitialAd?
/// iAd inter ad view
private var iAdInterAdView = UIView()
/// iAd inter ad close button
private var iAdInterAdCloseButton = UIButton(type: UIButtonType.System)
// MARK: - Init
private override init() {
super.init()
print("Ads helper init")
iAdInterAd = iAdLoadInterAd()
}
// MARK: - User Methods
/// Show inter ad
func showInterAd() {
iAdShowInterAd()
}
/// Show inter ad randomly (33% chance)
func showInterAdRandomly() {
let randomInterAd = Int(arc4random() % 3)
print("randomInterAd = \(randomInterAd)")
if randomInterAd == 1 {
iAdShowInterAd()
}
}
/// Remove all ads
func removeAllAds() {
print("Removed all ads")
if iAdInterAd != nil {
iAdInterAd!.delegate = nil
iAdInterAdCloseButton.removeFromSuperview()
iAdInterAdView.removeFromSuperview()
}
}
// MARK: - Internal Methods
/// iAd load inter ad
private func iAdLoadInterAd() -> ADInterstitialAd {
print("iAd inter ad loading...")
let iAdInterAd = ADInterstitialAd()
iAdInterAd.delegate = self
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
iAdInterAdCloseButton.frame = CGRectMake(18, 18, 27, 27)
} else {
iAdInterAdCloseButton.frame = CGRectMake(13, 13, 22, 22)
}
iAdInterAdCloseButton.layer.cornerRadius = 11
iAdInterAdCloseButton.setTitle("X", forState: .Normal)
iAdInterAdCloseButton.setTitleColor(UIColor.grayColor(), forState: .Normal)
iAdInterAdCloseButton.backgroundColor = UIColor.whiteColor()
iAdInterAdCloseButton.layer.borderColor = UIColor.grayColor().CGColor
iAdInterAdCloseButton.layer.borderWidth = 2
iAdInterAdCloseButton.addTarget(self, action: "iAdPressedInterAdCloseButton:", forControlEvents: UIControlEvents.TouchDown)
return iAdInterAd
}
/// iAd show inter ad
private func iAdShowInterAd() {
guard iAdInterAd != nil else {
print("iAd inter is nil, reloading")
iAdInterAd = iAdLoadInterAd()
return
}
if iAdInterAd!.loaded {
print("iAd inter showing")
iAdInterAdView.frame = presentingViewController.view.bounds
presentingViewController.view.addSubview(iAdInterAdView)
iAdInterAd!.presentInView(iAdInterAdView)
UIViewController.prepareInterstitialAds()
iAdInterAdView.addSubview(iAdInterAdCloseButton)
//pauseTasks() // not really needed for inter as you tend to show them when not playing.
} else {
print("iAd inter not ready, reloading again...")
iAdInterAd = iAdLoadInterAd()
}
}
/// iAd inter ad pressed close button
func iAdPressedInterAdCloseButton(sender: UIButton) { // dont make private as its called with a selector
print("iAd inter closed")
iAdInterAd!.delegate = nil
iAdInterAdCloseButton.removeFromSuperview()
iAdInterAdView.removeFromSuperview()
iAdInterAd = iAdLoadInterAd()
//resumeTasks() // not really needed for inter as you tend to not show them during gameplay
}
/// Pause tasks in the app/game
private func pauseTasks() {
// Pause app/game, music etc here.
// you could use NSNotifactionCenter or Delegates to call methods in other SKScenes / ViewControllers
}
/// Resume tasks in the app/game
private func resumeTasks() {
// Resume app/game, music etc here.
// you could use NSNotifactionCenter or Delegates to call methods in other SKScenes / ViewControllers
}
}
// MARK: - Delegates iAd Inter
extension Ads: ADInterstitialAdDelegate {
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
print("iAd inter did load")
}
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
print("iAd inter did unload")
}
func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
print("iAd inter error \(error)")
iAdInterAd!.delegate = nil
iAdInterAdCloseButton.removeFromSuperview()
iAdInterAdView.removeFromSuperview()
}
}
Now you simply call
Ads.sharedInstance.presentingViewController = self
in your GameViewController before doing anything else. This will init the helper and preload the first inter ad.
Than you simply call these anywhere you would like inter ads to show
GameData.sharedInstance.showInterAd()
or
GameData.sharedInstance.showInterAdRandomly() // 33% chance for ad
Presenting interstitial in sprite kit is almost identical to in other parts of the app. The only difference is you present the add by calling all the iAd methods with 'self.view'. This gets the view the SKScene is presented in and present the iAd over it
also this can be used to present interstitial without switching view controllers
currentView.requestInterstitialAdPresentation()
to request from in the scene:
self.view?.requestInterstitialAdPresentation()
Notice how in the function call it says request. That is why it only shows up sometimes. When you 'request' an ad the device sends a request to apple asking for an ad. If you get a response back in a reasonable amount of time then the ad will present. If you do not get a response back in a reasonable amount of time (most likely due to poor internet) there the ad won't present because theres nothing to present. However if you request once and it doesn't present, the next time you ask it will definitely present because you already have an ad loaded from the last time you requested but it never got presented.

iAd Interstitials not showing consistently? And not at all on the simulator

iAd interstitials aren't showing up at all on the iPhone simulator, and they don't show up consistently on my iPhone. I've gone to the Developer settings, changed the fill rate to 100%, and turned on Unlimited Ad Presentation. No difference... an interstitial will generally show the first time it's supposed to, and then won't show again for anywhere from a few minutes to fifteen minutes. No idea what is causing the difference in time.
Also, there doesn't seem to be a way to track if the interstitial is going to show or not / if it actually showed or didn't. I realize there's an interstitial delegate, but it seems that isn't used anymore. The way I am calling my interstitial is using viewController.interstitialPresentationPolicy = ADInterstitialPresentationPolicy.Automatic
Thanks!
So it seems that using requestInterstitialAdPresentation is intended to only be used when your ADInterstitialPresentationPolicy is set to Automatic. When implementing your interstitials using a Manual ADInterstitialPresentationPolicy you must use presentInView to present the ad at your own intervals. When presenting your interstitial in this manner it does not load with its own close button to dismiss itself. So, what I've done is created a UIView to present the interstitial in and used the interstitials delegate methods to dismiss the UIView. The inconsistency with receiving an ad from the iAd network still arises when testing. Sometimes you receive an ad, sometimes it fails to load which allows us to request a new ad, and sometimes nothing happens at all. This just seems to be the nature of iAd's interstitials.
import UIKit
import iAd // Import iAd
class ViewController: UIViewController, ADInterstitialAdDelegate { // Include the delegate
var iAdInterstitial = ADInterstitialAd() // Our ad
var iAdInterstitialView = UIView() // View to present our ad in
var adLoaded = false // Bool to keep track if an ad is loaded or not
override func viewDidLoad() {
super.viewDidLoad()
setupAd()
}
func setupAd() {
// Set presentation to manual so we can choose when to present the interstitial
// Setting this will also fetch an interstitial ad for us
self.interstitialPresentationPolicy = ADInterstitialPresentationPolicy.Manual
iAdInterstitial.delegate = self // Set the delegate
// Make our view the same size as the view we will be presenting in
iAdInterstitialView.frame = self.view.bounds
}
func requestNewAd() {
// This will fetch an ad for us
ViewController.prepareInterstitialAds()
println("Requesting new ad")
}
#IBAction func presentAdButton(sender: AnyObject) {
if (adLoaded) {
// We have an ad that is loaded so lets present it
self.view.addSubview(iAdInterstitialView)
iAdInterstitial.presentInView(iAdInterstitialView)
}
else {
// No ad has been loaded
println("Ad not loaded")
}
}
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
// Kinda works as expected
// Sometimes is called prematurely
// Sometimes takes minutes after ad is dismissed to be called
println("interstitialAdDidUnload")
// Get new ad
adLoaded = false
iAdInterstitialView.removeFromSuperview()
requestNewAd()
}
func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
// Failed to load ad so lets try again
println("didFailWithError: \(error)")
requestNewAd()
}
func interstitialAdWillLoad(interstitialAd: ADInterstitialAd!) {
// There is an ad and it has begun to download
println("interstitialAdWillLoad")
}
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
// We got an ad
println("interstitialAdDidLoad")
adLoaded = true
}
func interstitialAdActionShouldBegin(interstitialAd: ADInterstitialAd!, willLeaveApplication willLeave: Bool) -> Bool {
println("interstitialAdActionShouldBegin")
return true;
}
func interstitialAdActionDidFinish(interstitialAd: ADInterstitialAd!) {
// Done with this ad. Lets get a new one
println("interstitialAdActionDidFinish")
iAdInterstitialView.removeFromSuperview()
adLoaded = false
requestNewAd()
}

Resources