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.
Asked
Active
Viewed 5,844 times
3 Answers
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
-
1
-
What do you think about my implementation? https://stackoverflow.com/questions/60200602/ios-swiftui-admob-native-ads-convenience-class – Roman Vasilyev Feb 13 '20 at 04:43
-
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
-
-
-
-
1thank 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
-
-
1Because 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
-
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