How can I make the singleton of AdMob Interstitial in Swift? - ios

I'm using AdMob interstitial on my app and try to make the implementation easier.
I just found the singleton files of it in Objective-C, I can't remake them in Swift though.
How can I rewrite them in Swift?
And if I shouldn't use singleton for this implementation with some causes, please let me know.
AdMob.h
#import <Foundation/Foundation.h>
#import "AdsID.h"
#import GoogleMobileAds;
#interface AdMob : NSObject<GADBannerViewDelegate,GADInterstitialDelegate>
#property(nonatomic) GADBannerView *GADRecView; #property(nonatomic, strong) GADInterstitial *interstitial;
+ (AdMob *)sharedIncetance;
-(void)loadAdMobBanner:(UIViewController*)vc view:(UIView*)view x:(int)x y:(int)y;
-(void)loadAdMobInste:(UIViewController*)vc rate:(float)rate;
#end
AdMob.m
#import "AdMob.h"
#implementation AdMob
static AdMob *sharedData_ = nil;
+ (AdMob *)sharedInstance{
#synchronized(self){
if (!sharedData_) {
sharedData_ = [[AdMob alloc]init];
}
}
return sharedData_;
}
- (id)init {
self = [super init];
if (self) {
self.interstitial = [self createAndLoadInterstitial];
}
return self;
}
- (GADInterstitial *)createAndLoadInterstitial {
GADInterstitial *interstitial =
[[GADInterstitial alloc] initWithAdUnitID:#"XXXXXX"];
interstitial.delegate = self;
[interstitial loadRequest:[GADRequest request]];
return interstitial;
}
-(void)loadAdMobInste:(UIViewController*)vc{
if ([self.interstitial isReady]) {
[self.interstitial presentFromRootViewController:vc];
}
}
- (void)adViewDidReceiveAd:(GADBannerView *)bannerView {
NSLog(#"Banner adapter class name: %#", bannerView.adNetworkClassName);
}
#end
ViewController
[[AdMob sharedIncetance] loadAdMobInste:[self btk_parentViewController]];
UPDATE
I could implement it in Swift, but the error "whose view is not in the window hierarchy!" caused when I did the following them and ad didn't show:
Load interstitial in ViewController
Show interstitial in ViewController
Load interstitial in SecondViewController
Show interstitial in SecondViewController (ad didn't show and the error appeared)
If I used the code in Objective-C, ad showed and the error didn't appear.
AdMob
import Foundation
import GoogleMobileAds
class AdMob : NSObject, GADBannerViewDelegate, GADInterstitialDelegate{
static var sharedData_: AdMob? = nil
var interstitial: GADInterstitial?
class func sharedInstance() -> AdMob? {
let lockQueue = DispatchQueue(label: "self")
lockQueue.sync {
if sharedData_ == nil {
sharedData_ = AdMob()
}
}
return sharedData_
}
override init() {
super.init()
interstitial = createAndLoadInterstitial()
}
func createAndLoadInterstitial() -> GADInterstitial? {
let interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
interstitial.delegate = self
interstitial.load(GADRequest())
return interstitial
}
func loadInste(_ vc: UIViewController?) {
if interstitial?.isReady == true {
self.interstitial?.present(fromRootViewController: vc!)
}else{
print("Ad was not realy")
}
}
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
interstitial = createAndLoadInterstitial()
}
func interstitialDidReceiveAd(_ ad: GADInterstitial) {
print("interstitialDidReceiveAd")
}
func interstitial(_ ad: GADInterstitial, didFailToReceiveAdWithError error: GADRequestError) {
print("interstitial:didFailToReceiveAdWithError: \(error.localizedDescription)")
}
func interstitialWillPresentScreen(_ ad: GADInterstitial) {
print("interstitialWillPresentScreen")
}
func interstitialWillDismissScreen(_ ad: GADInterstitial) {
print("interstitialWillDismissScreen")
}
func interstitialWillLeaveApplication(_ ad: GADInterstitial) {
print("interstitialWillLeaveApplication")
}
}
AppDelegate
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var navigationController: UINavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
if let window = window {
let mainVC = ViewController()
navigationController = UINavigationController.init()
navigationController = UINavigationController(rootViewController: mainVC)
navigationController?.navigationBar.isHidden = true
window.rootViewController = navigationController
window.makeKeyAndVisible()
}
return true
}
}
ViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
AdMob.sharedInstance()?.loadInste(self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let secondVC = SecondViewController()
self.navigationController?.pushViewController(secondVC, animated: true)
if AdMob.sharedInstance()?.interstitial?.isReady == true {
AdMob.sharedInstance()?.interstitial?.present(fromRootViewController: self)
} else {
print("Ad wasn't ready")
}
}
}
SecondViewController
import GoogleMobileAds
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
AdMob.sharedInstance()?.loadInste(self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.navigationController?.popViewController(animated: true)
if AdMob.sharedInstance()?.interstitial?.isReady == true {
AdMob.sharedInstance()?.interstitial?.present(fromRootViewController: self)
} else {
print("Ad wasn't ready")
}
}
}

