Search code examples
iosswiftswiftuiadmob

Admob Dismiss view when initial ad dismissed


I'm using the latest implementation of admob with SwiftUI. Everything is working as expected. But I'd like to dismiss the parent view when an ad has completed, or when it's dismissed. I'm very new to delegates and can't quite wrap my head around how they work.

My SomeView is a horizontal tab view in a navigation stack, and I can dismiss it with presentationMode.wrappedValue.dismiss()

What I'd like is the adCoordinator's adDidDismissFullScreenContent method to dismiss SomeView when the user dismissed the ad, it prints just fine.

I've tried adding an adDismissed binding variable, and I've tried to hook my viewModel into the adCoordinator. But couldn't quite get either to work.

Any help would be much appreciated, thanks!

import SwiftUI
import CoreData

struct SomeView: View {
    @ObservedObject var viewModel: ViewModel
    private let adViewControllerRepresentable = AdViewControllerRepresentable()
    private let adCoordinator = AdCoordinator()
    @Binding var adDismissed: Bool
    
    var body: some View {
        VStack(alignment: .center) {
            Button("save_btn") {
                adCoordinator.presentAd(from: adViewControllerRepresentable.viewController)
            }.background {
                // Add the adViewControllerRepresentable to the background so it
                // doesn't influence the placement of other views in the view hierarchy.
                adViewControllerRepresentable
                    .frame(width: .zero, height: .zero)
            }.onAppear{
                print("On Appear")
                adCoordinator.loadAd()
            }
        }
    }
}

import Foundation
import SwiftUI
import GoogleMobileAds


class AdCoordinator: NSObject, GADFullScreenContentDelegate {
    private var ad: GADInterstitialAd?
    
    func loadAd() {
        
        GADInterstitialAd.load(
            withAdUnitID: "ca-app-pub-3940256099942544/4411468910", request: GADRequest()
        ) { ad, error in
            if let error = error {
                return print("Failed to load ad with error: \(error.localizedDescription)")
            }
            print("ad loading")
            self.ad = ad
            self.ad?.fullScreenContentDelegate = self
        }
    }
    
    // MARK: - GADFullScreenContentDelegate methods
    
    func adDidRecordImpression(_ ad: GADFullScreenPresentingAd) {
        print("\(#function) called")
    }
    
    func adDidRecordClick(_ ad: GADFullScreenPresentingAd) {
        print("\(#function) called")
    }
    
    func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
        print("\(#function) called")
    }
    
    func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
        print("\(#function) called")
    }
    
    
    func adWillDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
        return print("\(#function) called")
    }
    
    func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
        print("\(#function) called")
    }
    
    func presentAd(from viewController: UIViewController) {
        guard let fullScreenAd = ad else {
            return print("Ad wasn't ready")
        }
        fullScreenAd.present(fromRootViewController: viewController)
    }
}

struct AdViewControllerRepresentable: UIViewControllerRepresentable {
    let viewController = UIViewController()
    
    func makeUIViewController(context: Context) -> some UIViewController {
        return viewController
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        // No implementation needed. Nothing to update.
    }
}


Solution

  • I've found a way to make this work, in case anyone else has the same issue. I'm not sure if it's the best way, but I used observable objects and a published bool eg.

    private class InterstitialAdCoordinator: NSObject, GADFullScreenContentDelegate, ObservableObject  {
        
        private var interstitial: GADInterstitialAd?
        @Published var adWasDismissed = false
        
        func loadAd() {
            GADInterstitialAd.load(
                withAdUnitID: "ca-app-pub-3940256099942544/4411468910", request: GADRequest()
            ) { ad, error in
                self.interstitial = ad
                self.interstitial?.fullScreenContentDelegate = self
            }
        }
        
        func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
            interstitial = nil
            adWasDismissed = true
            print("Ad dismissed \(adWasDismissed)")
        }
        
        func showAd(from viewController: UIViewController, completion: () -> Void, onFailure: () -> Void) {
            if let interstitial = interstitial {
                interstitial.present(fromRootViewController: viewController)
                completion()
            }
            else {
                onFailure()
                return print("Ad wasn't ready")
            }
        }
    }
    

    I also added a completion handler, to the show ad func, in case the ad fails to display.