AdMob helps you monetize your mobile app through in-app advertising. Ads can be displayed as banner ads, interstitial ads, video ads, or native ads — which are seamlessly added to platform native UI components. The Google Mobile Ads SDK for Android and iOS is used to serve AdMob ads.

Native Ads Advanced is a format in which ad assets are presented to users via UI components that are native to the platform. They're shown using the same types of views with which you're already building your layouts, and can be formatted to match the visual design of the user experience in which they live.

This codelab will walk you through using Native Advanced ads within a UITableViewController, to show you how to monetize a feed-based app. You'll start with an app that displays a list of items, but no ads. Over the course of the codelab, you'll rewrite the controller to handle native ads, display them correctly, and use delegate classes to wire everything up.

What you will build

You will build a feed-based app with ads injected at regular intervals. Your app will:

  • Request Native Advanced Ads using the Google Mobile Ads SDK
  • Present ads within your feed
  • Customize the look of the ads to match your content

What you'll learn

What you'll need

This codelab is focused on Native Advanced ads in the Google Mobile Ads SDK. Non-relevant concepts and code blocks are glossed over and are provided for you to simply copy and paste.

You will start with an app that shows a restaurant menu. It has a UITableView showing a list of menu items.

Get the Code

There are two ways to get the code. You can clone the repository from GitHub:

git clone https://github.com/googlecodelabs/admob-native-advanced-feed.git

Or alternatively, click the following link to download the code for this codelab:

Download source code

This will unpack a root folder (admob-native-advanced-feed if you cloned the repository, or admob-native-advanced-feed-master if you downloaded the zip file), which contains a directory specific to either Android or iOS. For this codelab you'll navigate to the iOS directory. The iOS directory contains the start state for this codelab, located in the work directory. The end state for this codelab is located in the final directory.

You'll do all of your coding in this codelab in the work directory. If at any time you're having trouble, you can refer to the project in the final directory.

Run the project

In the work directory, open NativeAdvancedTableViewExample.xcodeproj and run the app on any iOS simulator. Your app should look like this:

Click the Show Menu button to see a list of menu items.

In subsequent steps, you'll add AdMob Native Advanced ads to this UITableView.

Use CocoaPods to get the SDKs

The easiest way to include the Firebase and Mobile Ads SDKs is using CocoaPods, which is used in this codelab. In the same directory as the NativeAdvancedTableViewExample.xcodeproj file, there's a file named Podfile that includes the following:

Podfile

source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '7.0'

target 'NativeAdvancedTableViewExample' do
  use_frameworks!
  pod 'Firebase'
  pod 'Firebase/AdMob'
end

Run pod update

In the terminal, navigate to the same directory as the Podfile described above. Then run:

pod install --repo-update

This command ensures you get the latest iOS SDK into your app and that all the APIs are there. Once the installation finishes, close NativeAdvancedTableViewExample.xcodeproj and open up NativeAdvancedTableViewExample.xcworkspace. Your workspace should include a Pods project with new dependencies for Firebase and AdMob.

GoogleService-Info.plist file included for your convenience

If you've ever integrated with the Firebase SDK before, you know that you need to download a GoogleService-Info.plist file from the Firebase console and include it in your app. For convenience, a sample GoogleService-Info.plist file has already been included in the project you downloaded, so you can move on the next step.

Before loading ads, your app will need to initialize the Firebase and Mobile Ads SDKs

Initialize Firebase

Add the call to configure:, shown below, to the application:didFinishLaunchingWithOptions:method of AppDelegate.swift to perform Firebase initialization. It's important to note you must include the import Firebase statement before calling any Firebase methods.

AppDelegate.swift

import Firebase

...

func application(_ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

  // Initialize the Firebase SDK.
  FirebaseApp.configure()
  return true
}

Initialize Google Mobile Ads

Add the call to configure:withApplicationID: with your AdMob App ID to the application:didFinishLaunchingWithOptions:method of AppDelegate.swift to perform Google Mobile Ads initialization.

AppDelegate.swift

import Firebase

...

func application(_ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  FirebaseApp.configure()

  // Initialize the Google Mobile Ads SDK.
  GADMobileAds.configure(withApplicationID: "ca-app-pub-3940256099942544~1458002511")

  return true
}

