Here’s some example code and a Demo app showing how to use implement MoPub banner ads inside SwiftUI apps.
MoPub doesn’t currently provide support for SwiftUI, so I put together this demo app: MoPub SwiftUI Demo.
Whenever we need to incorporate a view not currently covered in SwiftUI, such as a banner ad from the MoPub SDK, we’ll need to create a UIViewRepresentable. There. are a few steps to this, but once you get the hang of it, it gets fairly easy to replicate.
Additionally, once we have our Representable set up, we’ll be able to drop our MoPubBannerView anywhere in our SwiftUI environment.
Follow along for a more detailed explanation on integrating MoPub Banner Ads in SwiftUI
Step 0:
You will need to integrate the SDK into your own app using MoPub’s Documentation.
Step 1. Initialize MoPub SDK
This step is basically the same as the docs, except you may need to first add an AppDelegate to your SwiftUI app.
import SwiftUI
import MoPubSDK
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
//Initialize Mopub
let sdkConfig = MPMoPubConfiguration(adUnitIdForAppInitialization: "0ac59b0996d947309c33f59d6676399f")
sdkConfig.loggingLevel = .info
MoPub.sharedInstance().initializeSdk(with: sdkConfig)
return true
}
}
@main
struct MoPubSwiftUIDemoApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Step 2: Create a SwiftUI UIViewRepresentable
In order to use custom views, or native UIViews that do not yet have a SwiftUI equivalent, we’ll need to create a UIViewRepresentable. This is where the bulk of the work comes in to play. I’ll break down some of the important parts here, and the full code is at the bottom:
2a: makeUIView
This is where we do the MPAdView creation. The adSize must contain the correct dimensions of the ad to be loaded, such as height:320, width:50
. While the sdk offers ad size constants, such as kMPPresetMaxAdSize50Height
, I found that these have the height set as -1 for some reason. This results in the sdk not loading any ad here. The SDK also doesn’t play nice with how SwiftUI manages the parent view’s frame, so kMPPresetMaxAdSizeMatchFrame
doesn’t work either.
func makeUIView(context: Context) -> MPAdView {
let moPubBannerView = type(of: MPAdView()).init(adUnitId:adUnitID)!
//adSize needs to be defined with the exact dimensions of the desired ad, ex: 320x50.
//Only defining the height using something like kMPPresetMaxAdSize50Height will define a width of 0, causing the ad not to load
moPubBannerView.frame.size = adSize
moPubBannerView.delegate = context.coordinator
moPubBannerView.loadAd()
return moPubBannerView
}
2b: The delegate
In makeUIView above, the the delegate is passed through context.coordinator
. We actually set up the Delegate on the Coordinator
class. This also allows us to listen for any events.
class Coordinator: NSObject, UINavigationControllerDelegate, MPAdViewDelegate {
private let parent: MoPubBannerViewRepresentable
init(_ mopubView: MoPubBannerViewRepresentable) {
self.parent = mopubView
}
func viewControllerForPresentingModalView() -> UIViewController! {
return UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController
}
//Events from MPAdViewDelegate can go here
//These can be removed if not used
func adViewDidLoadAd(_ view: MPAdView!, adSize: CGSize) {
print("ad loaded with size: \(adSize)")
}
func adView(_ view: MPAdView!, didFailToLoadAdWithError error: Error!) {
if let error = error {
print("failed to load ad with error: \(error)")
}
}
func adViewDidFail(toLoadAd view: MPAdView!) {
print("failed to load ad")
}
}
2c: Set up the SwiftUI view
For UIViewRepresentable implementations, I like to set up a mini View to serve as an API of sorts between our Representable implementation and the rest of our app code. This allows for setting a frame to match the banner size, and anything else you need to do on all banner views. Alternatively, you could add MoPubBannerViewRepresentable directly to your View.
struct MoPubBannerView: View {
let adUnitID: String
let adSize: CGSize
var body: some View {
MoPubBannerViewRepresentable(adUnitID: adUnitID, adSize: adSize)
.frame(width: adSize.width, height: adSize.height)
}
}
Step 3: Add to our content View
All we need to do now is drop the BannerView into our view, passing it an adUnitId and the ad size. Here’s a sample banner using the MoPub Test Ad Ids:
struct ContentView: View {
var body: some View {
MoPubBannerView(adUnitID: "0ac59b0996d947309c33f59d6676399f", adSize: CGSize(width: 320, height: 50))
}
}
Full Code
To see a working app with more examples, check out my MoPub SwiftUI Demo App. The full UIViewRepresentable code is below
//
// MoPubBannerView.swift
// MoPubSwiftUIDemo
//
// Created by Adam Paxton on 3/10/21.
//
import MoPubSDK
import SwiftUI
import UIKit
struct MoPubBannerView: View {
let adUnitID: String
let adSize: CGSize
var body: some View {
MoPubBannerViewRepresentable(adUnitID: adUnitID, adSize: adSize)
.frame(width: adSize.width, height: adSize.height)
}
}
struct MoPubBannerViewRepresentable: UIViewRepresentable {
let adUnitID: String
let adSize: CGSize
func makeUIView(context: Context) -> MPAdView {
let moPubBannerView = type(of: MPAdView()).init(adUnitId:adUnitID)!
//adSize needs to be defined with the exact dimensions of the desired ad, ex: 320x50.
//Only defining the height using something like kMPPresetMaxAdSize50Height will define a width of 0, causing the ad not to load
moPubBannerView.frame.size = adSize
moPubBannerView.delegate = context.coordinator
moPubBannerView.loadAd()
return moPubBannerView
}
func updateUIView(_ uiView: MPAdView, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UINavigationControllerDelegate, MPAdViewDelegate {
private let parent: MoPubBannerViewRepresentable
init(_ mopubView: MoPubBannerViewRepresentable) {
self.parent = mopubView
}
func viewControllerForPresentingModalView() -> UIViewController! {
return UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController
}
//Events from MPAdViewDelegate can go here
//These can be removed if not used
func adViewDidLoadAd(_ view: MPAdView!, adSize: CGSize) {
print("ad loaded with size: \(adSize)")
}
func adView(_ view: MPAdView!, didFailToLoadAdWithError error: Error!) {
if let error = error {
print("failed to load ad with error: \(error)")
}
}
func adViewDidFail(toLoadAd view: MPAdView!) {
print("failed to load ad")
}
}
}
https://github.com/adampax/MoPubSwiftUIDemo/blob/main/MoPubSwiftUIDemo/MoPubBannerView.swift
You must be logged in to post a comment.