Nicolas M
Nicolas M

Reputation: 555

Google AdMob interstitial in SwiftUI

I try to integrate Interstitial ad in swiftUI, I create the UIViewControllerRepresentable class and the UIViewController.

https://developers.google.com/admob/ios/interstitial#show_the_ad

But I don't know how to show the ad once the ad ready and loaded.

in Admob documentation i have

  if interstitial.isReady {
                    interstitial.present(fromRootViewController: viewController)
                } else {
                    print("Ad wasn't ready")
                }

but I don't know where put his code and how input the view in my swiftUI view

import SwiftUI
import UIKit
import GoogleMobileAds

final class GADInterstitialViewController: UIViewControllerRepresentable {
    public var interstitial: GADInterstitial!
    public func makeUIViewController(context: UIViewControllerRepresentableContext<GADInterstitialViewController>) -> UIViewController {
        let interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
        let viewController = UIViewController()
        let request = GADRequest()
        interstitial.load(request)

        return viewController
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<GADInterstitialViewController>) {

    }



}


struct Transit: View {


    var body: some View {
        ZStack{
            GADInterstitialViewController()
                .frame(width: screen.width, height: screen.height, alignment: .center)
        }

    }

}

Upvotes: 6

Views: 2854

Answers (3)

Sergei Volkov
Sergei Volkov

Reputation: 1144

Important! Simply: When creating a root view, you need to select the LAST view from the hierarchy, then the advertisement will be shown from any view (for example, a sheet)

let root = UIApplication.shared.windows.last?.rootViewController

func showAd () {
     if let interstitial = interstitialAd {
        let root = UIApplication.shared.windows.last?.rootViewController
        interstitial.present(fromRootViewController: root!)
     }
 }

Upvotes: 0

mohit kejriwal
mohit kejriwal

Reputation: 1835

You can take a very basic approach. Just create a class which makes a new request every time you call its load method, as soon as ad is loaded it should inform your view, and whenever you want to display your ad just call its show method as shown below:-

import Foundation
import GoogleMobileAds
import UIKit
    
final class InterstitialAd : NSObject, GADInterstitialDelegate, ObservableObject {
    var interstitialAd: GADInterstitial? = nil
    @Published var isLoaded: Bool = false
    
    func LoadInterstitial() {
        interstitialAd = GADInterstitial(adUnitID: Constants.interstitialAdCode)
        let req = GADRequest()
        interstitialAd!.load(req)
        interstitialAd!.delegate = self
    }
    
    func showAd() {
        if let interstitialAd = self.interstitialAd, interstitialAd.isReady {
           let root = UIApplication.shared.windows.first?.rootViewController
           interstitialAd.present(fromRootViewController: root!)
           isLoaded = false
        }
    }
    
    func interstitialWillLeaveApplication(_ ad: GADInterstitial) {
        print("user clicked ad")
    }
    
    func interstitialDidReceiveAd(_ ad: GADInterstitial) {
        print("ad loaded")
        isLoaded = true
    }
}

Upvotes: 0

William Tong
William Tong

Reputation: 475

The solution doesn't work for me when the interstitial is not in the root view. After searching around, finally I could make it work.

I use an EnvironmentObject to hold the Interstitial

Xcode 11.5, Swift 5

import Foundation
import GoogleMobileAds
class SharedValues:ObservableObject{
    
    @Published var interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
    @Published var popInterstitial = false

}

And then create a struct or viewcontroller class to hold the ViewController/View which is used to display the Interstitial specifically. The code looks much but most of them are boilerplate codes.

struct InterstitialVC:UIViewControllerRepresentable{

@EnvironmentObject var sharing:SharedValues

func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
    
    if sharing.popInterstitial{
        
        showAd(uiViewController)
    }
}




func makeUIViewController(context: Context) -> some UIViewController {
    let vc = UIViewController()
    vc.view.frame = UIScreen.main.bounds

    sharing.interstitial.delegate = context.coordinator
    return vc
}

Here we implement the GADInterstitialDelegate, the Coordinator thing looks exotic to me the first time I see it. But when you get your hand dirty and you will find it very straight forward and convenient. You need the Coordinator thing to communicate between the delegate/UIKit and SwiftUI.

sharing.interstitial.delegate = context.coordinator

Above is the code you set the coordinator as your GADInterstitialDelegate, it may work good even if you don't implement the delegate methods. But those methods help a lot when you research and debug how things work.

func makeCoordinator() -> Coordinator {
    Coordinator(self)
}

class Coordinator:NSObject,GADInterstitialDelegate{
    var parent:InterstitialVC
    
    init(_ parent: InterstitialVC) {
        self.parent = parent
    }
    func interstitialDidReceiveAd(_ ad: GADInterstitial) {
        //do your things
        parent.sharing.popInterstitial = true
    }
    
    func interstitialDidDismissScreen(_ ad: GADInterstitial) {
        //do your things
        let request = GADRequest()
        parent.sharing.interstitial.load(request)
    }
    
    func interstitialWillPresentScreen(_ ad: GADInterstitial) {
        //do your things
    }
    func interstitialDidFail(toPresentScreen ad: GADInterstitial) {
        //do your things
    }
}

Almost all boilerplate codes. Notice that the Coordinate class is inside the InterstitialVC struct. I use the delegate method to determine when to pop and pre-load the Ad again.

func showAd(_ controller:UIViewController){
    
    if sharing.interstitial.isReady{
        sharing.interstitial.present(fromRootViewController: controller)
        sharing.popInterstitial = false
    }else{
        print("Not Ready Yet")
    }
}

}

In the ContentView or other views, find a good place to put/hide the InterstitialVC() before it pops. Voila

struct ContentView: View {
    @State var showInterstitial = true
    @EnvironmentObject var sharing:SharedValues
    var body: some View {
        ZStack{
//            if showInterstitial{
//                InterstitialVC()
//                   .edgesIgnoringSafeArea(.all)
//            }
            NavigationView{
                List{
                    NavigationLink("Show Second View", destination: SecondView())
                }
            }
           
            
            
        }.onAppear{
            
            let request = GADRequest()
            self.sharing.interstitial.load(request)
        }
        

    }
}

import SwiftUI
import GoogleMobileAds

struct SecondView: View {
    @EnvironmentObject var sharing:SharedValues
    
    @State var showInterstitial = true
    var body: some View {
        ZStack{
            if showInterstitial{
                
                InterstitialVC()
            }
            
            Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
        }
        .background(Color.yellow)
        .onAppear{
           let request = GADRequest()
           parent.sharing.interstitial.load(request)
          }
        
    }
}

Upvotes: 4

Related Questions