Native Custom Events

This guide is intended for publishers who want to use AdMob Mediation to load and display native ads from a network that isn't one of AdMob's Supported ad networks. See Custom Events for information about using AdMob Mediation to load and display banner, interstitial, or rewarded display ads.

Custom events are mediation adapter classes capable of requesting ads from another network. When you add the name of one of these classes to the mediation settings for an ad unit, the SDK can instantiate and use it to retrieve ads. Native custom event classes need to be able to do the following things:

  • Request native ads from a mediated network.
  • Forward events from the mediated network's SDK to the Google Mobile Ads SDK.
  • Use a GADMediatedNativeAd to map mediated native ad objects to AdMob's native ad interface.

Each of these tasks is covered below. You can also find the full source for a sample custom event project at our GitHub repository.

Prerequisites

To implement an AdMob custom event, you must first integrate the Mobile Ads SDK into your project. You may also want to first read about making an ad request and how mediation works.

The Sample SDK

The code used in this guide is taken from our sample custom event project, which also includes a "Sample SDK." In order for the project to illustrate how to build a custom event that mediates another ad network's SDK, it needed an SDK to mediate, so we created a mock called the Sample SDK.

The Sample SDK features classes similar to what you'd find in an ad network's production SDK. There are request objects like SampleNativeAdRequest, ad loaders like SampleNativeAdLoader, and other classes, constants and protocols used to simulate a real network's SDK. The ads that it produces are mocks, though, and no additional network traffic is generated.

Request native ads

The requestNativeAdWithParameter: method

Custom event classes must implement the GADCustomEventNativeAd protocol, which includes a method used by the Google Mobile Ads SDK to request native ads from the custom event:

Swift

func request(withParameter serverParameter: String,
                                   request: GADCustomEventRequest,
                                   adTypes: [Any],
                                   options: [Any],
                        rootViewController: UIViewController)

Objective-C

- (void)requestNativeAdWithParameter:(NSString *)serverParameter
                             request:(GADCustomEventRequest *)request
                             adTypes:(NSArray *)adTypes
                             options:(NSArray *)options
                  rootViewController:(UIViewController *)rootViewController;

When this method is called, the custom event should asynchronously request a native ad. Four of the parameters for requestNativeAdWithParameter: carry information that the custom event can use in making its request:

  • serverParameter - When adding a custom event to an ad unit's mediation configuration, publishers can enter a string value to be passed along with each request. This parameter holds that value (typically another ad unit ID, which was issued by the mediated network).
  • request - A GADCustomEventRequest object, which contains properties specific to a single request, such as which native formats are requested. GADCustomEventRequest also includes properties for targeting information provided by publishers at request time.
  • adTypes - An NSArray containing constants that indicate which native formats are requested. Possible values include kGADAdLoaderAdTypeNativeContent and kGADAdLoaderAdTypeNativeAppInstall.
  • options - An NSArray containing GADAdLoaderOptions objects that indicate the publisher's preferences for loading ads.

In addition to the parameters carrying request information, the rootViewController parameter provides a reference to the UIViewController in which the ad is to be displayed.

Here's a code snippet from our example custom event project that shows an implemented requestNativeAdWithParameter: method:

SampleCustomEventNativeAd (excerpt)

Swift

func request(withParameter serverParameter: String, request: GADCustomEventRequest, adTypes: [Any], options: [Any], rootViewController: UIViewController) {

  let adLoader = SampleNativeAdLoader()
  let sampleRequest = SampleNativeAdRequest()
  // Part of the custom event's job is to examine the properties of the GADCustomEventRequest and
  // create a request for the mediated network's SDK that matches them.

  if let adTypes = adTypes as? [String] {
    for adType: String in adTypes {
      if adType.isEqual(GADAdLoaderAdType.nativeContent) {
        sampleRequest.contentAdsRequested = true
      }
      else if adType.isEqual(GADAdLoaderAdType.nativeAppInstall) {
        sampleRequest.appInstallAdsRequested = true
      }
    }
  }

  if let options = options as? [GADAdLoaderOptions] {
    for loaderOptions: GADAdLoaderOptions in options {
      if let imageOptions = loaderOptions as? GADNativeAdImageAdLoaderOptions {

        sampleRequest.shouldRequestPortraitImages =
        imageOptions.preferredImageOrientation = .portrait;
        sampleRequest.shouldRequestMultipleImages = imageOptions.shouldRequestMultipleImages
        // If the GADNativeAdImageAdLoaderOptions' disableImageLoading property is YES, the adapter
        // should send just the URLs for the images.
        sampleRequest.shouldDownloadImages = !imageOptions.disableImageLoading
      }
      else if let options = loaderOptions as? GADNativeAdViewAdOptions {
        nativeAdViewAdOptions = options
      }
    }
  }
  // This custom event uses the server parameter to carry an ad unit ID, which is the most common
  // use case.
  adLoader.adUnitID = serverParameter
  adLoader.delegate = self
  adLoader.fetchAd(sampleRequest)
}

