For all articles, please move to:
SwiftUI APP integrates Google mobile advertising Admob (I): https://www.xugj520.cn/archives/swiftui-admob-1.html
SwiftUI APP integrates Google mobile advertising Admob (II): https://www.xugj520.cn/archives/swiftui-admob-2.html
Introduction:
As more and more applications are built using SwiftUI, I want to provide an easy way to integrate Admob directly into your application. In order to make it easier for everyone to integrate, I plan to release it as Cocoapod.
Let's take a look at the effect after integration:
Set up Google mobile advertising (Admob) SDK
For application, please refer to Google's official documentation at: https://developers.google.com/admob/ios/quick-start .
Importing SDK using Cocoapods
pod 'Google-Mobile-Ads-SDK'
Then run using the command line
pod install --repo-update
Update Info.plist
Please update the applied Info.plist file to add the following two keys:
- A string value is the GADApplicationIdentifier key of your AdMob application ID (identified in the AdMob interface).
- A SKAdNetworkIdentifier value is Google (cstr6suwn9.skadnetwork), and select the SKAdNetworkItems key of other buyers who provide these values to Google.
<key>GADApplicationIdentifier</key> <string>ca-app-pub-3940256099942544~2435281174</string>
Initialize Google mobile advertising (Admob) SDK
import SwiftUI import AppTrackingTransparency import GoogleMobileAds @main struct ExampleApp: App { //Use init() in App Delegate instead of ApplicationDidFinishLaunchWithOptions init() { if ATTrackingManager.trackingAuthorizationStatus == .notDetermined { // TODO, you can pop up the privacy agreement here } else { ATTrackingManager.requestTrackingAuthorization { status in GADMobileAds.sharedInstance().start(completionHandler: nil) } } } var body: some Scene { WindowGroup { ContentView() } } }
Banner ad (adaptive)
Create a BannerAd inheriting UIViewController
class BannerAdVC: UIViewController { let adUnitId: String //Initialize variable 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() //Creates your BannerView override func viewDidLoad() { bannerView.adUnitID = adUnitId bannerView.rootViewController = self //Add our BannerView to the VC view.addSubview(bannerView) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) loadBannerAd() } //Allows the banner to resize when transition from portrait to landscape orientation override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate { _ in self.bannerView.isHidden = true //So banner doesn't disappear in middle of animation } completion: { _ in self.bannerView.isHidden = false self.loadBannerAd() } } func loadBannerAd() { let frame = view.frame.inset(by: view.safeAreaInsets) let viewWidth = frame.size.width //Updates the BannerView size relative to the current safe area of device (This creates the adaptive banner) bannerView.adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth) bannerView.load(GADRequest()) } }
To use the newly created UIViewController in SwiftUI, you need to create a uiviewcontrollerrepresententable
final class 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) { } }
Now your banner ad is a swift UI view, but we still need to set up something so that you can add it to your application. Let's create a new SwiftUI view called SwiftUI banner ad. This view will manage the location and frame of your ads.
struct SwiftUIBannerAd: View { @State var height: CGFloat = 0 //Height of ad @State var width: CGFloat = 0 //Width of ad @State var adPosition: AdPosition let adUnitId: String init(adPosition: AdPosition, adUnitId: String) { self.adPosition = adPosition self.adUnitId = adUnitId } enum AdPosition { case top case bottom } public var body: some View { VStack { if adPosition == .bottom { Spacer() //Pushes ad to bottom } //Ad BannerAd(adUnitId: adUnitId) .frame(width: width, height: height, alignment: .center) .onAppear { //Call this in .onAppear() b/c need to load the initial frame size //.onReceive() will not be called on initial load setFrame() } //Changes the frame of the ad whenever the device is rotated. //This is what creates the adaptive ad .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in setFrame() } if adPosition == .top { Spacer() //Pushes ad to top } } } func setFrame() { //Get the frame of the safe area let safeAreaInsets = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.safeAreaInsets ?? .zero let frame = UIScreen.main.bounds.inset(by: safeAreaInsets) //Use the frame to determine the size of the ad let adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(frame.width) //Set the ads frame self.width = adSize.size.width self.height = adSize.size.height } }
this is it! You can add ads to your app. I recommend that you do this by placing it at the highest level of ZStack. (refer to the example at the beginning)
When testing your advertisement, be sure to set adUnitId as banner test advertisement unit ID: CA app pub 3940256099942544 / 2934735716
You may have noticed that I use NotificationCenter and UIApplication to get security zones and directions. Although you can use GeometryReader to do this, I do not recommend using it for production applications. When testing my own SwiftUI application, WidgeTube, I found that GeometryReader was simply unreliable for production. Many times, it is the root cause of the property graph crash of SwiftUI. Although some people have found a way to avoid this situation, by experimenting with the order of the view stack, I decided that it was best to avoid using GeometryReader completely.
Interstitial Ad
First, we need to create an InterstitialAdObject. This object handles the loading of insert ads in your application.
class InterstitialAd: NSObject { var interstitialAd: GADInterstitialAd? //Want to have one instance of the ad for the entire app //We can do this b/c you will never show more than 1 ad at once so only 1 ad needs to be loaded static let shared = InterstitialAd() func loadAd(withAdUnitId id: String) { let req = GADRequest() GADInterstitialAd.load(withAdUnitID: id, request: req) { interstitialAd, err in if let err = err { print("Failed to load ad with error: \(err)") return } self.interstitialAd = interstitialAd } } }
We will now use this object to create an interstitialdiew. The view will be a UIViewControllerRepresentable and a GADFullScreenContentDelegate.
class InterstitialAdView: NSObject, UIViewControllerRepresentable, GADFullScreenContentDelegate { //Here's the Ad Object we just created let interstitialAd = InterstitialAd.shared.interstitialAd @Binding var isPresented: Bool var adUnitId: String init(isPresented: Binding<Bool>, adUnitId: String) { self._isPresented = isPresented self.adUnitId = adUnitId super.init() interstitialAd?.fullScreenContentDelegate = self //Set this view as the delegate for the ad } //Make's a SwiftUI View from a UIViewController func makeUIViewController(context: Context) -> UIViewController { let view = UIViewController() //Show the ad after a slight delay to ensure the ad is loaded and ready to present DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1)) { self.showAd(from: view) } return view } func updateUIViewController(_ uiViewController: UIViewController, context: Context) { } //Presents the ad if it can, otherwise dismisses so the user's experience is not interrupted func showAd(from root: UIViewController) { if let ad = interstitialAd { ad.present(fromRootViewController: root) } else { print("Ad not ready") self.isPresented.toggle() } } func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) { //Prepares another ad for the next time view presented InterstitialAd.shared.loadAd(withAdUnitId: adUnitId) //Dismisses the view once ad dismissed isPresented.toggle() } }
Later, we will create a full screen modifier to render this view. Now we'll keep the existing content and create incentive ads (if you don't create incentive ads, skip to the full screen modifier).
During the test, insert test advertising unit ID: CA app pub 3940256099942544 / 4411468910 is used