Here the issue is that you present the AD after push the view controller so self view removed from window hierarchy that's why you getting this error "whose view is not in the window hierarchy!"
Note : Push, Present or Pop ViewController after present the AD
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Present ad First and then Push view controller
if AdMob.sharedInstance()?.interstitial?.isReady == true {
AdMob.sharedInstance()?.interstitial?.present(fromRootViewController: self)
} else {
print("Ad wasn't ready")
}
let secondVC = SecondViewController()
self.navigationController?.pushViewController(secondVC, animated: true)
}

Related

How to show Interstitial Ad in SKScene? - SpriteKit

I want to show an Interstitial Ad in the GameOverScene which is a SKScene that is shown through the main ViewController. With the code shown below the ad prints (“Ad Wasn’t Ready”) how do I fix this to work properly in the Game Over SKScene?
import GoogleMobileAds
import SpriteKit
import GameplayKit
import SwiftUI
class GameOverScene: SKScene {
var interstitial: GADInterstitial!
override func didMove(to view: SKView) {
interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
let request = GADRequest()
interstitial.load(request)
if interstitial.isReady {
interstitial.present(GameViewController())
} else {
print("Ad wasn't ready")
}
}
}
You're presenting ad before the load is completed. You need to show in delegate callback once the Ad is loaded successfully.
override func viewDidLoad() {
super.viewDidLoad()
interstitial = createAndLoadInterstitial()
}
func createAndLoadInterstitial() -> GADInterstitial {
var interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
interstitial.delegate = self
interstitial.load(GADRequest())
return interstitial
}
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
interstitial = createAndLoadInterstitial()
}
Show the ad in load success callback.
/// Tells the delegate an ad request succeeded.
func interstitialDidReceiveAd(_ ad: GADInterstitial) {
print("interstitialDidReceiveAd")
if ad.isReady {
ad.present(fromRootViewController:self)
} else {
print("Ad wasn't ready")
}
}
You can find more details here, https://developers.google.com/admob/ios/interstitial

View turns into black screen when i close rewarded video ad in iOS

