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.
You will build a feed-based app with ads injected at regular intervals. Your app will:
|
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.
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:
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.
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.
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:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '7.0'
target 'NativeAdvancedTableViewExample' do
use_frameworks!
pod 'Firebase'
pod 'Firebase/AdMob'
end
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.
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
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.
import Firebase
...
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Initialize the Firebase SDK.
FirebaseApp.configure()
return true
}
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.
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.
import Firebase
Next, add the following properties to your ViewController
class:
/// 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:
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:
class ViewController: UIViewController, GADUnifiedNativeAdLoaderDelegate {
Next, in your viewDidLoad()
method, set your ad loader's delegate
property:
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:
// 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.
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:
GADUnifiedNativeAdView
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.
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.
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.
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:
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 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
:
import Firebase
Next, update your viewDidLoad()
method to register UnifiedNativeAdCell
for cell reuse:
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:
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
}
}
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:
/// 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:
func adLoaderDidFinishLoading(_ adLoader: GADAdLoader) {
addNativeAds()
enableMenuButton()
}
Now the items passed to your TableViewController
includes ads in addition to menu items.
If you run your project now, you'll see native ads in your table!
Your feed app now includes native ads.