Objective-C

- (void)requestNativeAdWithParameter:(NSString *)serverParameter
                             request:(GADCustomEventRequest *)request
                             adTypes:(NSArray *)adTypes
                             options:(NSArray *)options
                  rootViewController:(UIViewController *)rootViewController {
  SampleNativeAdLoader *adLoader = [[SampleNativeAdLoader alloc] init];
  SampleNativeAdRequest *sampleRequest = [[SampleNativeAdRequest alloc] init];

  // Part of the custom event's job is to examine the properties of the GADCustomEventRequest and
  // create a request for the mediated network's SDK that matches them.
  for (NSString *adType in adTypes) {
    if ([adType isEqual:kGADAdLoaderAdTypeNativeContent]) {
      sampleRequest.contentAdsRequested = YES;
    } else if ([adType isEqual:kGADAdLoaderAdTypeNativeAppInstall]) {
      sampleRequest.appInstallAdsRequested = YES;
    }
  }

  for (GADNativeAdImageAdLoaderOptions *imageOptions in options) {
    if (![imageOptions isKindOfClass:[GADNativeAdImageAdLoaderOptions class]]) {
      continue;
    }

    sampleRequest.shouldRequestPortraitImages =
        imageOptions.preferredImageOrientation ==
        GADNativeAdImageAdLoaderOptionsOrientationPortrait;
    sampleRequest.shouldDownloadImages = !imageOptions.disableImageLoading;
    sampleRequest.shouldRequestMultipleImages = imageOptions.shouldRequestMultipleImages;
  }

  // This custom event uses the server parameter to carry an ad unit ID, which is the most common
  // use case.
  adLoader.adUnitID = serverParameter;
  adLoader.delegate = self;

  [adLoader fetchAd:sampleRequest];
}

This is a sample custom event that mediates to an imaginary ad network via a mock "Sample SDK." The custom event uses the information provided in the requestNativeAdWithParameter: parameters to request an ad from the Sample SDK's SampleNativeAdLoader. It also assigns itself as the delegate for theSampleNativeAdLoader, so it can forward events from the Sample SDK back to the Google Mobile Ads SDK. That process is the topic of the next section.

Respect native ad formats

As noted above, the adTypes array includes information about which native ad formats the publisher is requesting. It is extremely important that custom events respect this choice and return only those formats that the publisher indicated they're prepared to display. Otherwise, they could cause the publisher's rendering code to fail.

If, for example, the mediated ad network only ever provides app install ads, and the publisher requests content ads alone, your custom event should not request an app install ad anyway and then try to map it to the content ad format. Instead, it should call the delegate's customEventNativeAd:didFailToLoadWithError: method with an error code of kGADErrorInvalidRequest.

GADAdLoaderOptions

When making a request for native ads, publishers provide an array of GADAdLoaderOptions objects to specify their preferences for that request, such as how image assets should be returned. These are in turn provided to custom events as one of the parameters in the requestNativeAdWithParameter: method. Custom events should iterate over the options array, and act in accordance with the preferences it contains.

For example, if the options array contains a GADNativeAdImageAdLoaderOptions object with its shouldDownloadImages value set to true, the custom event must return actual image assets rather than just the URLs. In this case, if the SDK being adapted only ever provides URLs for images, then the custom event must use those urls to download the image files and make their data available to the publisher.

Forward events to the Mobile Ads SDK

