Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Expandable ads cannot be collapsed in iOS 18.2

106 views
Skip to first unread message

TAL Dev

unread,
Jan 10, 2025, 10:56:37 AMJan 10
to Google Mobile Ads SDK Developers
The iOS 18.2 update caused expandable ads to be unresponsive to tapping on the collapse button, leaving them fully expanded in an app and disrupting the user experience. This only started in iOS 18.2 and is present in the 11.13.0 version of the iOS SDK.

I've switched back to regular banner ads for now, but that's exacerbating the eCPM decline that typically occurs after the holiday season, for a massive 50% revenue decline.

Mobile Ads SDK Forum Advisor

unread,
Jan 10, 2025, 5:59:49 PMJan 10
to michae...@gmail.com, google-adm...@googlegroups.com
Hi,

Thank you for contacting Mobile Ads SDK Support Team,

I've tried checking Google Sample Project in iPhone 16 series simulator  and iPhone 15 physical device iOS18.2 . I am unable to replicate this issue. For me ads are getting collapsed properly.
Is this specific to any device ? Could you share additional detail along with your app Id and adUnit ID to reproduce this issue ?
 
This message is in relation to case "ref:!00D1U01174p.!5004Q02vGv6c:ref" (ADR-00283911)

Thanks,
 
Google Logo Mobile Ads SDK Team

Feedback
How was our support today?

rating1    rating2    rating3    rating4    rating5



TAL Dev

unread,
Jan 13, 2025, 2:40:52 PMJan 13
to Google Mobile Ads SDK Developers
Hello,

It's 100% reproducible even with the most basic code. My app is in SwiftUI and the Google sample app is in UIKit, which might be a difference. If you have a place to upload videos, I can show you two examples. Otherwise, here are 2 different code approaches that both 100% reproduce the issue (the ad itself cannot be tapped either).

Blank app with ContentView body:

    var body: some View {

        SwiftUIBannerAd(adPosition: .top, adUnitId: "")

            .padding(.top, UIApplication.currentUIWindow()?.safeAreaInsets.top)

    }


And SwiftUIBannerAd:

import SwiftUI

import GoogleMobileAds


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)


        let request = GADRequest()


        // Create an extra parameter that aligns the bottom of the expanded ad to

        // the bottom of the bannerView.

        let extras = GADExtras()

        extras.additionalParameters = ["collapsible" : "top"]

        request.register(extras)

        

        bannerView.load(request)

    }

}


struct 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) {}

}


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.currentUIWindow()?.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

    }

}



Second Approach:

Blank app and a ContentView body as such:

    var body: some View {

        GeometryReader { geometry in

            let adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(geometry.size.width)

            BannerView(adSize)

                .padding(.top, UIApplication.currentUIWindow()?.safeAreaInsets.top)

        }

    }


And BannerView:

import SwiftUI

import GoogleMobileAds


class BannerCoordinator: NSObject, GADBannerViewDelegate {

    private(set) lazy var bannerView: GADBannerView = {

        let banner = GADBannerView(adSize: parent.adSize)

        banner.adUnitID = ""

        

        let request = GADRequest()


        // Create an extra parameter that aligns the bottom of the expanded ad to

        // the bottom of the bannerView.

        let extras = GADExtras()

        extras.additionalParameters = ["collapsible" : "top"]

        request.register(extras)

        

        banner.load(request)

        banner.delegate = self

        return banner

    }()

    

    let parent: BannerView

    

    init(_ parent: BannerView) {

        self.parent = parent

    }

}


struct BannerView: UIViewRepresentable {

    let adSize: GADAdSize

    

    init(_ adSize: GADAdSize) {

        self.adSize = adSize

    }

    

    func makeUIView(context: Context) -> UIView {

        // Wrap the GADBannerView in a UIView. GADBannerView automatically reloads a new ad when its

        // frame size changes; wrapping in a UIView container insulates the GADBannerView from size

        // changes that impact the view returned from makeUIView.

        let view = UIView()

        view.addSubview(context.coordinator.bannerView)

        return view

    }

    

    func updateUIView(_ uiView: UIView, context: Context) {

        context.coordinator.bannerView.adSize = adSize

    }

    

    func makeCoordinator() -> BannerCoordinator {

        return BannerCoordinator(self)

    }

}

TAL Dev

unread,
Jan 13, 2025, 2:43:10 PMJan 13
to Google Mobile Ads SDK Developers
Implementation of `currentUIWindow` to be comprehensive:

public extension UIApplication {

    static func currentUIWindow() -> UIWindow? {

        UIApplication.shared.connectedScenes.flatMap { ($0 as? UIWindowScene)?.windows ?? [] }.first { $0.isKeyWindow }

    }

}


TAL Dev

unread,
Jan 13, 2025, 3:24:21 PMJan 13
to Google Mobile Ads SDK Developers
The issue seems to be with SwiftUI and padding. The AdMob banner view can no longer be tapped if a .padding() is added to it. It can be any simple SwiftUI .padding(), which is a standard view modifier, and necessary to keep the banner visible with the safe area insets. The banner works properly without .padding() in any context, but won't expand when it detects that it's underneath the notch and not in a safe area.

TAL Dev

unread,
Jan 13, 2025, 3:38:27 PMJan 13
to Google Mobile Ads SDK Developers
Issue persists if I use .offset() instead of .padding().

Mobile Ads SDK Forum Advisor

unread,
Jan 14, 2025, 10:11:21 PMJan 14
to michae...@gmail.com, google-adm...@googlegroups.com
Hi,

Thank you for sharing the code snippet screenshots.

I will check this issue and inform you once I have an update.

Mobile Ads SDK Forum Advisor

unread,
Jan 15, 2025, 2:33:37 AMJan 15
to michae...@gmail.com, google-adm...@googlegroups.com
Hi,

You can provide the sample project and videos via reply privately to the author option or to this link

Mobile Ads SDK Forum Advisor

unread,
Jan 15, 2025, 6:24:46 PMJan 15
to michae...@gmail.com, google-adm...@googlegroups.com
Hi,

Thank you for providing additional details.

I was able to replicate this issue and raised to wider team and will update you once i receive any update on this. Meanwhile, your patience is important.
Reply all
Reply to author
Forward
0 new messages