In-App Purchase Ads

In-App Purchase (IAP) ads allow users to make purchases directly within your apps.

This guide explains the code changes to your app required to serve IAP ads into interstitial slots, but does not discuss other required steps such as how to configure your purchase items in your Google Play and AdMob accounts.

See the In-app purchase (IAP) house ads implementation guide for additional information.

Prerequisite

Add InAppPurchaseActivity and billing permission to AndroidManifest.xml

IAP ads require an additional Activity in AndroidManifest.xml:

<activity android:name="com.google.android.gms.ads.purchase.InAppPurchaseActivity"
          android:theme="@style/Theme.IAPTheme"/>

as well as the com.android.vending.BILLING permission:

<uses-permission android:name="com.android.vending.BILLING" />

PlayStorePurchaseListener vs. InAppPurchaseListener

There are two different ways you can implement IAP ads in your app:

We recommend that beginners use the PlayStorePurchaseListener. When using PlayStorePurchaseListener, the entire Google Play billing flow is implemented for you in the Mobile Ads SDK. You only need to credit the user for purchased goods. Note that one limitation of PlayStorePurchaseListener is it can only be used with consumable products.

Implementing InAppPurchaseListener is recommended for developers who already have an in-app billing implementation. When using InAppPurchaseListener, the Mobile Ads SDK just notifies you that a user is interested in purchasing a particular product. It is up to you to complete the in-app billing process yourself and report the result back to the Mobile Ads SDK. The advantage of implementing InAppPurchaseListener is that you can implement IAP ads for both consumable and non-consumable products, but it involves writing a lot of new code if your app doesn't already use in-app billing.

PlayStorePurchaseListener

In order to serve IAP ads, you'll need to implement PlayStorePurchaseListener:

public interface PlayStorePurchaseListener {
    boolean isValidPurchase(String productId);
    void onInAppPurchaseFinished(InAppPurchaseResult inAppPurchaseResult);
}

isValidPurchase

The isValidPurchase method allows you to verify that the purchase for this item is valid. Returning false here cancels the purchase process:

@Override
public boolean isValidPurchase(String sku) {
  // Optional: check if the product has already been purchased.
  try {
    if (getOwnedProducts().contains(sku)) {
      // Handle the case if product is already purchased.
      return false;
    }
  } catch (RemoteException e) {
    return false;
  }
  return true;
}

onInAppPurchaseFinished

The onInAppPurchaseFinished method is called when the user completes the purchase. In this method, you are responsible for crediting the user and calling InAppPurchaseResult.finishPurchase() to consume the product:

@Override
public void onInAppPurchaseFinished(InAppPurchaseResult result) {
  int resultCode = result.getResultCode();
  if (resultCode == Activity.RESULT_OK) {
    // Credit the user with goods.

    // Call finishPurchase() to consume the product.
    result.finishPurchase();
  }
}

Register PlayStorePurchaseListener on an interstitial

When creating an interstitial ad, you must call InterstitialAd.setPlayStorePurchaseParams to register the PlayStorePurchaseListener with this interstitial. The setPlayStorePurchaseParams method also accepts your Android app's public key for optional verification.

Here is an example showing how to set the PlayStorePurchaseListener:

interstitialAd = new InterstitialAd(this);
private String base64PublicKey = "MIIBIjANBgkqhkiG ... "; // truncated for this example
// Assumes "this" activity implemented PlayStorePurchaseListener.
interstitialAd.setPlayStorePurchaseParams(this, base64PublicKey);

Complete code example

To download a complete example, click the button below.

Download Example

MainActivity.java

package admob.demo.iap.defaultpurchase;

import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;
import com.google.android.gms.ads.purchase.InAppPurchaseResult;
import com.google.android.gms.ads.purchase.PlayStorePurchaseListener;

import android.app.Activity;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.android.vending.billing.IInAppBillingService;

import java.util.Collections;
import java.util.List;

public class MainActivity extends Activity implements PlayStorePurchaseListener {

  public static final int BILLING_RESPONSE_RESULT_OK = 0;

  private InterstitialAd interstitial;
  private IInAppBillingService mService;
  private Button showAdButton;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    showAdButton = (Button) findViewById(R.id.showAd);
    showAdButton.setEnabled(false);

    // Create the interstitial ad and set Google Play store purchase parameters.
    interstitial = new InterstitialAd(this);
    // No need to set a public key for IAP ads.
    interstitial.setPlayStorePurchaseParams(this, null);

    // Put your ad unit ID here, e.g., "ca-app-pub-2412876219430673/4729615340"
    interstitial.setAdUnitId();