A few things can happen when a custom event tries to load a native ad from its mediated network. The SDK could successfully return a native ad, it could come back with an error, or it might simply report that no ads are available. It's important for the Google Mobile Ads SDK to be aware of these events, so the GADCustomEventNativeAd protocol includes a delegate (of type GADCustomEventNativeAdDelegate), which the custom event can use to forward them.

It's part of a custom event's job to act as a "man-in-the-middle," listening for events from the mediated SDK, and then sending the corresponding GADCustomEventNativeAdDelegate protocol message to the delegate as appropriate. Your custom event needs to be aware of the following messages :

  • customEventNativeAd:didReceiveMediatedNativeAd: - This message should be sent when a custom event successfully loads a native ad. It takes a single parameter of type GADMediatedNativeAd, which the custom event should use to pass an "adapted" version of the native ad it just loaded (GADMediatedNativeAd classes are covered in the next section).
  • customEventNativeAd:didFailToLoadWithError: - When the custom event tries and fails to load a native ad, it should use this method to report the failure. It takes a single NSError parameter, which should contain information specific to the failure.

Here's an example of how this works in our example custom event project:

SampleCustomEventNativeAd (excerpt)

Swift

extension SampleCustomEventNativeAdSwift: SampleNativeAdLoaderDelegate {

  func adLoader(_ adLoader: SampleNativeAdLoader, didReceive nativeAppInstallAd: SampleNativeAppInstallAd) {
    if let mediatedAd = SampleMediatedNativeAppInstallAdSwift(sampleNativeAppInstallAd: nativeAppInstallAd, nativeAdViewAdOptions: nativeAdViewAdOptions) {
      delegate?.customEventNativeAd(self, didReceive: mediatedAd)
    }
  }

  func adLoader(_ adLoader: SampleNativeAdLoader, didReceive nativeContentAd: SampleNativeContentAd) {
    if let mediatedAd = SampleMediatedNativeContentAdSwift(sampleNativeContentAd: nativeContentAd, nativeAdViewAdOptions: nativeAdViewAdOptions) {
      delegate?.customEventNativeAd(self, didReceive: mediatedAd)
    }
  }

  func adLoader(_ adLoader: SampleNativeAdLoader, didFailToLoadAdWith errorCode: SampleErrorCode) {
    let error = NSError(domain: customEventErrorDomain, code: errorCode.rawValue, userInfo: nil)
    delegate?.customEventNativeAd(self, didFailToLoadWithError: error)
  }

}

Objective-C

@interface SampleCustomEventNativeAd () <SampleNativeAdLoaderDelegate>
@end

@implementation SampleCustomEventNativeAd

@synthesize delegate;

...

#pragma mark SampleNativeAdLoaderDelegate implementation

- (void)adLoader:(SampleNativeAdLoader *)adLoader
    didReceiveNativeAppInstallAd:(SampleNativeAppInstallAd *)nativeAppInstallAd {
  SampleMediatedNativeAppInstallAd *mediatedAd = [[SampleMediatedNativeAppInstallAd alloc]
      initWithSampleNativeAppInstallAd:nativeAppInstallAd];
  [self.delegate customEventNativeAd:self didReceiveMediatedNativeAd:mediatedAd];
}

- (void)adLoader:(SampleNativeAdLoader *)adLoader
    didReceiveNativeContentAd:(SampleNativeContentAd *)nativeContentAd {
  SampleMediatedNativeContentAd *mediatedAd =
      [[SampleMediatedNativeContentAd alloc] initWithSampleNativeContentAd:nativeContentAd];
  [self.delegate customEventNativeAd:self didReceiveMediatedNativeAd:mediatedAd];
}

- (void)adLoader:(SampleNativeAdLoader *)adLoader
    didFailToLoadAdWithErrorCode:(SampleErrorCode)errorCode {
  NSError *error = [NSError errorWithDomain:customEventErrorDomain code:errorCode userInfo:nil];
  [self.delegate customEventNativeAd:self didFailToLoadWithError:error];
}

...

@end

The class implements the Sample SDK's SampleNativeAdLoaderDelegate protocol. In SampleCustomEventNativeAd.m (excerpt) the custom event class itself was assigned to the SampleNativeAdLoader as its delegate:

Swift

adLoader.delegate = self

Objective-C

adLoader.delegate = self;

This ensures that the Sample SDK sends messages back to the custom event when it has success or failure to report. The custom event then sends the appropriate message to its own delegate, forwarding the event to the Google Mobile Ads SDK. In short, the Google Mobile Ads SDK listens to the custom event, which is listening to the mediated SDK.

The adLoader:didFailToLoadAdWithErrorCode method above is a great example of how this works. When the Sample SDK fails to load an ad, it sends an adLoader:didFailToLoadAdWithErrorCode: message to the custom event. The custom event creates a new NSError object with the SampleErrorCode provided by the Sample SDK, and then sends it to its own delegate via the customEventNativeAd:didFailToLoadWithError: message. In this way, a Sample SDK event is turned into a Google Mobile Ads SDK event.

Map native ads

Different SDKs have their own unique formats for native ads. One SDK might return objects that contain a "title" field, for instance, while another might have "headline." Additionally, the methods used to track impressions and process clicks may vary from one SDK to another. To smooth out these wrinkles, when a custom event receives a native ad object from its mediated network's SDK, it should use a subclass of GADMediatedNativeAd to "map" the mediated SDK's native ad object so it matches the interface expected by the Google Mobile Ads SDK.

Each of AdMob's system-defined native ad formats has a corresponding GADMediatedNativeAd class: GADMediatedNativeAppInstallAd for app install ads, and GADMediatedNativeContentAd for content ads. Custom events should create subclasses of these to map the native ad objects provided by their mediated SDK.

Here's an example mapper class from our example custom event project:

Swift

class SampleMediatedNativeAppInstallAdSwift: NSObject {

  init?(sampleNativeAppInstallAd: SampleNativeAppInstallAd?, nativeAdViewAdOptions: GADNativeAdViewAdOptions?) {
    guard let sampleNativeAppInstallAd = sampleNativeAppInstallAd else {
      return nil
    }
    sampleAd = sampleNativeAppInstallAd
    super.init()

    extras = [SwiftCustomEventConstants.awesomenessKey: sampleAd.degreeOfAwesomeness ?? ""]
    if let image = sampleAd.image {
      mappedImages = [GADNativeAdImage(image: image)]
    }
    else {
      let imageURL = URL(fileURLWithPath: sampleNativeAppInstallAd.imageURL)
      mappedImages = [GADNativeAdImage(url: imageURL, scale: sampleAd.imageScale)]
    }
    if let icon = sampleAd.icon {
      mappedIcon = GADNativeAdImage(image: icon)
    }
    else {
      let iconURL = URL(fileURLWithPath: sampleNativeAppInstallAd.iconURL)
      mappedIcon = GADNativeAdImage(url: iconURL, scale: sampleAd.iconScale)
    }
    self.nativeAdViewAdOptions = nativeAdViewAdOptions
  }
}

extension SampleMediatedNativeAppInstallAdSwift : GADMediatedNativeAppInstallAd {
  func headline() -> String? {
    return sampleAd.headline
  }

  func images() -> [Any]? {
    return mappedImages
  }

  func body() -> String? {
    return sampleAd.body
  }

  func icon() -> GADNativeAdImage? {
    return mappedIcon
  }

  func callToAction() -> String? {
    return sampleAd.callToAction
  }

  func starRating() -> NSDecimalNumber? {
    return sampleAd.starRating
  }

  func store() -> String? {
    return sampleAd.store
  }

  func price() -> String? {
    return sampleAd.price
  }

  func extraAssets() -> [AnyHashable : Any]? {
    return extras
  }

  func mediatedNativeAdDelegate() -> GADMediatedNativeAdDelegate? {
    return self
  }

  func adChoicesView() -> UIView? {
    return nil
  }
}

extension SampleMediatedNativeAppInstallAdSwift: GADMediatedNativeAdDelegate {
...
  func mediatedNativeAdDidRecordImpression(_ mediatedNativeAd: GADMediatedNativeAd) {
    sampleAd.recordImpression()
  }

