SwiftUI for banner ads

This guide shows you how to integrate banner ads with the Google Mobile Ads SDK into your SwiftUI app. For the other ad formats integration steps, see the respective ad format guides:

Prerequisites

  • Complete the Get started guide.
  • Target iOS SDK 13.0 or higher.
  • This guide assumes you understand how to load banner ads. If you aren't already familiar with loading banner ads, check out the Banner guide first:

Always test with test ads

When building and testing your apps, make sure you use test ads rather than live, production ads. Failure to do so can lead to suspension of your account.

We provide test ad unit IDs that have been specially configured to return test ads for every request which you can use in your own apps while coding, testing, and debugging. When you're ready to publish your app, be sure you replace those ad unit IDs with your own.

For more information about how the Mobile Ads SDK's test ads work, see Enabling test ads.

The primary steps to integrate banner ads in SwiftUI are as follows:

  • Determine your ad width.
  • Create a GADBannerView in a custom UIViewControllerRepresentable type.
  • Create a Coordinator object to pass the width value from the UIViewController to the UIViewRepresentable.

Determine your ad width

To use our preferred adaptive banner format, you first define and implement a delegate to pass the device's frame width from a UIViewController to your SwiftUI class.

// Delegate methods for receiving width update messages.

protocol BannerViewControllerWidthDelegate: AnyObject {
  func bannerViewController(_ bannerViewController: BannerViewController, didUpdate width: CGFloat)
}
class BannerViewController: UIViewController {
  weak var delegate: BannerViewControllerWidthDelegate?

  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // Tell the delegate the initial ad width.
    delegate?.bannerViewController(
      self, didUpdate: view.frame.inset(by: view.safeAreaInsets).size.width)
  }

  override func viewWillTransition(
    to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator
  ) {
    coordinator.animate { _ in
      // do nothing
    } completion: { _ in
      // Notify the delegate of ad width changes.
      self.delegate?.bannerViewController(
        self, didUpdate: self.view.frame.inset(by: self.view.safeAreaInsets).size.width)
    }
  }
}

Create a GADBannerView

To represent your view controller in SwiftUI, create a type that conforms to the UIViewControllerRepresentable protocol. This type's primary responsibility is to create the relationship between the GADBannerView and the content view. It keeps the viewWidth as @State, and requests a new banner ad whenever the view's width changes.

struct BannerView: UIViewControllerRepresentable {
  @State private var viewWidth: CGFloat = .zero
  private let bannerView = GADBannerView()
  private let adUnitID = ""

  func makeUIViewController(context: Context) -> some UIViewController {
    let bannerViewController = BannerViewController()
    bannerView.adUnitID = adUnitID
    bannerView.rootViewController = bannerViewController
    bannerViewController.view.addSubview(bannerView)

    return bannerViewController
  }

  func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
    guard viewWidth != .zero else { return }

    // Request a banner ad with the updated viewWidth.
    bannerView.adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth)
    bannerView.load(GADRequest())
  }

Add to the view hierarchy

Add your UIViewControllerRepresentable type to your content view's view hierarchy like so:

struct ContentView: View {

  var body: some View {
    BannerView()
  }
}

Pass the width value to your UIViewControllerRepresentable

The makeCoordinator() method provided by UIViewControllerRepresentable lets you create a class to communicate changes from your view controller to your SwiftUI interface.

Create a nested Coordinator class inside your UIViewControllerRepresentable that conforms to the BannerViewControllerWidthDelegate protocol. It declares a property of its parent BannerView so the coordinator can modify the viewWidth value directly.

struct BannerView: UIViewControllerRepresentable {
  @State private var viewWidth: CGFloat = .zero
  ...

  func makeUIViewController(context: Context) -> some UIViewController {
    let bannerViewController = BannerViewController()
    bannerView.adUnitID = adUnitID
    bannerView.rootViewController = bannerViewController
    bannerViewController.view.addSubview(bannerView)
    // Tell the bannerViewController to update our Coordinator when the ad
    // width changes.
    bannerViewController.delegate = context.coordinator

    return bannerViewController
  }

  ...

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

  fileprivate class Coordinator: NSObject, BannerViewControllerWidthDelegate {
    let parent: BannerView

    init(_ parent: BannerView) {
      self.parent = parent
    }

    // MARK: - BannerViewControllerWidthDelegate methods

    func bannerViewController(_ bannerViewController: BannerViewController, didUpdate width: CGFloat) {
      // Pass the viewWidth from Coordinator to BannerView.
      parent.viewWidth = width
    }
  }
}

Ad events

To be notified of events related to banner ad interactions, set the delegate property of the banner view. Then implement GADBannerViewDelegate in your Coordinator class to receive the following delegate calls.

struct BannerView: UIViewControllerRepresentable {
  ...

  func makeUIViewController(context: Context) -> some UIViewController {
    let bannerViewController = BannerViewController()
    bannerView.adUnitID = adUnitID
    bannerView.rootViewController = bannerViewController
    bannerView.delegate = context.coordinator
    ...
  }

  fileprivate class Coordinator: NSObject, BannerViewControllerWidthDelegate, GADBannerViewDelegate
  {
    ...

    // MARK: - GADBannerViewDelegate methods

    func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
      print("\(#function) called")
    }

    func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) {
      print("\(#function) called")
    }

    func bannerViewDidRecordImpression(_ bannerView: GADBannerView) {
      print("\(#function) called")
    }

    func bannerViewWillPresentScreen(_ bannerView: GADBannerView) {
      print("\(#function) called")
    }

    func bannerViewWillDismissScreen(_ bannerView: GADBannerView) {
      print("\(#function) called")
    }

    func bannerViewDidDismissScreen(_ bannerView: GADBannerView) {
      print("\(#function) called")
    }
  }
}

This concludes the SwiftUI implementation for banner ads. The complete example for banner ads is available on GitHub.