I am trying to integrate Native Ads from AdbMob in iOS with UIKit
Below is my code
import UIKit
import GoogleMobileAds
class ViewController: UIViewController,GADNativeAdLoaderDelegate,GADNativeAdDelegate,GADVideoControllerDelegate {
private var adLoader: GADAdLoader!
let adView: GADNativeAdView = {
let view = GADNativeAdView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .white
view.layer.cornerRadius = 10
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 0.5
view.layer.shadowOffset = CGSize(width: 0, height: 2)
return view
}()
let adLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor(red: 1, green: 0.8, blue: 0.4, alpha: 1)
label.font = UIFont.systemFont(ofSize: 15)
label.textColor = UIColor.white
label.text = "Ad"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let iconImageView: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = .cyan
imageView.contentMode = .scaleAspectFit
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let headlineLabel: UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 18)
label.text = "Headline Label"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let advertiserLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 14)
label.text = "Advertiser Label"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let ratingsImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let bodyLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 14)
label.text = "This is the body of the card."
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let gadMediaView: GADMediaView = {
let view = GADMediaView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let installButton: UIButton = {
let button = UIButton()
button.backgroundColor = .systemBlue
button.setTitle("Install", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let storeLabel: UILabel = {
let label = UILabel()
label.text = "Store"
label.font = UIFont.systemFont(ofSize: 14)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let priceLabel: UILabel = {
let label = UILabel()
label.text = "Price"
label.font = UIFont.systemFont(ofSize: 14)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupConstraints()
let multipleAdOptions = GADMultipleAdsAdLoaderOptions()
multipleAdOptions.numberOfAds = 5;
adLoader = GADAdLoader(adUnitID: "ca-app-pub-3940256099942544/3986624511",
rootViewController: self,
adTypes: [.native],
options: nil)
adLoader.delegate = self
adLoader.load(GADRequest())
}
func setupConstraints() {
// Constraints for your custom GADUnifiedNativeAdView
view.addSubview(adView)
adView.addSubview(adLabel)
adView.addSubview(iconImageView)
adView.addSubview(headlineLabel)
adView.addSubview(advertiserLabel)
adView.addSubview(ratingsImageView)
adView.addSubview(bodyLabel)
adView.addSubview(gadMediaView)
adView.addSubview(installButton)
adView.addSubview(storeLabel)
adView.addSubview(priceLabel)
NSLayoutConstraint.activate([
adView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
adView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
adView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
adView.heightAnchor.constraint(equalToConstant: 350)
])
NSLayoutConstraint.activate([
adLabel.topAnchor.constraint(equalTo: adView.topAnchor,constant: 4),
adLabel.leadingAnchor.constraint(equalTo: adView.leadingAnchor,constant: 4),
adLabel.heightAnchor.constraint(equalToConstant: 30), // Set a specific height for the title label
adLabel.widthAnchor.constraint(equalToConstant: 30)
])
NSLayoutConstraint.activate([
iconImageView.topAnchor.constraint(equalTo: adLabel.bottomAnchor, constant: 8),
iconImageView.leadingAnchor.constraint(equalTo: adLabel.trailingAnchor, constant: 8),
iconImageView.widthAnchor.constraint(equalToConstant: 40),
iconImageView.heightAnchor.constraint(equalToConstant: 40)
])
NSLayoutConstraint.activate([
headlineLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 8),
headlineLabel.topAnchor.constraint(equalTo: iconImageView.topAnchor)
])
NSLayoutConstraint.activate([
advertiserLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 8),
advertiserLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: 2),
])
NSLayoutConstraint.activate([
ratingsImageView.leadingAnchor.constraint(equalTo: advertiserLabel.trailingAnchor, constant: 8),
ratingsImageView.topAnchor.constraint(equalTo: advertiserLabel.bottomAnchor),
ratingsImageView.widthAnchor.constraint(equalToConstant: 100),
ratingsImageView.heightAnchor.constraint(equalToConstant: 17)
])
NSLayoutConstraint.activate([
bodyLabel.topAnchor.constraint(equalTo: iconImageView.bottomAnchor, constant: 8),
bodyLabel.leadingAnchor.constraint(equalTo: adView.leadingAnchor),
bodyLabel.trailingAnchor.constraint(equalTo: adView.trailingAnchor)
])
NSLayoutConstraint.activate([
gadMediaView.leadingAnchor.constraint(equalTo: adView.leadingAnchor, constant: 10),
gadMediaView.trailingAnchor.constraint(equalTo: adView.trailingAnchor, constant: -10),
gadMediaView.topAnchor.constraint(equalTo: bodyLabel.bottomAnchor, constant: 8),
gadMediaView.heightAnchor.constraint(equalToConstant: 150)
])
NSLayoutConstraint.activate([
installButton.trailingAnchor.constraint(equalTo: adView.trailingAnchor, constant: -10),
installButton.topAnchor.constraint(equalTo: gadMediaView.bottomAnchor,constant: 10),
installButton.heightAnchor.constraint(equalToConstant: 40),
installButton.widthAnchor.constraint(equalToConstant: 100)
])
NSLayoutConstraint.activate([
storeLabel.trailingAnchor.constraint(equalTo: installButton.leadingAnchor, constant: -10),
storeLabel.centerYAnchor.constraint(equalTo: installButton.centerYAnchor)
])
NSLayoutConstraint.activate([
priceLabel.trailingAnchor.constraint(equalTo: storeLabel.leadingAnchor, constant: -10),
priceLabel.centerYAnchor.constraint(equalTo: storeLabel.centerYAnchor)
])
}
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
nativeAd.delegate = self
iconImageView.image = nativeAd.icon?.image
headlineLabel.text = nativeAd.headline
gadMediaView.mediaContent = nativeAd.mediaContent
let mediaContent = nativeAd.mediaContent
if mediaContent.hasVideoContent {
// By acting as the delegate to the GADVideoController, this ViewController receives messages
// about events in the video lifecycle.
mediaContent.videoController.delegate = self
print("Ad contains a video asset.")
} else {
print("Ad does not contain a video.")
}
bodyLabel.text = nativeAd.body
advertiserLabel.text = nativeAd.advertiser
installButton.setTitle(nativeAd.callToAction, for: .normal)
storeLabel.text = nativeAd.store
priceLabel.text = nativeAd.price
// In order for the SDK to process touch events properly, user interaction should be disabled.
installButton.isUserInteractionEnabled = false
ratingsImageView.image = imageOfStars(from: nativeAd.starRating)
adView.nativeAd = nativeAd
}
func imageOfStars(from starRating: NSDecimalNumber?) -> UIImage? {
guard let rating = starRating?.doubleValue else {
return nil
}
if rating >= 5 {
return UIImage(named: "stars_5")
} else if rating >= 4.5 {
return UIImage(named: "stars_4_5")
} else if rating >= 4 {
return UIImage(named: "stars_4")
} else if rating >= 3.5 {
return UIImage(named: "stars_3_5")
} else {
return nil
}
}
func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
print("\(adLoader) failed with error: \(error.localizedDescription)")
}
func adLoaderDidFinishLoading(_ adLoader: GADAdLoader) {
}
func nativeAdDidRecordImpression(_ nativeAd: GADNativeAd) {
// The native ad was shown.
}
func nativeAdDidRecordClick(_ nativeAd: GADNativeAd) {
// The native ad was clicked on.
}
func nativeAdWillPresentScreen(_ nativeAd: GADNativeAd) {
// The native ad will present a full screen view.
}
func nativeAdWillDismissScreen(_ nativeAd: GADNativeAd) {
// The native ad will dismiss a full screen view.
}
func nativeAdDidDismissScreen(_ nativeAd: GADNativeAd) {
// The native ad did dismiss a full screen view.
}
func nativeAdWillLeaveApplication(_ nativeAd: GADNativeAd) {
// The native ad will cause the app to become inactive and
// open a new app.
}
func videoControllerDidEndVideoPlayback(_ videoController: GADVideoController) {
print("Video playback has ended.")
}
}
Below is the output
I keep getting a validation error saying Ad attribution missing but I have added the a UILabel saying Ad at top left corner but still same validation error
This is the issue it points to
What else needs to be added
After going through this doc, it also says I need to add an image on top right corner, I tried adding a dummy image, I couldn’t find the exact image of Ads by Google Icon which is pointed in docs but still same issue