0

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:

  1. Is there some way other than using two View Controllers to show Interstitial iAds?
  2. If not, how can I get around this problem?
  3. 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.

Christian Kreiter
  • 610
  • 1
  • 5
  • 16
  • Translations: `iAdInterAdCloseButton = [UIButton buttonWithType:UIButtonTypeSystem]` and `if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)` – Ewan Mellor Nov 29 '15 at 00:37
  • why is it causing you troubles?. That first button code is something that is new with swift 2.0, as in it was slightly different before in swift. In object C it should look like this i think UIButton *iAdInterAdCloseButton = [UIButton buttonWithType:UIButtonTypeSystem]; – crashoverride777 Nov 29 '15 at 00:44
  • in regards to the device code. Is your app Universal? Otherwise it won't get called as far as I know? You can read this and try out the possible ways to check if device is an iPad http://stackoverflow.com/questions/10167221/ios-detect-if-user-is-on-an-ipad – crashoverride777 Nov 29 '15 at 00:45
  • I can help you as much as i can with the limited knowable I have about obj c. The code for the most part is pretty simple I believe so I dont think it should be that hard. Not sure if obj c has things such as extensions, which is what I used for the Delegates. – crashoverride777 Nov 29 '15 at 00:49
  • I was also thinking, why dont you use the swift file and use a bridging header in that obj c project. Its probably a good idea in general for older apps https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html – crashoverride777 Nov 29 '15 at 00:53
  • Ewan's answer was correct. It turns out the only reason my computer is giving me a hard time is because the code prediction isn't working today. I think I've got it from here. Thanks again, I'll let you know if there are any problems. – Christian Kreiter Nov 29 '15 at 01:02

2 Answers2

