iOS Swift: iAd Interstitial leaves black screen after dismissed - ios

I'm trying to add ads into my game, every time the user loses I present my game over view controller. On occasions, when an ad loads I have a full screen interstitial is shown on top of the game over screen.
My problem is the interstitial doesn't come with a close button, so I added one so the user doesn't feel forced to tap on the ad every time it comes up. When the user clicks the close button, the ad is dismissed and the game over view controller is once again shown. Problem is, once in a while (at random, maybe the first time or after a couple of runs through) the ad is dismissed and leaves a black screen.
Any ideas why this is happening? I've been scratching my head for a few days trying to figure this out.
Thanks!! Here is my code:
// Ad variables
var interstitialAdView: UIView = UIView()
var interstitial:ADInterstitialAd!
var intersitialTracker = false
var closeButton:UIButton!
override func viewDidAppear(animated: Bool) {
if !intersitialTracker {
loadInterstitialAd()
}
}
// Buttons to restart game, and return to home screen
#IBAction func restartButtonPressed(sender: AnyObject) {
intersitialTracker = false
interstitial = nil
delegate?.gameOverViewControllerDidPressRestart(self)
}
#IBAction func homeButtonPressed(sender: AnyObject) {
interstitial = nil
delegate?.gameOverViewControllerDidPressHomebutton(self)
}
func loadInterstitialAd() {
if interstitial != nil {
interstitial.delegate = nil
}
interstitial = ADInterstitialAd()
interstitial.delegate = self
intersitialTracker = true
}
func interstitialAdWillLoad(interstitialAd: ADInterstitialAd!) {
}
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
interstitialAdView = UIView()
interstitialAdView.frame = self.view.bounds
view.addSubview(interstitialAdView)
closeButton = UIButton(frame: CGRect(x: 20, y: 20, width: 20, height:20))
closeButton.setBackgroundImage(UIImage(named: "close"), forState: UIControlState.Normal)
closeButton.addTarget(self, action: Selector("close"), forControlEvents: UIControlEvents.TouchDown)
self.view.addSubview(closeButton)
interstitialAd.presentInView(interstitialAdView)
}
// Called when user leaves the ad
func interstitialAdActionDidFinish(interstitialAd: ADInterstitialAd!) {
interstitialAdView.removeFromSuperview()
closeButton.removeFromSuperview()
interstitial = nil
closeButton = nil
}
// Called when user goes in ad
func interstitialAdActionShouldBegin(interstitialAd: ADInterstitialAd!, willLeaveApplication willLeave: Bool) -> Bool {
return true
}
func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
}
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
interstitialAdView.removeFromSuperview()
closeButton.removeFromSuperview()
interstitial = nil
closeButton = nil
}
// Close button for ads
func close() {
if closeButton != nil {
interstitialAdView.removeFromSuperview()
closeButton.removeFromSuperview()
interstitial = nil
closeButton = nil
}
}
Sorry for the lengthy post, thanks!!!!!