Now that you have installed the Firebase and Mobile Ads SDKs, let's get started with loading native ads.

The GADAdLoader class loads native ads. It will load GADUnifiedNativeAds.

It's recommended to preload ads as early as possible in your application. Once you show your feed, you should ideally have the native ads already loaded so you can display them at the same time you display your content.

We are going to implement this behavior in this example by preloading ads in the ViewController class and disabling the to Show Menu button until all the ads have loaded.

In ViewController.Swift, add a line to import Firebase.

ViewController.Swift

import Firebase

Next, add the following properties to your ViewController class:

ViewController.Swift

  /// The ad unit ID from the AdMob UI.
  let adUnitID = "ca-app-pub-3940256099942544/8407707713"

  /// The number of native ads to load (between 1 and 5 for this example).
  let numAdsToLoad = 5

  /// The native ads.
  var nativeAds = [GADUnifiedNativeAd]()

  /// The ad loader that loads the native ads.
  var adLoader: GADAdLoader!

The app is going to load 5 ads sequentially, using the multiple native ads loading feature. The adLoader variable is used to load the native ads, and the ads are stored in the nativeAds array once loaded. Finally, a callback is received when all ads are loaded.

Now replace your viewDidLoad()method with the following implementation:

ViewController.Swift

  override func viewDidLoad() {
    super.viewDidLoad()

    // Load the menu items.
    addMenuItems()

    let options = GADMultipleAdsAdLoaderOptions()
    options.numberOfAds = numAdsToLoad

    // Prepare the ad loader and start loading ads.
    adLoader = GADAdLoader(adUnitID: adUnitID,
                           rootViewController: self,
                           adTypes: [.unifiedNative],
                           options: [options])
    adLoader.load(GADRequest())
  }

Take a closer look at the code above. We're initializing the ad loader with the number of ads we want to load, and we're loading the ads. However, if you run your app right now, you'll notice the app is stuck in a loading state:

In the next step, you'll learn how to register for ad callbacks when ads load, fail to load and finish loading, so you can receive the ads and move to the next view.

GADAdLoader has a delegate property to register for callbacks when the ad loaded or ad failed to load. In this step, you'll set this delegate to load subsequent ads.

First, modify your class signature to implement GADUnifiedNativeAdLoaderDelegate:

ViewController.Swift

class ViewController: UIViewController, GADUnifiedNativeAdLoaderDelegate {

Next, in your viewDidLoad() method, set your ad loader's delegate property:

ViewController.Swift

override func viewDidLoad() {
    super.viewDidLoad()

    // Load the menu items.
    addMenuItems()

    let options = GADMultipleAdsAdLoaderOptions()
    options.numberOfAds = numAdsToLoad

    // Prepare the ad loader and start loading ads.
    adLoader = GADAdLoader(adUnitID: adUnitID,
                           rootViewController: self,
                           adTypes: [.unifiedNative],
                           options: [options])
    adLoader.delegate = self
    adLoader.load(GADRequest())
  }

Finally, implement the delegate in your ViewController class to handle both the success and failure ad load methods:

ViewController.Swift

  // MARK: - GADAdLoaderDelegate

  func adLoader(_ adLoader: GADAdLoader,
                didFailToReceiveAdWithError error: GADRequestError) {
    print("\(adLoader) failed with error: \(error.localizedDescription)")

  }

  func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADUnifiedNativeAd) {
    print("Received native ad: \(nativeAd)")

    // Add the native ad to the list of native ads.
    nativeAds.append(nativeAd)
  }
  
  func adLoaderDidFinishLoading(_ adLoader: GADAdLoader) {
    enableMenuButton()
  }

When the ad load succeeds, this code stores the ad in the nativeAds array you defined earlier. It logs errors, and also enables the menu button when loading has completed.

Run your project

If you run your project now, you should see multiple ads loading in the logs. You should also see the Show Menu button get enabled once ads have finished loading.

In the next step, you will learn how to prepare your ad layout for use in the table.

