12

I found nowhere an example how to integrate it with swiftui. Does anybody found a tutorial? The problem is the part with the root controller.

Ben Keil
  • 1,050
  • 1
  • 10
  • 30
  • 1
    There's an official guide available now provided by Google: [How to integrate ads with the Google Mobile Ads SDK into your SwiftUI app](https://developers.google.com/admob/ios/swiftui). – Kjuly Mar 02 '23 at 02:32

3 Answers3

29

in the Apple SwiftUI tutorial - integration in SwiftUI

you can find that how to solve this question with UIViewControllerRepresentable

and I create an example like this

import GoogleMobileAds
import SwiftUI
import UIKit

struct GADBannerViewController: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIViewController {
        let view = GADBannerView(adSize: kGADAdSizeBanner)
        let viewController = UIViewController()
        view.adUnitID = "your ad unit id in there."
        view.rootViewController = viewController
        viewController.view.addSubview(view)
        viewController.view.frame = CGRect(origin: .zero, size: kGADAdSizeBanner.size)
        view.load(GADRequest())
        return viewController
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

then you can using GADBannerViewController in your SwiftUI view's body like that

HStack {
    Spacer()
    GADBannerViewController()
        .frame(width: kGADAdSizeBanner.size.width, height: kGADAdSizeBanner.size.height)
    Spacer()
}

if you have any questions, please let me know.

張家齊
  • 489
  • 4
  • 4
7

To improve on Mcatach and avoid adding the view to the app's root view controller:

struct GADBannerViewController: UIViewControllerRepresentable {

@State private var banner: GADBannerView = GADBannerView(adSize: kGADAdSizeBanner)

func makeUIViewController(context: Context) -> UIViewController {
    let bannerSize = GADBannerViewController.getAdBannerSize()
    let viewController = UIViewController()
    banner.adSize = bannerSize
    banner.adUnitID = "ca-pub-ad-id-12345678"
    banner.rootViewController = viewController
    viewController.view.addSubview(banner)
    viewController.view.frame = CGRect(origin: .zero, size: bannerSize.size)
    banner.load(Ads.createRequest())
    return viewController
}

func updateUIViewController(_ uiViewController: UIViewController, context: Context){
    let bannerSize = GADBannerViewController.getAdBannerSize()
    banner.frame = CGRect(origin: .zero, size: bannerSize.size)
    banner.load(GADRequest())
}

static func getAdBannerSize() -> GADAdSize {
    if let rootView = UIApplication.shared.windows.first?.rootViewController?.view {
        let frame = rootView.frame.inset(by: rootView.safeAreaInsets)
        return GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(frame.width)
    }
    //No root VC, use 320x50 ad banner
    return kGADAdSizeBanner
}

}

The layout code:

    private func adSection() -> some View {
    HStack {
        let size = GADBannerViewController.getAdBannerSize()
        Spacer()
        GADBannerViewController()
            .frame(width: size.size.width, height: size.size.height)
        Spacer()
    }
}
Pig Dog Bay
  • 149
  • 1
  • 3
  • nice addition! It's better this way – mcatach Dec 30 '20 at 19:25
  • What does Ads.createRequest() look like? – chitgoks Mar 09 '23 at 07:53
  • @chitgoks Just GADRequest(), I'll update the answer. – Pig Dog Bay Mar 09 '23 at 12:11
  • 1
    thank you @PigDogBay. best solution for SwiftUI. Just one thing, it gives a purple message saying This method should not be called on the main thread as it may lead to UI unresponsiveness. Why is that? Even i tried to run the banner.load() inside a dispatch async, still the same. – chitgoks Mar 09 '23 at 12:17
  • 1
    @chitgoks Maybe related to this https://developer.apple.com/forums/thread/714467 – Pig Dog Bay Mar 09 '23 at 12:29
  • @PigDogBay thanks for the confirmation. I know it is because of using admob but glad to know it's an issue that will be resolved. – chitgoks Mar 10 '23 at 01:08
5

You should use UIViewRepresentable instead of UIViewControllerRepresentable.

I implemented the Adaptive banner with this code:

struct AdView : UIViewRepresentable {
    @State private var banner: GADBannerView = GADBannerView(adSize: kGADAdSizeBanner)
    
    func makeUIView(context: UIViewRepresentableContext<AdView>) -> GADBannerView {
        #if DEBUG
        banner.adUnitID = "ca-app-pub-debug"
        #else
        banner.adUnitID = "ca-app-pub-prod"
        #endif

        guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else {
            return banner
        }
        
        banner.rootViewController = rootViewController
        
        let frame = { () -> CGRect in
            return banner.rootViewController!.view.frame.inset(by: banner.rootViewController!.view.safeAreaInsets)
        }()
        let viewWidth = frame.size.width

        banner.adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth)

        banner.load(GADRequest())
        return banner
    }
    
    func updateUIView(_ uiView: GADBannerView, context: UIViewRepresentableContext<AdView>) {
    }
}

Then you can call on your Stack using

AdView().frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 300)
                .frame(width: kGADAdSizeBanner.size.width, height: kGADAdSizeBanner.size.height)
mcatach
  • 1,227
  • 13
  • 23
  • Exactly why is is better than UIViewControllerRepresentable? – Makalele Nov 03 '20 at 12:01
  • 1
    Because you want to add a view, not a view controller, to your view controller. – mcatach Nov 04 '20 at 15:52
  • I tried your solution, but banner is misplaced - not only covering status bar, but it's even a little higher. – Makalele Nov 05 '20 at 07:21
  • 1
    Working great! Thanks a lot – Muvimotv Dec 12 '20 at 01:43
  • This is how I have implemented banner ads, but I find that I have thousands of requests. For example, on AdMob I see 6.35K requests for only 153 impressions because it's constantly calling updateUIView. Is that ok? – CS0521 Nov 01 '21 at 21:04
  • hi @mcatach using kGADAdSizeBanner.size.width does not occupy the whole width of the screen. why is that? I did try to use .infinity and it worked but it gave out a purple message in xcode saying non-finite something. – chitgoks Mar 08 '23 at 14:59