1

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
crashoverride777
  • 10,581
  • 2
  • 32
  • 56
  • This is seemingly a great answer for me. Thank you. However, it doesn't seem to be working. I've been putting together all the pieces, but it's not working. I get the logs saying "iAd inter ad loading..." and "iAd inter did load" and so on. But the ads aren't showing up on the screen. I'm not sure what's wrong. Would you like me to post my code? I'm pretty sure it's identical to the necessary code. – Christian Kreiter Nov 27 '15 at 16:20
  • hey you are welcome. I just made a new xCode game project and copied the above code and it works no problem. Are you calling Ads.sharedInstance.showInterAd() or Ads.sharedInstance.showInterAdRandomly()?. The random one only has a 33% chance of showing. Also sometimes the simulator is a pain with testing and you need to wait a couple of hours. – crashoverride777 Nov 28 '15 at 16:49
  • You need to call Ads.sharedInstance.presentingViewController = self in your game View Controller in viewDidLoad, preferably before loading your first scene. Than in your scenes you need to call the ...showInterAd methods and the ads should show. Let me know how it goes – crashoverride777 Nov 28 '15 at 16:51
  • Ugh, I created a new project using your code and tried again. Apparently, that github link you sent me was confusing and even useless in *my* situation. Well I'm all good now. Thanks. – Christian Kreiter Nov 28 '15 at 18:17
  • Yeah the github one is the full helper, i.e. Banner and inter ads from both apple and google. Google ads need a lot of frameworks and other setups. – crashoverride777 Nov 28 '15 at 18:35
  • I'm having trouble converting it to Objective-C, which I need to do for a specific project. If you could convert the whole things for me and re-post your answer with an edit of Objective-C code, that would be great! If not, there are a few specific lines I'm having trouble with. I'll edit my question for you. – Christian Kreiter Nov 29 '15 at 00:09
  • Hey, I am so sorry I have zero objective c knowledge. When I posted my answer I did realise that you asked for obj c. – crashoverride777 Nov 29 '15 at 00:24
  • What lines are your main issues? – crashoverride777 Nov 29 '15 at 00:25
  • Check my question again. – Christian Kreiter Nov 29 '15 at 00:33
  • What does the `sharedInstance()` do? Could I just as easily remove it and call `Ads.presentingViewController = self`? – Christian Kreiter Nov 29 '15 at 01:27
  • not really the shared instance is basically creating the helper as a singleton. So if you want to do what you said you would have to manual init your helper in every skScene etc. In swift you can make it 1 line with a static property (sharedInstance). In obj c it would look something like mentioned here "http://stackoverflow.com/questions/5381085/how-to-create-singleton-class-in-objective-c" – crashoverride777 Nov 29 '15 at 02:02
  • I decided to use a bridging header instead. But when I do so, even though I go into my `GameViewController.m` and set the `Ads.swift`'s `presentingViewController` to be the `GameViewController`, it doesn't work. In my `iAdShowInterAd()`, I set a `print()` to see if the `presentingViewController` is nil. It ends up being nil. What's wrong? I'll edit my question to show you what I mean. – Christian Kreiter Dec 02 '15 at 20:42
  • hey, I am sorry to may have caused you issues with my swift solution, I can feel you are close. I dont know why your view controller is returning nil. Are you calling the Ads.sharedInstance.presentingViewController = self in your viewControllers "ViewDidLoad" method or are you creating a new presentingViewController property? The main reason it must return nil is because you are not setting the Ads.swift property presentingViewController to your gameViewController. Sorry again my objective c knowledge is so limited – crashoverride777 Dec 03 '15 at 14:21
  • That's alright, I'm thankful for your help. Yes, I am calling the Swift's property `presentinvViewController`, not creating a new one. – Christian Kreiter Dec 03 '15 at 14:32
  • I am stumped them. This is literally the last step you need to make it work. As an alternative have you tried going the the ads.swift helper and go to all the methods that use the presentingViewController var. (private func showInterAd() etc ). You than take out those lines, should only be 1 -2 if you just use inter ads, and paste them into new methods you create in your gameViewController. Than in your ads.swift in the spots you just cut the lines out you now call the new methods you created in your view controller by either using NSNotifcationCenter or protocols/delegates. – crashoverride777 Dec 03 '15 at 14:54
  • Than in your viewController in the new methods just replace presentingViewController with self. Otherwise maybe some community member with better obj c knowledge can let you know why the presentingvyiewcontroler: UiViewController! property is nil although you set it to self in your ViewController – crashoverride777 Dec 03 '15 at 14:56
  • maybe try reading these and see if you can make the necessary adjustments to present to a viewController from another class thats not a viewController "http://stackoverflow.com/questions/19438538/present-a-uiviewcontroller-from-an-nsobject" or "http://stackoverflow.com/questions/3760286/call-presentmodalviewcontroller-from-nsobject-class" or "http://stackoverflow.com/questions/21924528/how-to-present-a-slcompose-view-controller-from-nsobject-class" or "http://stackoverflow.com/questions/22904164/presentviewcontroller-from-custom-tablecell-in-xib/22904272#22904272" – crashoverride777 Dec 03 '15 at 15:05
  • No, that won't work. I guess I'll just find another solution somewhere else. Your solution definitely worked, and I'll keep it in mind for all my future Swift games. Thanks again for your help :) – Christian Kreiter Dec 03 '15 at 18:16
  • Hey, sorry again. Keep me posted if you found a solution – crashoverride777 Dec 05 '15 at 12:56
0

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.

AwesomeTN
  • 398
  • 2
  • 5
  • 16
  • That works wonderfully! So now I have two questions. **1.** How would I call that function from an SKScene, rather than from the GameViewController? Would it be `[[[GameViewController.m alloc] init] requestInterstitialAdPresentation];`? **2.** Why do the iAds only show up sometimes? I have to wait a while before they will work. – Christian Kreiter Nov 18 '15 at 18:34
  • It turns out that my code snippet doesn't actually work. Any other ideas? – Christian Kreiter Nov 18 '15 at 18:44
  • that should work, can you please show the code in your scene – AwesomeTN Nov 18 '15 at 18:59
  • show more code not just that sniper, show whats it in – AwesomeTN Nov 18 '15 at 22:06