I have successfully implemented AdMob rewarded video ad. I have implemented it in GameViewController class and calling it into gameScene using NotificationCenter method and it is working. When i close rewarded video after video completion, my GameScene turns into black screen. Here is my code of GameViewController:
import UIKit
import SpriteKit
import GoogleMobileAds
class GameViewController: UIViewController, GADBannerViewDelegate, GADRewardBasedVideoAdDelegate, UIAlertViewDelegate{
var rewardBasedVideo:GADRewardBasedVideoAd?
var adRequestInProgress = false
override func viewDidLoad() {
super.viewDidLoad()
// create our scene:
let menuScene = MenuScene
let skView = self.view as! SKView
skView.showsPhysics = true
skView.ignoresSiblingOrder = true
let size = CGSize(width:590, height:390)
menuScene.size = CGSize(width: size.width, height: size.height)
skView.presentScene(menuScene)
skView.translatesAutoresizingMaskIntoConstraints = false
NotificationCenter.default.addObserver(self, selector: #selector(self.videoReward), name:NSNotification.Name(rawValue:"showVideoRewardAd"), object: nil)
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask{
return UIInterfaceOrientationMask.landscape;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden : Bool {
return true
}
func videoReward(){
rewardBasedVideo = GADRewardBasedVideoAd.sharedInstance()
rewardBasedVideo?.delegate = self
rewardBasedVideo?.load(GADRequest(),
withAdUnitID: "ca-app-pub-3940256099942544/1712485313")
if rewardBasedVideo?.isReady == true {
rewardBasedVideo?.present(fromRootViewController: self)
} else {
UIAlertView(title: "Reward based video not ready",
message: "The reward based video didn't finish loading or failed to load",
delegate: self.view,
cancelButtonTitle: "ok").show()
}
}
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
didFailToLoadWithError error: Error) {
adRequestInProgress = false
print("Reward based video ad failed to load: \(error.localizedDescription)")
}
func rewardBasedVideoAdDidReceive(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
adRequestInProgress = false
rewardBasedVideo?.present(fromRootViewController: self)
print("Reward based video ad is received.")
}
}
My GameScene Code where i am calling rewarded video looks like this:
override func touchesBegan(_ touches: Set<UITouch>, with
event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let nodeTouched = atPoint(location)
if let gameSprite = nodeTouched as? GameSprite{
gameSprite.onTap()
}
if nodeTouched.name == "play" {
NotificationCenter.default.post(name: NSNotification.Name(rawValue:"showVideoRewardAd"), object:nil)
}
}
Now tell me, Where is my mistake?

GADInterstitial duplicates in view hierarchy

I have an implementation of GADInterstitial
class AdsManager {
let adsAppId = MY_ID
let fullScreenAdUnitId = MY_ID
static let manager: AdsManager = AdsManager()
private var interstitial: GADInterstitial!
private init () {
createAndLoadInterstitial()
}
func presentInterstitial(fromViewController viewController: UIViewController) {
if interstitial.isReady {
interstitial.present(fromRootViewController: viewController)
}
else {
print("Interstitial is not ready")
}
createAndLoadInterstitial()
}
private func createAndLoadInterstitial() {
//TODO: replace test ad unit id with production
interstitial = GADInterstitial(adUnitID: MY_ID)
interstitial.load(GADRequest())
}
}
and I show this ads like this:
func touchedButton(_ sender: UIButton) {
AdsManager.manager.presentInterstitial(fromViewController: self)
}
Everythink works and looks fine but when I was debugging I found something strange:
Four instances of the same view. Anyone know is it good? Or maybe I made a mistake in my AdsManager? Maybe Firebase implementation mistake?
The number of GADUIKitWebView's is dependent on the type of advertisement that is presented. A video, image, and text ad will all have different layouts. Based on the amount of memory being used I would assume it is correct.
View hierarchy of an interactive GADInterstitial advertisement:
Besides that, you do have a problem with your implementation. Your problem is in this function:
func presentInterstitial(fromViewController viewController: UIViewController) {
if interstitial.isReady {
interstitial.present(fromRootViewController: viewController)
}
else {
print("Interstitial is not ready")
}
createAndLoadInterstitial() // PROBLEM
}
You should move createAndLoadInterstitial() into the else so you only load another GADInterstitial when you actually need one. For example:
func presentInterstitial(fromViewController viewController: UIViewController) {
if interstitial.isReady {
interstitial.present(fromRootViewController: viewController)
}
else {
print("Interstitial is not ready")
createAndLoadInterstitial()
}
}
In addition to this you should implement the GADInterstitial delegate methods and load another GADInterstitial only after it has dismissed the screen. For example:
/// Called just after dismissing an interstitial and it has animated off the screen.
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
print("interstitialDidDismissScreen")
createAndLoadInterstitial()
}

admob interstitial ad is never ready [duplicate]

This question already exists:
admob interstitial alway returns false
Closed 6 years ago.
i have this game and i created 3 funcions in my gameviewcontroller and here they are
func getInterstitialAd(){
interstitial = GADInterstitial(adUnitID: "ca-app-pub-1782852253088296/5018877964")
let requestInterstitial = GADRequest()
interstitial.load(requestInterstitial)
}
func showAd() {
if (interstitial.isReady == true){
interstitial.present(fromRootViewController: GameViewController())
}else{
print("ad wasn't ready")
interstitial = createAd()
}
}
func createAd() -> GADInterstitial{
let interstital = GADInterstitial(adUnitID: "ca-app-pub-1782852253088296/5018877964")
interstitial.load(GADRequest())
return interstital
}
and in one of my scene called StartMenu , i call those function
var viewController: GameViewController!
and then i call the functions
viewController.getInterstitialAd()
viewController.showAd()
but it always returns ad not ready , and false for interstitial.isReady,
but also the getInterstitial function is always called .
can someone help with that please
Create a new swift file AdMobDelegate :-
import UIKit
import GoogleMobileAds
class AdMobDelegate: NSObject, GADInterstitialDelegate {
var interstitialView: GADInterstitial!
func createAd() -> GADInterstitial {
interstitialView = GADInterstitial(adUnitID: "Your Key")
interstitialView.delegate = self
let request = GADRequest()
interstitialView.loadRequest(request)
return interstitialView
}
func showAd() {
if interstitialView != nil {
if (interstitialView.isReady == true){
interstitialView.present(fromRootViewController:currentVc)
} else {
print("ad wasn't ready")
interstitialView = createAd()
}
} else {
print("ad wasn't ready")
interstitialView = createAd()
}
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
print("Ad Received")
if ad.isReady {
interstitialView.present(fromRootViewController: currentVc)
}
}
func interstitialDidDismissScreen(ad: GADInterstitial!) {
print("Did Dismiss Screen")
}
func interstitialWillDismissScreen(ad: GADInterstitial!) {
print("Will Dismiss Screen")
}
func interstitialWillPresentScreen(ad: GADInterstitial!) {
print("Will present screen")
}
func interstitialWillLeaveApplication(ad: GADInterstitial!) {
print("Will leave application")
}
func interstitialDidFailToPresentScreen(ad: GADInterstitial!) {
print("Failed to present screen")
}
func interstitial(ad: GADInterstitial!, didFailToReceiveAdWithError error: GADRequestError!) {
print("\(ad) did fail to receive ad with error \(error)")
}
}
Now you can use the object of this delegate class in other files as follows :-
//Define admobdelegate as global variable
var admobDelegate = AdMobDelegate()
//Declare a global variable currentVc to hold reference to current view controller
var currentVc: UIViewController!
class abc1: UIViewController {
override func viewdidload() {
super.viewdidload()
currentVc = self
admobDelegate.showAd()
}
override func viewDidAppear() {
super.viewDidAppear()
currentVc = self
}
}
class abc2: UIViewController {
override func viewdidload() {
super.viewdidload()
currentVc = self
admobDelegate.showAd()
}
override func viewDidAppear() {
super.viewDidAppear()
currentVc = self
}
}
Code is in Swift 2.2. Write your equivalent code in swift 3 in case of syntax error.

interstitialWillDismissScreen only being called once

I am using Admob interstitials in my swift project and I am having trouble reloading the ads. The first interstitial displays fine, and when interstitialWillDismissScreen is called, it exits back to the game and reloads a new interstitial as it's supposed to. However, neither interstitialDidReceiveAd nor interstitialWillDismissScreen are called again, so after the second ad is displayed, no other ads come through. What am I missing?
import GoogleMobileAds
let appDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
class GameScene: SKScene, GKGameCenterControllerDelegate, GADInterstitialDelegate {
var interstitial: GADInterstitial!
override func didMoveToView(view: SKView) {
//preload interstitial ad
if NSUserDefaults.standardUserDefaults().boolForKey("paidToRemoveAds") == false {
interstitial = loadAd()
}
interstitial.delegate = self
}
func gameOver() {
runGoogleAd()
}
func loadAd() -> GADInterstitial {
let ad = GADInterstitial(adUnitID: "ca-app-pub-2963481692578498/7292484569")
let request = GADRequest()
request.testDevices = [kGADSimulatorID]
ad.loadRequest(request)
return ad
}
func runGoogleAd() {
if interstitial.isReady {
interstitial.presentFromRootViewController((appDelegate.window?.rootViewController)!)
}
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
print("ad loaded")
}
func interstitialWillDismissScreen(ad: GADInterstitial!) {
interstitial = loadAd()
print("loading new ad")
}
}
I assume loadAd() creates a new instance? You need to set the delegate on the new instance:
func interstitialWillDismissScreen(ad: GADInterstitial!) {
interstitial = loadAd()
interstitial.delegate = self // <-- You forgot this.
print("loading new ad")
}
Actually you should probably set the delegate in loadAd() since it is an instance member of this class.

Resources