Я следил за этими материалами:
Парень из Medium: https://medium.com/@diegoturchi95/admob ... de75b2f67c
Официальный документ Google: https://developers.google.com/admob/ios/banner
В результате моя реализация выглядит так:
Swift-коды:
ComposeView
Код: Выделить всё
import UIKit
import SwiftUI
import ComposeApp
import GoogleMobileAds
struct ComposeView: UIViewControllerRepresentable {
//init() {
// MainViewControllerKt.IOSBanner = { () -> UIViewController in
//let width = UIScreen.main.bounds.width
//let adSize = currentOrientationAnchoredAdaptiveBanner(width: width)
//let bannerView = BannerAdView(adSize).frame(height: adSize.size.height)
// let bannerView = BannerAdView()
// return UIHostingController(rootView: bannerView)
// }
//}
init() {
MainViewControllerKt.IOSBanner = {
let width = UIScreen.main.bounds.width
// This is what your Kotlin code calls when it needs the banner
let adSize = currentOrientationAnchoredAdaptiveBanner(width: width)
//let bannerView = BannerAdView(adSize).frame(height: adSize.size.height)
let bannerView = AdViewBanner()
.frame(height: adSize.size.height)
//.frame(height: 90) // Safe fallback - adaptive size 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 body: some View {
ComposeView()
.ignoresSafeArea()
}
}
Код: Выделить всё
import Foundation
import GoogleMobileAds
import UserMessagingPlatform
@MainActor
final class GoogleMobileAdsConsentManager: NSObject {
static let shared = GoogleMobileAdsConsentManager()
private 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 test consent form
params.debugSettings = debugSettings
do {
try await ConsentInformation.shared.requestConsentInfoUpdate(with: params)
try await ConsentForm.loadAndPresentIfRequired(from: nil)
completion(nil)
} catch {
completion(error)
}
}
func startGoogleMobileAdsSDK() {
guard canRequestAds, !isMobileAdsStarted else { return }
isMobileAdsStarted = true
MobileAds.shared.start(completionHandler: nil)
}
}
Код: Выделить всё
//
// AdMobBanner.swift
// iosApp
//
import SwiftUI
import UIKit
import GoogleMobileAds
import ComposeApp // Your generated KMP module
// MARK: - Adaptive BannerAdView (SwiftUI wrapper)
struct AdViewBanner: UIViewRepresentable {
private let adUnitID = "ca-app-pub-3940256099942544/2435281174" // Test ID - change in production
func makeUIView(context: Context) -> BannerView {
let banner = BannerView()
banner.translatesAutoresizingMaskIntoConstraints = false
banner.adUnitID = adUnitID
banner.delegate = context.coordinator
// Required: set rootViewController so ads can present modals
banner.rootViewController = UIApplication.shared.topMostViewController()
// Use Google's recommended adaptive size
let width = UIScreen.main.bounds.width
let adaptiveSize = currentOrientationAnchoredAdaptiveBanner(width: width)
banner.adSize = adaptiveSize
banner.load(Request())
return banner
}
func updateUIView(_ uiView: BannerView, context: Context) {
// Handle rotation properly
let width = UIScreen.main.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 ad loaded successfully")
}
func bannerView(_ bannerView: BannerView, didFailToReceiveAdWithError error: Error) {
print("Banner ad failed: \(error.localizedDescription)")
}
}
}
// MARK: - UIApplication extension to get top VC
extension UIApplication {
func topMostViewController() -> UIViewController? {
let keyWindow = connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
.first(where: { $0.isKeyWindow })
var top = keyWindow?.rootViewController
while let presented = top?.presentedViewController {
top = presented
}
return top ?? UIViewController()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Код: Выделить всё
import SwiftUI
@main
struct iOSApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Код: Выделить всё
import SwiftUI
import Foundation
import GoogleMobileAds
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Task { @MainActor in
await GoogleMobileAdsConsentManager.shared.gatherConsent { error in
if let error = error {
print("Consent error: \(error.localizedDescription)")
}
GoogleMobileAdsConsentManager.shared.startGoogleMobileAdsSDK()
}
}
return true
}
}
Код: Выделить всё
lateinit var IOSBanner: () -> UIViewController
fun generateIOSBanner(): UIViewController {
return IOSBanner()
}
fun MainViewController(): UIViewController {
return ComposeUIViewController {
MainApp {
UIKitView(
modifier = Modifier,
factory = { generateIOSBanner().view }
)
}
}
}
Код: Выделить всё
@Composable
fun MainApp(bannerContext: @Composable (String) -> Unit) {
Platform.initDataStore()
AppTheme(mainModel = mainModel) {
var route by rememberSaveableString()
val controller = rememberNavController { value -> route = value }
Column(
content = {
Box(modifier = Modifier.weight(weight = 1f)) {
MainGraph(controller = controller, mainModel = mainModel)
}
bannerContext.invoke(route)
},
modifier = Modifier.animContentSize().background(color = background())
)
}
}
}

Я также попробовал реализовать без функции адаптивного размера, в результате чего получилось полноэкранное объявление, а не баннер.
Я ожидаю, что оно будет выглядеть так, как на Android (androidMain):

В чем проблема и как ее исправить?
Спасибо.
Подробнее здесь: https://stackoverflow.com/questions/798 ... rm-for-ios
Мобильная версия