Search code examples
swiftswiftuiadmob

How to make Ad Mob banner disappear/clear if It didn't load the ad in SwiftUI?


I have implemented a SwiftUIBannerAd in my iOS app, but sometimes the ads fail to load. In such cases, I want the ad banner to be transparent so that it doesn't occupy any space on the screen. How can I modify the existing code to achieve this?

Here is my current implementation of the banner:

public struct SwiftUIBannerAd: View {
@State var height: CGFloat = 0
@State var width: CGFloat = 0
@State var adPosition: AdPosition
let adUnitId: String

    public init(adPosition: AdPosition, adUnitId: String) {
        self.adPosition = adPosition
        self.adUnitId = adUnitId
    }
    
    public enum AdPosition {
        case top
        case bottom
    }
    
    public var body: some View {
        VStack {
            if adPosition == .bottom {
                Spacer()
            }
    
            //Ad
            BannerAd(adUnitId: adUnitId)
                .frame(width: width, height: height, alignment: .center)
                .onAppear {
                    setFrame()
                }
                .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
                    setFrame()
                }
    
            if adPosition == .top {
                Spacer()
            }
        }
    }
    
    func setFrame() {
        let safeAreaInsets = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.safeAreaInsets ?? .zero
        let frame = UIScreen.main.bounds.inset(by: safeAreaInsets)
    
        let adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(frame.width)
    
        self.width = adSize.size.width
        self.height = adSize.size.height
    }

}

class BannerAdVC: UIViewController, GADBannerViewDelegate {
let adUnitId: String

    init(adUnitId: String) {
        self.adUnitId = adUnitId
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    var bannerView: GADBannerView = GADBannerView()
    
    override func viewDidLoad() {
        bannerView.delegate = self
        bannerView.adUnitID = adUnitId
        bannerView.rootViewController = self
        view.addSubview(bannerView)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    
        loadBannerAd()
        
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        coordinator.animate(alongsideTransition: nil) { _ in
            self.loadBannerAd()
        }
    }
    
    func loadBannerAd() {
        let frame = view.frame.inset(by: view.safeAreaInsets)
        let viewWidth = frame.size.width
    
        bannerView.adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth)
    
        if #available(iOS 14, *) {
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
                    let request = GADRequest()
                    DispatchQueue.main.async {
                        request.scene = self.view.window?.windowScene
                        self.bannerView.load(request)
                    }
                })
            }
        } else {
            let request = GADRequest()
            request.scene = view.window?.windowScene
            bannerView.load(request)
        }
    }

}

struct BannerAd: UIViewControllerRepresentable {
let adUnitId: String

    init(adUnitId: String) {
        self.adUnitId = adUnitId
    }
    
    
    func makeUIViewController(context: Context) -> BannerAdVC {
        return BannerAdVC(adUnitId: adUnitId)
    }
    
    func updateUIViewController(_ uiViewController: BannerAdVC, context: Context) {
    
    }

}

I was trying to make it work with this, but it didn't do anything:

func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) {
            print("Failed to receive ad: \(error.localizedDescription)")
            bannerView.backgroundColor = .clear
            bannerView.isHidden = true
        }

I am displaying this Banner in my views like that:

if showBannerAd {
                HStack {
                    Spacer()
                    SwiftUIBannerAd(adPosition: .top, adUnitId: StaticCodes.bannerCode)
                        .frame(width: GADAdSizeBanner.size.width, height: GADAdSizeBanner.size.height)
                        .padding()
                    Spacer()
                }
            } else {
                EmptyView()
                    .frame(height: 0)
            }

Solution

  • Do this and embed in the ZStack

    VStack {
                    Spacer()
                    if showBannerAd {
                        HStack {
                            Spacer()
                            SwiftUIBannerAd(adPosition: .top, adUnitId: StaticCodes.bannerCode)
                                .frame(width: GADAdSizeBanner.size.width, height: GADAdSizeBanner.size.height)
                            Spacer()
                        }
                    } else {
                        EmptyView()
                            .frame(height: 0)
                    }
                }