This guide shows you how to integrate ads with the Google Mobile Ads SDK into your SwiftUI app. It covers integration steps for banner, interstitial, rewarded, and rewarded interstitial ad formats. For native ad integration steps, see Native ads.
Prerequisites
- Complete the Get started guide.
- Target iOS SDK 13.0 or higher.
- This guide assumes you understand how to load the ad format of your choice. If you aren't already familiar with loading ads, check out the ad format guides 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.
Banner ads
The primary steps to integrate banner ads in SwiftUI are as follows:
- Determine your ad width.
- Create a
GAMBannerView
in a customUIViewControllerRepresentable
type. - Create a
Coordinator
object to pass the width value from theUIViewController
to theUIViewRepresentable
.
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 GAMBannerView
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 GAMBannerView
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 = GAMBannerView()
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(GAMRequest())
}
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.
Full-screen ads
This section covers SwiftUI implementations for the following ad formats:
The code snippets in this section demonstrate these concepts using interstitial ads as an example.
Implementation
To integrate full-screen ads into your SwiftUI project, create a separate class to implement loading and presenting full-screen ads. Initialize the class in SwiftUI to call these methods from action events.
Create an ad coordinator class
Create a class that is responsible for loading and presenting ads.
class AdCoordinator: NSObject {
private var ad: GAMInterstitialAd?
func loadAd() {
GAMInterstitialAd.load(
withAdUnitID: "/21775744923/example/interstitial", request: GAMRequest()
) { ad, error in
if let error = error {
return print("Failed to load ad with error: \(error.localizedDescription)")
}
self.ad = ad
}
}
func presentAd() {
guard let fullScreenAd = ad else {
return print("Ad wasn't ready")
}
// View controller is an optional parameter. Pass in nil.
fullScreenAd.present(fromRootViewController: nil)
}
}
Load and present the ad in SwiftUI
Your SwiftUI content view is responsible for calling the load and present
methods. The following code snippet shows how to call them from a Button
.
struct ContentView: View {
// Initialize your ad coordinator class.
private let adCoordinator = AdCoordinator()
var body: some View {
Button("Load an ad.") {
adCoordinator.loadAd()
}
Button("Watch an ad.") {
adCoordinator.presentAd()
}
}
}
Ad events
To be notified of events related to the full-screen ad interactions, set the
fullScreenContentDelegate
property of the ad. Then implement
GADFullScreenContentDelegate
to receive the following delegate calls.
class AdCoordinator: NSObject, GADFullScreenContentDelegate {
...
func loadAd() {
GAMInterstitialAd.load(
withAdUnitID: "/21775744923/example/interstitial", request: GAMRequest()
) { ad, error in
if let error = error {
return print("Failed to load ad with error: \(error.localizedDescription)")
}
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) {
print("\(#function) called")
}
func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
print("\(#function) called")
}
}
This concludes the SwiftUI implementation for full-screen ads. The complete examples for each respective ad format are available on GitHub.