  func mediatedNativeAd(_ mediatedNativeAd: GADMediatedNativeAd, didRecordClickOnAssetWithName assetName: String, view: UIView, viewController: UIViewController) {
    sampleAd.handleClick(on: view)
  }
}

Objective-C

// SampleMediatedNativeAppInstallAd.h (excerpt)

@interface SampleMediatedNativeAppInstallAd : NSObject<GADMediatedNativeAppInstallAd>

- (instancetype)initWithSampleNativeAppInstallAd:
        (SampleNativeAppInstallAd*)sampleNativeAppInstallAd;

@end

// SampleMediatedNativeAppInstallAd.m (excerpt)

@implementation SampleMediatedNativeAppInstallAd

- (instancetype)initWithSampleNativeAppInstallAd:
        (nonnull SampleNativeAppInstallAd *)sampleNativeAppInstallAd {
  if (!sampleNativeAppInstallAd) {
    return nil;
  }

  self = [super init];
  if (self) {
    _sampleAd = sampleNativeAppInstallAd;
    _extras = @{SampleCustomEventExtraKeyAwesomeness : _sampleAd.degreeOfAwesomeness};

    if (_sampleAd.image) {
      _mappedImages = @[ [[GADNativeAdImage alloc] initWithImage:_sampleAd.image] ];
    } else {
      NSURL *imageURL = [[NSURL alloc] initFileURLWithPath:_sampleAd.imageURL];
      _mappedImages =
          @[ [[GADNativeAdImage alloc] initWithURL:imageURL
                                             scale:_sampleAd.imageScale] ];
    }

    if (_sampleAd.icon) {
      _mappedIcon = [[GADNativeAdImage alloc] initWithImage:_sampleAd.icon];
    } else {
      NSURL *iconURL = [[NSURL alloc] initFileURLWithPath:_sampleAd.iconURL];
      _mappedIcon = [[GADNativeAdImage alloc] initWithURL:iconURL scale:_sampleAd.iconScale];
    }
  }
  return self;
}

- (NSString *)headline {
  return self.sampleAd.headline;
}

- (NSArray *)images {
  return self.mappedImages;
}

- (NSString *)body {
  return self.sampleAd.body;
}

- (GADNativeAdImage *)icon {
  return self.mappedIcon;
}

- (NSString *)callToAction {
  return self.sampleAd.callToAction;
}

- (NSDecimalNumber *)starRating {
  return self.sampleAd.starRating;
}

- (NSString *)store {
  return self.sampleAd.store;
}

- (NSString *)price {
  return self.sampleAd.price;
}

- (NSDictionary *)extraAssets {
  return self.extras;
}

- (id<GADMediatedNativeAdDelegate>)mediatedNativeAdDelegate {
  return self;
}

#pragma mark - GADMediatedNativeAdDelegate implementation

- (void)mediatedNativeAdDidRecordImpression:(id<GADMediatedNativeAd>)mediatedNativeAd {
  if (self.sampleAd) {
    [self.sampleAd recordImpression];
  }
}

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd
    didRecordClickOnAssetWithName:(NSString *)assetName
                             view:(UIView *)view
                   viewController:(UIViewController *)viewController {
  if (self.sampleAd) {
    [self.sampleAd handleClickOnView:view];
  }
}

@end

Let's first take a look at the initializer and some of the work it's doing.

Hold a reference to the mediated native ad object

The initializer accepts an instance of SampleNativeAppInstallAd as its only parameter. This is the native ad class used by the Sample SDK for its app install ads. The mapper needs a reference to the mediated ad object so it can pass on click and impression events, so it stores one as sampleAd.

Create an NSDictionary to hold extra assets

Some mediated networks may provide additional assets beyond those in the AdMob native ad formats. The GADMediatedNativeAd protocol includes a method called extraAssets that the Google Mobile Ads SDK uses to retrieve any of these "extra" assets from your mapper. The initializer above creates an NSDictionary and fills it with the extra assets provided by the Sample SDK (in this case, a single NSString value called degreeOfAwesomeness). This NSDictionary is used as a return value by the extraAssets method later on:

Swift

extras = [SampleCustomEventExtraKeyAwesomeness : sampleAd.degreeOfAwesomeness]

Objective-C

_extras = @{SampleCustomEventExtraKeyAwesomeness : _sampleAd.degreeOfAwesomeness};