Not entirely sure why this is happening to you but one way to work around it is to call the function that shows the game over screen. I can't tell exactly which line of code does by the above code you have given but it could look something like this;
func close() {
if closeButton != nil {
interstitialAdView.removeFromSuperview()
closeButton.removeFromSuperview()
interstitial = nil
closeButton = nil
self.GameOverScreen()
}

Had the same problem, where it would show a black screen after closing the ad.
I ended up using a UIViewController to contain the ad, and then dismissed the view controller upon the ad finishing. This is much cleaner and gets you the presenting transition for free.
Here's what the code looks like to present the ad:
- (void)interstitialAdDidLoad:(ADInterstitialAd *)interstitialAd
{
UIViewController *controller = [[UIViewController alloc] init];
[self.iadInterstitial presentInView:controller.view];
// Nearly everyone has this logic in their UIViewController. So you may
// have to replace 'self.viewController' with just 'self'.
[self.viewController presentViewController:controller animated:YES completion:nil];
}
Here's what the code looks like to dismiss:
- (void)interstitialAdActionDidFinish:(ADInterstitialAd *)interstitialAd
{
[self.viewController dismissViewControllerAnimated:YES completion:^{
self.iadInterstitial.delegate = nil;
self.iadInterstitial = nil;
}];
}

I figured it out after some time, I removed all statements where interstitial was assigned nil, instead I just did it when I exited the view controller. The screen stopped getting black after that. No sure why this worked, but it did. If someone wants to shine some light it will be welcomed!

Related

Portrait/Landscape display ios swift 3

I have an application with 2 views.
On the first view, the user enter a login, hits on search button.
The application retrieves through an api information about the login,
is redirected on the second view where it displays information about the login.There is a back button on the second view to go back on the first view to be able to search a different login
In the second view, I treat both cases (Landscape/Portrait)
What happens is the following : first time I enter the login, Portrait and landscape cases are well treated on the result view.
When I go back and search a new login, It will only display the mode in which you entered the second time (if you entered in portrait mode, it will
only display in portrait mode, the same with landscape) Is there something that I should be doing ?
here is the code for the first view :
var login = ""
class FirstViewController: UIViewController {
#IBOutlet weak var Input: UITextField!
#IBAction func sendlogin(_ sender: UIButton) {
if let text = Input.text, !text.isEmpty {
login = text
performSegue(withIdentifier: "callaffiche", sender: self)
return
} else {
return
}
}
here is the code for the second view (I will only post viewDidLoad, the back button creation along its function and the creation of the imageuser as there are many objects. But all of them are created with the same principle ) AfficheElemts calls the creation of every single object( ButtonBackAffiche, ImageAffiche are called within AfficheElements
override func viewDidLoad() {
super.viewDidLoad()
print("ds viewdidload")
let qos = DispatchQoS.userInitiated.qosClass
let queue = DispatchQueue.global(qos: qos)
queue.sync {
self.aut.GetToken(completionHandler: { (hasSucceed) in
if hasSucceed {
print("good")
DispatchQueue.main.async {
self.AfficheElements()
}
} else {
print("bad")
}
})
}
}
func ButtonBackAffiche () {
let button = UIButton()
button.restorationIdentifier = "ReturnToSearch"
button.setTitle("Back", for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
button.isEnabled = true
button.addTarget(self, action: #selector(ReturnToSearch(button:)), for: .touchUpInside)
if UIDevice.current.orientation.isPortrait {
button.frame = CGRect (x:CGFloat(180),y:CGFloat(600),width:50,height:30)
} else {
button.frame = CGRect (x:CGFloat(350),y:CGFloat(360),width:50,height:30)
}
self.view.addSubview(button)
}
func ImageAffiche () {
//Get image (Data) from URL Internet
let strurl = NSURL(string: image_url)!
let dtinternet = NSData(contentsOf:strurl as URL)!
let bongtuyet:UIImageView = UIImageView ()
if UIDevice.current.orientation.isPortrait {
print("portrait ds imageview")
bongtuyet.frame = CGRect (x:10,y:80,width:30,height:30)
} else {
print("landscape ds imageview")
bongtuyet.frame = CGRect (x:CGFloat(200),y:CGFloat(80),width:90,height:120)
}
bongtuyet.image = UIImage(data:dtinternet as Data)
self.view.addSubview(bongtuyet)
}
func ReturnToSearch(button: UIButton) {
performSegue(withIdentifier: "ReturnToSearch", sender: self)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
print("ds viewwilltransition")
if UIDevice.current.orientation.isPortrait {
print("portrait")
} else {
print("landscape")
}
while let subview = self.view.subviews.last {
subview.removeFromSuperview()
}
AfficheElements()
}
One last thing, I have put traces in the code and the creation of the objects, it goes through the right portion of the code but does not display the objects at the right locations.
Thanks #Spads for taking time to help me.
I finally figured it out. I was not calling the function AfficheElements
int the main queue.
DispatchQueue.main.async {
self.AfficheElements()
}
in viewWillTransition solved it.

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.

Using AdMob interstitial ads in iOS game applications and Swift

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.

How to add iAd in SpriteKit and deactivate it when a scene changes?

In my game file GameScene, I wrote code for iAd to be displayed there.
func addiAd(){
bannerView = ADBannerView(adType: .Banner)
bannerView.delegate = self
bannerView.hidden = true
bannerView.frame = CGRectOffset(bannerView.frame, 0.0, 0.0)
bannerView.center = CGPointMake(bannerView.center.x,
(view?.bounds.size.height)! - bannerView.frame.size.height/2)
view!.addSubview(bannerView)
print("iAd is working")
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
bannerView.hidden = false
}
func bannerViewActionDidFinish(banner: ADBannerView!) {
bannerView.removeFromSuperview()
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
bannerView.hidden = true
}
Well, it first looks like it works, but not perfectly because when a scene has transitioned to another game scene file called GameOverScene, my bannerView does not disappear and stays where it appeared forever until the run is over. I want to deactivate this. Is my code wrong written above? In my source code, in total, I want two adBanner views in GameScene and GameOverScene respectively. My assumption for the error is that I did not write those code in GameViewController, but I am unsure about it. Could you show me how to implement it and explain me where it has to be written?
In the iAd delegate methods you could change the alpha properties of your banner. For example:
func bannerViewDidLoadAd(banner: ADBannerView!) {
bannerView.alpha = 1.0
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
bannerView.alpha = 0.0
}
And then when you're changing scenes or want to make sure that the iAd banner does not appear you could set its hidden property. For example:
func hideBanner() {
// Call whenever you don't want the ADBannerView to be on screen
bannerView.hidden = true
}
func showBanner() {
// Call when you want the ADBannerView to be on screen
bannerView.hidden = false
}
This would require you to update your addiAd function also: Change bannerView.hidden = true to bannerView.alpha = 0.0.
And finally you shouldn't be removing the iAd banner from the Superview here:
func bannerViewActionDidFinish(banner: ADBannerView!) {
bannerView.removeFromSuperview()
}

iAd interstitial ads not working on sprite kit app Xcode swift

I'm trying to implement interstitial ads with iAd into my spriteKit game. My code is as follows:
class ViewController: UIViewController, ADInterstitialAdDelegate {
var interAd = ADInterstitialAd()
var interAdView: UIView!
var closeButton = UIButton.buttonWithType(UIButtonType.System) as! UIButton
override func viewDidAppear(animated: Bool) {
closeButton.frame = CGRectMake(10, 10, 20, 20)
closeButton.layer.cornerRadius = 10
closeButton.setTitle("x", forState: .Normal)
closeButton.setTitleColor(UIColor.blackColor(), forState: .Normal)
closeButton.backgroundColor = UIColor.whiteColor()
closeButton.layer.borderColor = UIColor.blackColor().CGColor
closeButton.layer.borderWidth = 1
closeButton.addTarget(self, action: "close:", forControlEvents: UIControlEvents.TouchDown)
}
func close(sender: UIButton) {
closeButton.removeFromSuperview()
interAdView.removeFromSuperview()
}
func loadAd() {
println("load ad")
interAd = ADInterstitialAd()
interAd.delegate = self
}
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
println("ad did load")
interAdView = UIView()
interAdView.frame = self.view!.frame
view!.addSubview(interAdView)
interAd.presentInView(interAdView)
UIViewController.prepareInterstitialAds()
interAdView.addSubview(closeButton)
}
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
}
func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
println("failed to receive")
println(error.localizedDescription)
closeButton.removeFromSuperview()
interAdView.removeFromSuperview()
}
This code delivers me more problems than it does results. Unfortunately I am a beginner at implementing any sort of ads into an app and I don't know how I can change any of this in my favour.
One issue I get is that output traces ad did load (as you can see thats supposed to be traced once the ad is presented) however when ad did load is traced no ad is presented. I wait for at least 3 minutes but nothing happens.
Another issue I have is this WARNING: More than 10 instances of ADBannerView or ADInterstitialView currently exist. This is a misuse of the iAd API, and ad performance will suffer as a result. This message is printed only once., but this is printed after the function to load the ad is called once or twice.

Resources