Attempting to combine Adaptive AdMob for iOS a part of myCcompose Multiplatform venture.
I adopted these supplies:
-
A man from Medium: https://medium.com/@diegoturchi95/admob-integration-in-compose-multiplatform-kmp-65de75b2f67c
-
Google official doc: https://builders.google.com/admob/ios/banner
My implementation appears to be like like this.
Swift code:
import UIKit
import SwiftUI
import ComposeApp
import GoogleMobileAds
struct ComposeView: UIViewControllerRepresentable {
//init() {
// MainViewControllerKt.IOSBanner = { () -> UIViewController in
//let width = UIScreen.major.bounds.width
//let adSize = currentOrientationAnchoredAdaptiveBanner(width: width)
//let bannerView = BannerAdView(adSize).body(top: adSize.dimension.top)
// let bannerView = BannerAdView()
// return UIHostingController(rootView: bannerView)
// }
//}
init() {
MainViewControllerKt.IOSBanner = {
let width = UIScreen.major.bounds.width
// That is what your Kotlin code calls when it wants the banner
let adSize = currentOrientationAnchoredAdaptiveBanner(width: width)
//let bannerView = BannerAdView(adSize).body(top: adSize.dimension.top)
let bannerView = AdViewBanner()
.body(top: adSize.dimension.top)
//.body(top: 90) // Secure fallback - adaptive dimension will override
return UIHostingController(rootView: bannerView)
}
}
func makeUIViewController(context: Context) -> UIViewController {
MainViewControllerKt.MainViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
}
struct ContentView: View {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var physique: some View {
ComposeView()
.ignoresSafeArea()
}
}
GoogleMobileAdsConsentManager:
import Basis
import GoogleMobileAds
import UserMessagingPlatform
@MainActor
remaining class GoogleMobileAdsConsentManager: NSObject {
static let shared = GoogleMobileAdsConsentManager()
non-public var isMobileAdsStarted = false
var canRequestAds: Bool {
ConsentInformation.shared.canRequestAds
}
func gatherConsent(completion: @escaping (Error?) -> Void) async {
let params = RequestParameters()
let debugSettings = DebugSettings()
// debugSettings.geography = .EEA // Uncomment to check consent kind
params.debugSettings = debugSettings
do {
attempt await ConsentInformation.shared.requestConsentInfoUpdate(with: params)
attempt await ConsentForm.loadAndPresentIfRequired(from: nil)
completion(nil)
} catch {
completion(error)
}
}
func startGoogleMobileAdsSDK() {
guard canRequestAds, !isMobileAdsStarted else { return }
isMobileAdsStarted = true
MobileAds.shared.begin(completionHandler: nil)
}
}
AdMobBanner:
//
// AdMobBanner.swift
// iosApp
//
import SwiftUI
import UIKit
import GoogleMobileAds
import ComposeApp // Your generated KMP module
// MARK: - Adaptive BannerAdView (SwiftUI wrapper)
struct AdViewBanner: UIViewRepresentable {
non-public let adUnitID = "ca-app-pub-3940256099942544/2435281174" // Check ID - change in manufacturing
func makeUIView(context: Context) -> BannerView {
let banner = BannerView()
banner.translatesAutoresizingMaskIntoConstraints = false
banner.adUnitID = adUnitID
banner.delegate = context.coordinator
// Required: set rootViewController so adverts can current modals
banner.rootViewController = UIApplication.shared.topMostViewController()
// Use Google's really useful adaptive dimension
let width = UIScreen.major.bounds.width
let adaptiveSize = currentOrientationAnchoredAdaptiveBanner(width: width)
banner.adSize = adaptiveSize
banner.load(Request())
return banner
}
func updateUIView(_ uiView: BannerView, context: Context) {
// Deal with rotation correctly
let width = UIScreen.major.bounds.width
let newSize = currentOrientationAnchoredAdaptiveBanner(width: width)
if !isAdSizeEqualToSize(size1: uiView.adSize, size2: newSize) {
uiView.adSize = newSize
uiView.load(Request())
}
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator: NSObject, BannerViewDelegate {
func bannerViewDidReceiveAd(_ bannerView: BannerView) {
print("Banner advert loaded efficiently")
}
func bannerView(_ bannerView: BannerView, didFailToReceiveAdWithError error: Error) {
print("Banner advert failed: (error.localizedDescription)")
}
}
}
// MARK: - UIApplication extension to get prime VC
extension UIApplication {
func topMostViewController() -> UIViewController? {
let keyWindow = connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.home windows }
.first(the place: { $0.isKeyWindow })
var prime = keyWindow?.rootViewController
whereas let introduced = prime?.presentedViewController {
prime = introduced
}
return prime ?? UIViewController()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
iOSApp
import SwiftUI
@major
struct iOSApp: App {
var physique: some Scene {
WindowGroup {
ContentView()
}
}
}
AppDelegate
import SwiftUI
import Basis
import GoogleMobileAds
class AppDelegate: UIResponder, UIApplicationDelegate {
func software(_ software: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Job { @MainActor in
await GoogleMobileAdsConsentManager.shared.gatherConsent { error in
if let error = error {
print("Consent error: (error.localizedDescription)")
}
GoogleMobileAdsConsentManager.shared.startGoogleMobileAdsSDK()
}
}
return true
}
}
Kotlin half:
lateinit var IOSBanner: () -> UIViewController
enjoyable generateIOSBanner(): UIViewController {
return IOSBanner()
}
enjoyable MainViewController(): UIViewController {
return ComposeUIViewController {
MainApp {
UIKitView(
modifier = Modifier,
manufacturing facility = { generateIOSBanner().view }
)
}
}
}
MainApp appears to be like like:
@Composable
enjoyable MainApp(bannerContext: @Composable (String) -> Unit) {
Platform.initDataStore()
AppTheme(mainModel = mainModel) {
var route by rememberSaveableString()
val controller = rememberNavController { worth -> route = worth }
Column(
content material = {
Field(modifier = Modifier.weight(weight = 1f)) {
MainGraph(controller = controller, mainModel = mainModel)
}
bannerContext.invoke(route)
},
modifier = Modifier.animContentSize().background(coloration = background())
)
}
}
}
The implementation works, however not as anticipated. The banner seems zoomed in:

I additionally tried to implement it with out the adaptive dimension function, however that resulted in a full display advert as an alternative of a banner.
I count on it to look just like the Android model in androidMain:

What’s the drawback and the way can I repair it?
Thanks.