The project you started with includes UnifiedNativeAdCell.xib, which is used for rendering GADUnifiedNativeAd objects. Currently, this is a basic UIView with subviews representing ad properties. However, this UIView needs some changes:

  1. The main view needs to be a GADUnifiedNativeAdView
  2. The subviews need to be registered with the appropriate IBOutlet properties on GADUnifiedNativeAdView

Prepare the Native ad layout

Open up UnifiedNativeAdCell.xib, and select the view under Content View. Then open up the Identity Inspector on the right hand side and change the class to GADUnifiedNativeAdView, as shown in the screenshot below.

Note that view already includes an Ad attribution view as per Admob's policy guidelines.

UnifiedNativeAdCell.xib

All unified native ads must be placed inside of a GADUnifiedNativeAdView in order for the Google Mobile Ads SDK to do impression tracking on them. The change you just made makes this view a GADUnifiedNativeAdView.

Next, select the view named Media View, and check the Identity Inspector on the right hand side. Check the class for this view and make sure it is already named GADMediaView.

UnifiedNativeAdCell.xib

GADMediaView is a special view type defined by the Google Mobile Ads SDK for use with native ads, and is used to support video assets. If the native ad you load contains a video asset, it will be displayed within this GADMediaView. If a video ad is not available, the Google Mobile Ads SDK takes the first image returned from the native ad, and displays it within the GADMediaView.

The rest of these views are for text assets in the native ads. In this example, they are displayed using a combination of labels and buttons. In a real life example, the layout and types of views you use are up to your discretion.

Associate ad views with the assets

The UnifiedNativeAdCell.xib file represents a native ad, but you must tell the Google Mobile Ads SDK which view corresponds to which asset. Click on the Unified Native Ad View and open the Connections Inspector on the right hand side. Click the mediaView outlet, and drag it to the GADMediaView defined in your xib file, as shown below:

UnifiedNativeAdCell.xib

Do this for each view in the GADUnifiedNativeAdView. When you're done, you should have 7 outlets connected and they should look like this:

Performing this linking is required so that the Google Mobile Ads SDK can track clicks on these views. You will also use these properties in the next step to populate these views with ad data.

Run your project

Run your project again to make sure it's still working. You've made good progress but you won't see ads quite yet!

Your native ad layout is now prepared, but your code is not using it yet. In the next step, you will update your TableViewController to include native ads.

Your table view is currently only set up to handle cells of type MenuItemViewCell. In this step, you will change your TableViewController's UITableViewDelegate to handle native ad cells. You will use the UnifiedNativeAdCell.xib file which you prepared in the previous step.

First, import Firebase in your TableViewController:

TableViewController.swift

import Firebase

Next, update your viewDidLoad() method to register UnifiedNativeAdCell for cell reuse:

TableViewController.swift

  override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(UINib(nibName: "MenuItem", bundle: nil),
        forCellReuseIdentifier: "MenuItemViewCell")
    tableView.register(UINib(nibName: "UnifiedNativeAdCell", bundle: nil),
        forCellReuseIdentifier: "UnifiedNativeAdCell")
  }

Finally, replace your tableView(cellForRowAt:) method with the following code:

TableViewController.swift

  override func tableView(_ tableView: UITableView,
      cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    if let menuItem = tableViewItems[indexPath.row] as? MenuItem {

      let reusableMenuItemCell = tableView.dequeueReusableCell(
          withIdentifier: "MenuItemViewCell",
          for: indexPath) as! MenuItemViewCell

      reusableMenuItemCell.nameLabel.text = menuItem.name
      reusableMenuItemCell.descriptionLabel.text = menuItem.description
      reusableMenuItemCell.priceLabel.text = menuItem.price
      reusableMenuItemCell.categoryLabel.text = menuItem.category
      reusableMenuItemCell.photoView.image = menuItem.photo

      return reusableMenuItemCell
    } else {
      let nativeAd = tableViewItems[indexPath.row] as! GADUnifiedNativeAd
      /// Set the native ad's rootViewController to the current view controller.
      nativeAd.rootViewController = self

      let nativeAdCell = tableView.dequeueReusableCell(
          withIdentifier: "UnifiedNativeAdCell", for: indexPath)

      // Get the ad view from the Cell. The view hierarchy for this cell is defined in
      // UnifiedNativeAdCell.xib.
      let adView : GADUnifiedNativeAdView = nativeAdCell.contentView.subviews.first as! GADUnifiedNativeAdView

      // Associate the ad view with the ad object.
      // This is required to make the ad clickable.
      adView.nativeAd = nativeAd

      // Populate the ad view with the ad assets.
      (adView.headlineView as! UILabel).text = nativeAd.headline
      (adView.priceView as! UILabel).text = nativeAd.price
      if let starRating = nativeAd.starRating {
        (adView.starRatingView as! UILabel).text =
            starRating.description + "\u{2605}"
      } else {
        (adView.starRatingView as! UILabel).text = nil
      }
      (adView.bodyView as! UILabel).text = nativeAd.body
      (adView.advertiserView as! UILabel).text = nativeAd.advertiser
      // The SDK automatically turns off user interaction for assets that are part of the ad, but
      // it is still good to be explicit.
      (adView.callToActionView as! UIButton).isUserInteractionEnabled = false
      (adView.callToActionView as! UIButton).setTitle(
          nativeAd.callToAction, for: UIControlState.normal)

      return nativeAdCell

    } 
  }

What did you just change?

You just added a lot of code here, so let's walk through what changed.

Each if block handles a data type (menu items, native ads). The menu items code was present already, and native ad block performs the same logical steps. Let's look closer at the native ad if block.

If the table item is a native ad, you first updated the rootViewController property on the ad.

      nativeAd.rootViewController = self

This rootViewController property is used by the Google Mobile Ads SDK to determine what view controller to use in the segue when an ad is clicked. Since you requested the ads in a different class than the class displaying the ads, the rootViewController property needs to be updated to the view controller that's displaying the ad.

Next, you instantiated a new UnifiedNativeAdCell. After finding the GADUnifiedNativeAdView within this cell, you set the nativeAd property on the view:

      adView.nativeAd = nativeAd

Finally, this code populated the views inside the GADUnifiedNativeAdView with the data from the ad. Populating a view with data is typical of any UITableView implementation.

       (adView.headlineView as! UILabel).text = nativeAd.headline
      (adView.priceView as! UILabel).text = nativeAd.price
      if let starRating = nativeAd.starRating {
        (adView.starRatingView as! UILabel).text =
            starRating.description + "\u{2605}"
      } else {
        (adView.starRatingView as! UILabel).text = nil
      }
      (adView.bodyView as! UILabel).text = nativeAd.body
      (adView.advertiserView as! UILabel).text = nativeAd.advertiser
      // The SDK automatically turns off user interaction for assets that are part of the ad, but
      // it is still good to be explicit.
      (adView.callToActionView as! UIButton).isUserInteractionEnabled = false
      (adView.callToActionView as! UIButton).setTitle(
          nativeAd.callToAction, for: UIControlState.normal)

Your TableViewController is now fully prepared to handle native ads. The final step is to actually pass the native ads to your TableViewController.

The final step is to pass the native ads that you loaded in your ViewController class to your TableViewController class.

First, add the addNativeAds() method to your ViewController class:

ViewController.swift

  /// Add native ads to the tableViewItems list.
  func addNativeAds() {
    if nativeAds.count <= 0 {
      return
    }

    let adInterval = (tableViewItems.count / nativeAds.count) + 1
    var index = 0
    for nativeAd in nativeAds {
      if index < tableViewItems.count {
        tableViewItems.insert(nativeAd, at: index)
        index += adInterval
      } else {
        break
      }
    }
  }

The addNativeAds() method inserts ads into your tableview items, and spreads them out based on the number of ads that loaded.

Next, call the addNativeAds() method once all the ads have finished loading. You'll call this right before you enable the menu button:

ViewController.swift

  func adLoaderDidFinishLoading(_ adLoader: GADAdLoader) {
    addNativeAds()
    enableMenuButton()
  }

Now the items passed to your TableViewController includes ads in addition to menu items.

Run your project

If you run your project now, you'll see native ads in your table!

Your feed app now includes native ads.

What we've covered

Next Steps

Learn More