Hello I want to add ads to a swiftUI grid. The grid contains pictures that I get from a firebase backend and after every couple of pictures I would like to have an ad.
I am quite new to both SwiftUi and working with ads, so I'm not sure how correct my code is, but here is what I got so far.
// Code for the pictures Grid struct PicturesGrid: View { private let data: [Item] var body: some View { let gridItems = [GridItem(.fixed(UIScreen.screenWidth / 2), alignment: .leading), GridItem(.fixed(UIScreen.screenWidth / 2), alignment: .leading)] return ScrollView(showsIndicators: false) { LazyVGrid(columns: gridItems) { ForEach(0..<self.data.count, id: \.self) { index in // Using this workaround for the ad to be on the whole width of the screen // Also, after every six images I am adding and ad if index != 0, index % 6 == 0 { AdView() .frame(width: UIScreen.screenWidth, height: 280) .padding(.top, 20) Spacer() item .frame(width: UIScreen.screenWidth / 2) } else { item .frame(width: UIScreen.screenWidth / 2) } } } } } // this is for the picture var item: some View { NavigationLink(destination: DetailView(viewModel: DetailViewModel(item: itemAtIndexPath))) { Cell(viewModel: CellViewModel(item: itemAtIndexPath)) } .buttonStyle(PlainButtonStyle()) } }
This is the code that I am currently using to load, create and display an ad
// Code for the ad that I am currently using struct AdView: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> UIViewController { let adController = AdViewController(self) return adController } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} } class AdViewController: UIViewController { private var adView: AdView /// The height constraint applied to the ad view, where necessary. var heightConstraint: NSLayoutConstraint? /// The ad loader. You must keep a strong reference to the GADAdLoader during the ad loading /// process. var adLoader: GADAdLoader! /// The native ad view that is being presented. var nativeAdView: GADUnifiedNativeAdView! /// The ad unit ID. let adUnitID = "ca-app-pub-3940256099942544/3986624511" init(_ adView: AdView) { self.adView = adView super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() var nibView: Any? nibView = Bundle.main.loadNibNamed("ListAdView", owner: nil, options: nil)?.first guard let nativeAdView = nibView as? GADUnifiedNativeAdView else { return } setAdView(nativeAdView) adLoader = GADAdLoader(adUnitID: adUnitID, rootViewController: self, adTypes: [.unifiedNative], options: nil) adLoader.delegate = self DispatchQueue.global(qos: .background).async { self.adLoader.load(GADRequest()) } } func setAdView(_ adView: GADUnifiedNativeAdView) { // Remove the previous ad view. DispatchQueue.main.async { [weak self] in guard let weakSelf = self else { return } weakSelf.nativeAdView = adView weakSelf.view.addSubview(weakSelf.nativeAdView) weakSelf.nativeAdView.translatesAutoresizingMaskIntoConstraints = false // Layout constraints for positioning the native ad view to stretch the entire width and height let viewDictionary = ["_nativeAdView": weakSelf.nativeAdView!] weakSelf.view.addConstraints( NSLayoutConstraint.constraints( withVisualFormat: "H:|[_nativeAdView]|", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) ) weakSelf.view.addConstraints( NSLayoutConstraint.constraints( withVisualFormat: "V:|[_nativeAdView]|", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) ) } } } extension AdViewController: GADUnifiedNativeAdLoaderDelegate { func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: GADRequestError) { print("didFailToReceiveAdWithError: \(error)") } func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADUnifiedNativeAd) { print("Received unified native ad: \(nativeAd)") // Deactivate the height constraint that was set when the previous video ad loaded. heightConstraint?.isActive = false // Populate the native ad view with the native ad assets. // The headline and mediaContent are guaranteed to be present in every native ad. (nativeAdView.headlineView as? UILabel)?.text = nativeAd.headline nativeAdView.mediaView?.mediaContent = nativeAd.mediaContent // This app uses a fixed width for the GADMediaView and changes its height to match the aspect // ratio of the media it displays. if let mediaView = nativeAdView.mediaView, nativeAd.mediaContent.aspectRatio > 0 { heightConstraint = NSLayoutConstraint( item: mediaView, attribute: .height, relatedBy: .equal, toItem: mediaView, attribute: .width, multiplier: CGFloat(1 / nativeAd.mediaContent.aspectRatio), constant: 0) heightConstraint?.isActive = true } // This asset is not guaranteed to be present. Check that it is before // showing or hiding it. (nativeAdView.advertiserView as? UILabel)?.text = nativeAd.advertiser nativeAdView.advertiserView?.isHidden = nativeAd.advertiser == nil // In order for the SDK to process touch events properly, user interaction should be disabled. nativeAdView.callToActionView?.isUserInteractionEnabled = false // Associate the native ad view with the native ad object. This is // required to make the ad clickable. // Note: this should always be done after populating the ad views. nativeAdView.nativeAd = nativeAd } }
I want to mention that this is working at the moment, but the problems that I want to fix and I don't know how are:
- The grid with the pictures load, but when I scroll over an ad, it takes several seconds for the ad to load and display. How could I at least hide it while it loads or make it faster?
- If I scroll over an ad, the ad loads and if I continue scrolling, when I scroll back up, the ad is not loaded anymore and I have to wait for it to load again. How can I fix this? Or what is the best practice for this kind of scenario?
- Should I use multipleAds? To load them before showing? If yes, then how should I do this?
- Does what I am doing here look even a little bit correct? Please...I need some help