    setInterstitialAdListener();
  }

  private void setInterstitialAdListener() {
    // Set an AdListener.
    interstitial.setAdListener(new AdListener() {
      @Override
      public void onAdLoaded() {
        showAdButton.setEnabled(true);
      }

      @Override
      public void onAdClosed() {
        showAdButton.setEnabled(false);
        // Optional: your custom code here.
      }
    });
  }

  public void loadInterstitial(View v) {
    // Create ad request.
    AdRequest adRequest = new AdRequest.Builder().build();

    // Begin loading interstitial ad.
    interstitial.loadAd(adRequest);
  }

  public void displayInterstitial(View v) {
    if (interstitial.isLoaded()) {
      interstitial.show();
    }
  }

  @Override
  public boolean isValidPurchase(String sku) {
    // Optional: check if the product has already been purchased.
    try {
      if (getOwnedProducts().contains(sku)) {
        // Handle the case if product is already purchased.
        return false;
      }
    } catch (RemoteException e) {
      Log.e("Iap-Ad", "Query purchased product failed.", e);
      return false;
    }
    return true;
  }

  @Override
  public void onInAppPurchaseFinished(InAppPurchaseResult result) {
    Log.i("Iap-Ad", "onInAppPurchaseFinished Start");
    int resultCode = result.getResultCode();
    Log.i("Iap-Ad", "result code: " + resultCode);
    String sku = result.getProductId();
    if (resultCode == Activity.RESULT_OK) {
      Log.i("Iap-Ad", "purchased product id: " + sku);
      int responseCode = result.getPurchaseData().getIntExtra(
          "RESPONSE_CODE", BILLING_RESPONSE_RESULT_OK);
      String purchaseData = result.getPurchaseData().getStringExtra("INAPP_PURCHASE_DATA");
      Log.i("Iap-Ad", "response code: " + responseCode);
      Log.i("Iap-Ad", "purchase data: " + purchaseData);

      // Finish purchase and consume product.
      result.finishPurchase();
      // if (responseCode == BILLING_RESPONSE_RESULT_OK) {
      // Optional: your custom process goes here, e.g., add coins after purchase.
      //  }
    } else {
      Log.w("Iap-Ad", "Failed to purchase product: " + sku);
    }
    Log.i("Iap-Ad", "onInAppPurchaseFinished End");
  }

  private List getOwnedProducts() throws RemoteException {
    // Query for purchased items.
    // See http://developer.android.com/google/play/billing/billing_reference.html and
    // http://developer.android.com/google/play/billing/billing_integrate.html
    Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
    int response = ownedItems.getInt("RESPONSE_CODE");
    Log.i("Iap-Ad", "Response code of purchased item query");
    if (response == 0) {
      return ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
    }
    return Collections.emptyList();
  }
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingBottom="@dimen/activity_vertical_margin"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                tools:context=".MainActivity" >
    <Button android:id="@+id/loadAd"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:onClick="loadInterstitial"
            android:text="LoadAds" />
    <Button android:id="@+id/showAd"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBaseline="@+id/loadAd"
            android:layout_alignBottom="@+id/loadAd"
            android:layout_centerHorizontal="true"
            android:onClick="displayInterstitial"
            android:text="ShowAds" />
</RelativeLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="admob.demo.iap.defaultpurchase"
    android:versionCode="2"
    android:versionName="0.2" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="com.android.vending.BILLING" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <activity
            android:name="admob.demo.iap.defaultpurchase.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.google.android.gms.ads.purchase.InAppPurchaseActivity"
            android:theme="@style/Theme.IAPTheme" />
        <activity
            android:name="com.google.android.gms.ads.AdActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
    </application>
</manifest>

InAppPurchaseListener

In order to serve IAP ads, you'll need to implement InAppPurchaseListener:

public interface InAppPurchaseListener {
    void onInAppPurchaseRequested(InAppPurchase inAppPurchase);
}

This interface has a single method, onInAppPurchaseRequested, which is called when the user indicates they want to purchase an item. Your app should start the in-app billing flow upon receiving this call. Check InAppPurchase.getProductId to see which product the user wishes to purchase.

Record the resolution

When the purchase flow has completed, you must record the result of the purchase:

The possible resolutions are:

Register InAppPurchaseListener on an interstitial

Once you've implemented the InAppPurchaseListener, you must set it on the interstitial in order for IAP ads to be eligible:

interstitialAd = new InterstitialAd(this);
// Assumes "this" activity implemented InAppPurchaseListener.
interstitialAd.setInAppPurchaseListener(this);

Send feedback about...

AdMob by Google
AdMob by Google