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
- Read the Interstitial Ads guide.
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:
- PlayStorePurchaseListener (recommended for beginners)
- InAppPurchaseListener (for advanced publishers)
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.
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:
- If using Google Play billing, call InAppPurchase.recordPlayBillingResolution.
- If using another billing service, call InAppPurchase.recordResolution.
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);