Map image assets

Mapping image assets is a little more complicated than mapping simpler data types like NSString or double. Images might be downloaded automatically or simply returned as URL values. Their pixel density can also vary. To help custom event developers manage these details, the Google Mobile Ads SDK provides the GADNativeAdImage class. Image asset information (whether it's actual UIImage objects or just NSURL values) should be returned to the Google Mobile Ads SDK using this class. Here's how the mapper class handles creating a GADNativeAdImage to hold the icon image for its app install ad:

Swift

if let icon = sampleAd.icon {
  mappedIcon = GADNativeAdImage(image: icon)
} else {
  let iconURL = URL(fileURLWithPath: sampleNativeAppInstallAd.iconURL)
  mappedIcon = GADNativeAdImage(url: iconURL, scale: sampleAd.iconScale)
}

Objective-C

if (_sampleAd.icon) {
  _mappedIcon = [[GADNativeAdImage alloc] initWithImage:_sampleAd.icon];
} else {
  NSURL *iconURL = [[NSURL alloc] initFileURLWithPath:_sampleAd.iconURL];
  _mappedIcon = [[GADNativeAdImage alloc] initWithURL:iconURL scale:_sampleAd.iconScale];
}

If you recall from the section on making requests, publishers can use a GADNativeAdImageAdLoaderOptions object to specify that native ad images shouldn't be automatically downloaded. Here, the mapper checks to see if the image was downloaded already, and creates a GADNativeAdImage with the appropriate information—either a UIImage or a matching pair of NSURL and scale values.

With the initializer covered, let's move on to the work being done elsewhere in the class.

Return mapped assets

This mapper class inherits methods from GADMediatedNativeAppInstallAd that correspond to the expected assets for an app install ad. The Google Mobile Ads SDK calls these methods to retrieve the assets, so your mapper class should return the appropriate value. For most assets, this is pretty simple:

Swift

func headline() -> String? {
  return sampleAd.headline
}

Objective-C

- (NSString *)headline {
  return self.sampleAd.headline;
}

For some assets, however, data types may not match or some other type of conversion may be required. It's the mapper's job to handle these details, and the asset methods are a good place to do it.

AdChoices

Your adapter is responsible for placing your AdChoices icon in Google's native ad view. You should use the didRenderInView: and didUntrackView: delegate methods in GADMediatedNativeAdDelegate to add and remove your AdChoices view.

The adapter must also respect the publisher's preference of AdChoices location by checking if any options are of type GADNativeAdViewAdOptions that have the preferredAdChoicesPosition property set. If a preferred corner is not specified, AdChoices should be rendered in the top right corner.

A sample implementation of how to respect the publisher's AdChoices placement and render the AdChoices icon is shown below:

Swift

class SampleMediatedNativeAd: NSObject, GADMediatedNativeAdDelegate {
  /// Ad networks should provide their own AdChoices view.
  private var adChoicesView: SampleAdChoicesView?
  /// Note: GADNativeAdViewAdOptions requires GoogleMobileAds SDK v7.12.0 or higher.
  private var nativeAdViewAdOptions: GADNativeAdViewAdOptions?

  private func getNativeAd(withAdTypes adTypes: [Any], options: [Any]) {
    if let options = options as? [GADAdLoaderOptions] {
      for loaderOptions: GADAdLoaderOptions in options {
        if let options = loaderOptions as? GADNativeAdViewAdOptions {
          nativeAdViewAdOptions = options
        }
        // You can similarly check for other options (GADNativeAdImageAdLoaderOptions).
      }
    }
    // Request your native ad here.
  }

  // MARK: - GADMediatedNativeAdDelegate
  func mediatedNativeAd(_ mediatedNativeAd: GADMediatedNativeAd, didRenderIn view: UIView, viewController: UIViewController) {
    if !adChoicesView {
      // Create or retrieve your AdChoices view.
    }
    // Place AdChoices View in mediated network's view.
    view.addSubview(adChoicesView)
    switch nativeAdViewAdOptions.preferredAdChoicesPosition {
    case .topLeftCorner:
    // Adjust placement of _adChoicesView frame to top left corner.
    case .bottomLeftCorner:
    // Adjust placement of _adChoicesView frame to bottom left corner.
    case .bottomRightCorner:
    // Adjust placement of _adChoicesView frame to bottom right corner.
    case .topRightCorner:        // Fall through.
      fallthrough
    default:
      // Default placement of AdChoices icon is the top right corner.
      // Adjust placement of _adChoicesView frame to top right corner.
    }
  }

  func mediatedNativeAd(_ mediatedNativeAd: GADMediatedNativeAd, didUntrackView view: UIView) {
    adInfoView?.removeFromSuperview()
  }
}

Objective-C

@interface SampleMediatedNativeAd ()<GADMediatedNativeAdDelegate> {

  /// Ad networks should provide their own AdChoices view.
  SampleAdChoicesView *_adChoicesView;

  /// Note: GADNativeAdViewAdOptions requires GoogleMobileAds SDK v7.12.0 or higher.
  GADNativeAdViewAdOptions *_nativeAdViewAdOptions;
}

- (void)getNativeAdWithAdTypes:(NSArray *)adTypes options:(NSArray *)options {

  if(options != nil) {
    for (GADAdLoaderOptions *loaderOptions in options) {
        if ([loaderOptions isKindOfClass:[GADNativeAdViewAdOptions class]]) {
            _nativeAdViewAdOptions = (GADNativeAdViewAdOptions *)loaderOptions;
        }
        // You can similarly check for other options (GADNativeAdImageAdLoaderOptions).
    }
  }

  // Request your native ad here.
}

#pragma mark - GADMediatedNativeAdDelegate

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd
         didRenderInView:(UIView *)view
          viewController:(UIViewController *)viewController {
  if (!_adChoicesView) {
    // Create or retrieve your AdChoices view.
  }
  // Place AdChoices View in mediated network's view.
  [view addSubview:_adChoicesView];

  switch (_nativeAdViewAdOptions.preferredAdChoicesPosition) {
    case GADAdChoicesPositionTopLeftCorner:
      // Adjust placement of _adChoicesView frame to top left corner.
      break;
    case GADAdChoicesPositionBottomLeftCorner:
      // Adjust placement of _adChoicesView frame to bottom left corner.
      break;
    case GADAdChoicesPositionBottomRightCorner:
      // Adjust placement of _adChoicesView frame to bottom right corner.
      break;
    case GADAdChoicesPositionTopRightCorner:
      // Fall through.
    default:
      // Default placement of AdChoices icon is the top right corner.
      // Adjust placement of _adChoicesView frame to top right corner.
      break;
  }

}

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd
          didUntrackView:(UIView *)view {
    // Remove SampleAdChoices view from its parent.
    [_adChoicesView removeFromSuperview];
}

Impression and click events

It's important that the mediated network's SDK be notified any time an impression or click occurs, so mapper classes are expected to provide the Google Mobile Ads SDK with a delegate object to use for this purpose. This is done via the mediatedNativeAdDelegate method. In the example above, the mapper class serves as its own delegate and returns itself:

Swift

func mediatedNativeAdDelegate() -> GADMediatedNativeAdDelegate? {
  return self
}

Objective-C

- (id<GADMediatedNativeAdDelegate>)mediatedNativeAdDelegate {
  return self;
}

Because different networks handle processing clicks and impressions differently, the GADMediatedNativeAdDelegate protocol accommodates two different approaches.

Handle clicks and impressions within the mapper itself

If the mediated native ad objects provide methods to record clicks and impressions, a custom event's mapper classes can use them. This is the most common approach. GADMediatedNativeAdDelegate includes two methods, mediatedNativeAdDidRecordImpression: and mediatedNativeAd:didRecordClickOnAssetWithName:, which mappers should override and use to call the corresponding method on the mediated native ad object.

Here's how the SampleMediatedNativeAppInstallAd handles this:

Swift

func mediatedNativeAdDidRecordImpression(_ mediatedNativeAd: GADMediatedNativeAd) {
  sampleAd?.recordImpression()
}

func mediatedNativeAd(_ mediatedNativeAd: GADMediatedNativeAd, didRecordClickOnAssetWithName assetName: String, view: UIView, viewController: UIViewController) {
  sampleAd?.handleClick(on: view)
}

Objective-C

- (void)mediatedNativeAdDidRecordImpression:(id<GADMediatedNativeAd>)mediatedNativeAd {
  if (self.sampleAd != nil) {
    [self.sampleAd recordImpression];
  }
}

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd
    didRecordClickOnAssetWithName:(NSString *)assetName
                             view:(UIView *)view
                   viewController:(UIViewController *)viewController {
  if (self.sampleAd != nil) {
    [self.sampleAd handleClick:view];
  }
}

Because the SampleNativeAppInstallAdMapper holds a reference to the Sample SDK's native ad object, it can simply call the appropriate method on that object to report a click or impression.

Let the mediated SDK track clicks and impressions

For ad networks that need to track clicks and impressions on their own, GADCustomEventNativeAd protocol offers two optional messages: handlesUserClicks and handlesUserImpressions. Returning a YES from one of these indicates the custom event tracks that type of occurrence for itself. Returning a NO or not responding indicates that the Google Mobile Ads SDK should handle tracking clicks and impressions on behalf of the custom event and use mediatedNativeAdDidRecordImpression: and mediatedNativeAd:didRecordClickOnAssetWithName: to report them.

Custom events tracking clicks or impressions themselves can use the mediatedNativeAd:didRenderInView: message in the GADMediatedNativeAdDelegate protocol to pass the native ad's view to the mediated SDK's native ad object, so the mediated SDK can use it to do the actual tracking. The sample SDK shown so far in this guide's code examples doesn't use this approach for handling clicks and impressions, but if it did, the appropriate mediatedNativeAd:didRenderInView: method would look like this:

Swift

func mediatedNativeAd(_ mediatedNativeAd: GADMediatedNativeAd, didRenderIn view: UIView, viewController: UIViewController) {
  sampleAd?.setNativeAdView(view)
}

Objective-C

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd didRenderInView:(UIView *)view {
  [self.sampleAd setNativeAdView:view];
}

GADMediatedNativeAdDelegate also includes mediatedNativeAd:didUntrackView:, which is used for the opposite purpose. Custom events should implement it to release any references to the view and if possible disassociate it from the native ad object.

GADMediatedNativeAdNotificationSource

In order for mediated native ads to report events like the presentation of a screen or recording of a click, the SDK provides the GADMediatedNativeAdNotificationSource class. It has six class methods corresponding to various events in the life of a mediated native ad, each taking a reference to the corresponding ad object:

  • mediatedNativeAdDidRecordImpression: - This method should be called by mediated native ads from custom events that track impressions for themselves to report an impression back to the Google Mobile Ads SDK. This is required for reporting purposes.
  • mediatedNativeAdDidRecordClick: - Similarly, custom events that track their own clicks should have their mediated native ads call this method to report that a click has occurred.
  • mediatedNativeAdWillPresentScreen: - Must be called just before a mediated native ad opens an in-app modal screen.
  • mediatedNativeAdWillDismissScreen: - Must be called just before the in-app modal screen opened by the mediated native ad is dismissed.
  • mediatedNativeAdDidDismissScreen: - Must be called after an in-app modal screen opened by the mediated native ad is dismissed.
  • mediatedNativeAdWillLeaveApplication: - Must be called just before the mediated native ad causes focus to leave the application, such as when opening a destination URL in Safari.

Use a custom event

To use a custom event, you need to add it to the mediation configuration for an ad unit. This is done in the AdMob interface. (Create a custom event provides detailed instructions for editing an ad unit's mediation configuration).

When you add the custom event to an ad unit's mediation configuration, you'll be asked for three pieces of information:

  • Class Name - This is the class name of your custom event.
  • Label - This is the label you'd like AdMob's interface to use to represent the custom event when it displays the ad unit's mediation sources. It's just for you, as it only ever appears on AdMob.com
  • Parameter - This is a string value that is passed to the custom event whenever requests for this ad unit are made. Typically this value is set to an ad unit ID from the mediated network.

Here's a screenshot of an example custom event entry:

That's it! You now have everything you need to write your own iOS custom events for AdMob.

Send feedback about...

AdMob for iOS
AdMob for iOS
Need help? Visit our support page.