AFS for Mobile Apps (AFSMA) Implementation for Android

The Google Mobile Ads SDK also supports custom search styles. If your app already uses the Google Mobile Ads SDK, we recommend you use the AFSMA SDK version instead.

If you're upgrading to version 19.0.0 or later from 18.1.0 or earlier, please see our migration guide.

Prerequisites

This implementation guide assumes you are familiar with the following:

Import the AFS Native SDK

Add the SDK

To add the AFS Native SDK to your app, do the following:

Open the build.gradle file inside your application module directory. Add a new build rule under dependencies for the latest version of the SDK:

dependencies {
  implementation 'com.google.android.gms:play-services-afs-native:19.1.0'
}

Ensure that your top-level build.gradle contains a reference to the google() repo or to maven { url "https://maven.google.com" }.

Follow these instructions to include the Google Play Standalone Version Matcher Plugin in your project. Applying this plugin causes a gradle build error when the AFS Native SDK is used with an incompatible version of Google Play Services instead of allowing the app to build but potentially causing runtime crashes. Or, apply the failOnVersionConflict() ResolutionStrategy to your project to cause a build error when incompatible versions of Google Play Services are used in your project. Save the changes and click Sync Project with Gradle Files in the toolbar.

Use AndroidX instead of Android Support Libraries

Starting with version 17.0.0 of the SDK, your app must use Jetpack (AndroidX) Libraries instead of Android Support Libraries. Compatibility requirements:

  • Set com.android.tools.build:gradle to v3.2.1 or later.
  • Set compileSdkVersion to 28 or later.
  • Update your app to use Jetpack (AndroidX); follow the instructions in Migrating to AndroidX.

Classes

To serve AFS native ads in your app, implement the following classes:

SearchAdController

  • This class is responsible for asynchronously requesting ads, caching and retrieving ads, and rendering ads.
  • Each ad context needs a separate SearchAdController; for example, if you have a screen which shows ads alongside a list of search results and another screen which shows ads alongside details for a specific product, you should create two separate instances of SearchAdController, one for each case.
  • The constructor needs to be provided your web property code (publisher id), style ID to apply to returned ads, and SearchAdOptions. The Context provided in the constructor must be the Activity which contains the SearchAdController and where you will place the ad View.
  • Call loadAds to indicate a new user search and initiate an asynchronous ad request. Any ads loaded from previous calls to loadAds are cleared from the internal ad cache when a new call is made.
  • Create a View with createAdView to display ad creatives.
  • Once ads have loaded, call populateAdView with a View previously generated with createAdView to render a cached ad into that View. In addition to the View which is to be populated, provide an adKey, an arbitrary string to uniquely identify the ad. This associates the specific ad creative returned from the cache with that adKey, so when the same adKey is passed to a future call to populateAdView, the same ad will be returned. For example, if populateAdView is called for the first time with adKey="keyA" and renders an ad for hiking boots, each subsequent call to populateAdView with adKey="keyA" will populate the same ad for hiking boots. (Making a new call to loadAds clears all cached ads and associated ad keys.)

SearchAdOptions

  • Pass this object to the SearchAdController constructor to customize how ads are requested and displayed. Call build() on a SearchAdOptions.Builder to create a SearchAdOptions object.

View

  • Create a View object to hold ads by calling createAdView() on the SearchAdController. Displays at most one ad at a time, but the same View can be recycled to display different ads over time.

SearchAdRequest

  • Call the loadAds method on the SearchAdController with a SearchAdRequest to initiate an asynchronous ad request. Call build() on a SearchAdRequest.Builder to create a SearchAdRequest object.

AdListener

  • Implement this interface and pass it to the SearchAdController constructor to register callbacks for several states.
  • Note: AdListener callbacks will not be called on a canceled request (a call to loadAds that was preempted by another call to loadAds before the first call resolved).

Example implementation

The example below demonstrates creating a SearchAdController in a sample Activity.

//  MainActivity.java implementation
//  (MainActivity is a subclass of Activity)

SearchAdController adController;
// adContainer where we will place our ads in this example.
ViewGroup adContainer;

protected void onCreate(Bundle bundle){
  super.onCreate(bundle);
  adContainer = (ViewGroup) findViewById(...);
  // Specify ad options (not required).
  SearchAdOptions.Builder adOptionsBuilder = new SearchAdOptions.Builder();
  adOptionsBuilder.setAdType(SearchAdOptions.AD_TYPE_TEXT);
  adOptionsBuilder.setPrefetch(true);
  adOptionsBuilder.setNumAdsRequested(3);
  // Provide a callback to trigger when ads are loaded.
  AdListener adListener = new AdListener() {
    public void onAdLoaded() {
      createAndShowAd();
    }
  };
  // Instantiate the SearchAdController.
  adController = new SearchAdController(this, "your-client-id", "your-style-id",
                                        adOptionsBuilder.build(), adListener);
}

When the user initiates a query, create a SearchAdRequest and call loadAds on the SearchAdController to start an asynchronous ad request.

// Create the request.
SearchAdRequest.Builder requestBuilder = new SearchAdRequest.Builder();
requestBuilder.setQuery("user query here");
// Load the ads.
adController.loadAds(requestBuilder.build());

Implement your onAdLoaded callback to populate a loaded ad into an ad view.

private void createAndShowAd() {
  // Create a new view that will contain the ad.
  View adView = adController.createAdView();
  // Attach the new view to the view hierarchy.
  adContainer.addView(adView);
  // Display the ad inside the adView. We need to provide an adKey to
  // indicate which ad is to be displayed in the adView. In this example, 
  // since we only have one ad, we can provide any constant string. However, 
  // if you intend to display multiple ads, each ad you wish to display
  // should be given a unique adKey of your choosing.
  adController.populateAdView(adView, "demoAd");
}

An ad related to the given query will now appear in the adView.

Investigating errors

The SearchAdController requires an AdListener object with the onAdLoaded() method to notify your app that ads are ready to display. You should also implement the onAdFailedToLoad() method so you can detect and correct errors. For example, you might use the following AdListener to debug your implementation:

AdListener adListener = new AdListener() {
    public void onAdLoaded() {
        // Called when an ad is loaded.
        Toast.makeText(MainActivity.this, "Ad Loaded",
                Toast.LENGTH_SHORT).show();
        Log.d(MainActivity.class.getSimpleName(), "Ad Loaded");
    }

    public void onAdLeftApplication() {
        // Called when an ad leaves the application
        // (to go to the browser for example).
        Toast.makeText(MainActivity.this, "Ad Left Application",
                Toast.LENGTH_SHORT).show();
        Log.d(MainActivity.class.getSimpleName(), "Ad Left Application");
    }

    @Override
    public void onAdFailedToLoad(int errorCode) {
        // Called when an ad request failed.
        Toast.makeText(MainActivity.this, "Ad Failed to Load: " + errorCode,
                Toast.LENGTH_SHORT).show();
        Log.e(MainActivity.class.getSimpleName(), "Ad Failed to Load: " +
                errorCode);
    }
};

Constants used in the onAdFailedToLoad() callback method are defined in the AdListener.