Android In-app purchasing: paid disconnection of ads in your application

Many times they have already asked to write an article on how to implement paid advertising shutdown in the application. On In-app there were already articles on Habr. True, they considered the old version of the API. In principle, the new version is not very different from the old one. There was a similar article, but it was more about advertising display that was discussed there, but we did not see the second part of the article. As it turned out, many people are still interested in this issue, I decided to write how to implement it in my application.

In-app purchase is a service for buying virtual goods inside the application (for example, game currency, new levels, etc.). It is used mainly in games, in cases where the question arises of the need to earn money on your creation.

This article will discuss how you can use In-App Purchase to disable ads in your application .

In-app advertising


In principle, you can take any site. Take for example AdMob. For convenience, I usually stuff these things in wrappers so that when changing the site, if necessary, I would not have to change anything. Wrappers for the advertising platform should implement the interface:
public interface AdsControllerBase {
        public void createView( RelativeLayout layout);
        public void show(boolean show);
        public void onStart();
        public void onDestroy();
        public void onResume();
        public void onStop();
}


Then the wrapper for AdMob will look something like this:
Wrapper for admob
public class AdMobController implements AdsControllerBase, AdListener {
	private static final String ADMOB_ID = "ваш_идентификатор_из_AdMob";
	private static final int REQUEST_TIMEOUT = 30000;
	private AdView adView;
	private Context c;
	private long last;
	public AdMobController(Context activity, RelativeLayout layout) {
		this.c = activity;
		createView(layout);
		last = System.currentTimeMillis() - REQUEST_TIMEOUT;
	}
	public void createView(RelativeLayout layout) {
		if(PreferencesHelper.isAdsDisabled()) return;
		adView = new AdView((Activity) c, AdSize.BANNER, ADMOB_ID);
		RelativeLayout.LayoutParams adParams = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT,
				RelativeLayout.LayoutParams.WRAP_CONTENT);
		adParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		adParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
		adView.setAdListener(this);
		layout.addView(adView, adParams);
		adView.loadAd(new AdRequest()); 
	}
	// обновляем рекламу не чаще, чем раз в 30 секунд
	public void show(boolean show) {
		if(adView == null) return;	
		adView.setVisibility((show) ? View.VISIBLE : View.GONE);
		if (show && (System.currentTimeMillis() - last > REQUEST_TIMEOUT)) {
			last = System.currentTimeMillis();
			adView.loadAd(new AdRequest());
		}
	}
	@Override
	public void onReceiveAd(Ad ad) {}
	@Override
	public void onFailedToReceiveAd(Ad ad, AdRequest.ErrorCode error) {}
	@Override
	public void onPresentScreen(Ad ad) {}
	@Override
	public void onDismissScreen(Ad ad) {}
	@Override
	public void onLeaveApplication(Ad ad) {}
	@Override
	public void onStart() {}
	@Override
	public void onDestroy() {}
	@Override
	public void onResume() {}
	@Override
	public void onStop() {}
}



Then the initialization of the advertisement will be as follows:
AdsControllerBase ads = new AdMobController(this, layout);


With this implementation, if the site changes, we simply create an instance of another class. For work you need only application_ID. which you will receive after creating the application in the Admob admin area.

In-app purchasing or internal payments in applications


In order to work with the shopping system, the IMarketBillingService.aidl file is required. It lies in the / user / android-sdk-linux / extras / google / play_billing directory with the SDK. You need to put the file in com.android.vending.billing package of your application.

You can read about types of purchases here. We are interested in recoverable purchases, that is, those that are tied to the account and can no longer be bought again. If you delete the application and decide again, the purchase will be restored. In our case, after the purchase of disconnecting advertising, advertising will no longer bother the user. This also applies to other devices: if a user logs in to another device under his account, the application will be restored to the application and advertising will be disabled.

To work, you need to add permission to AndroidManifest.xml:


The official documentation and an example from the SDK help a lot.

It is necessary to determine the key in the application - PublicKey, obtained when registering an account on the Android Market.
We define IabHelperand initialize. If successful, then try to restore purchases.

// id вашей покупки из админки в Google Play
static final String SKU_ADS_DISABLE = "com.ads.disable";
IabHelper mHelper;
private void billingInit() {
		mHelper = new IabHelper(this, BASE64_PUBLIC_KEY);
		// включаем дебагинг (в релизной версии ОБЯЗАТЕЛЬНО выставьте в false)
		mHelper.enableDebugLogging(true);
		// инициализируем; запрос асинхронен 
		// будет вызван, когда инициализация завершится
		mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
			public void onIabSetupFinished(IabResult result) {
				if (!result.isSuccess()) {
					return;
				}
				// чекаем уже купленное
				mHelper. queryInventoryAsync(mGotInventoryListener);
			}
		});
	}


mGotInventoryListener - listener to restore purchases.
// Слушатель для востановителя покупок.
	IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
		private static final String TAG = "QueryInventoryFinishedListener";
		public void onQueryInventoryFinished(IabResult result,
				Inventory inventory) {
			LOG.d(TAG, "Query inventory finished.");
			if (result.isFailure()) {
				LOG.d(TAG, "Failed to query inventory: " + result);
				return;
			}
			LOG.d(TAG, "Query inventory was successful.");
			/*
			 * Проверяются покупки. 
			 * Обратите внимание, что надо проверить каждую покупку, чтобы убедиться, что всё норм! 
			 * см. verifyDeveloperPayload().
			 */
			Purchase purchase = inventory.getPurchase(SKU_ADS_DISABLE);
			PreferencesHelper.savePurchase(
							context,
					PreferencesHelper.Purchase.DISABLE_ADS,
							purchase != null && verifyDeveloperPayload(purchase));
			ads.show(!PreferencesHelper.isAdsDisabled());
		}
	};

Now you need, in fact, to realize the purchase itself:

private void buy(){
		if(!PreferencesHelper.isAdsDisabled()){
			/* для безопасности сгенерьте payload для верификации. В данном примере просто пустая строка юзается.
			 * Но в реальном приложение подходить к этому шагу с умом. */
		    String payload = ""; 
			mHelper.launchPurchaseFlow(this, SKU_ADS_DISABLE, RC_REQUEST, 
		               mPurchaseFinishedListener, payload);
		}
	}


SKU_ADS_DISABLE - product identifier that you created in the Google Play admin panel. mPurchaseFinishedListener- listener:
// слушатель завершения покупки
	IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
		public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
			if (result.isFailure()) {
				return;
			}
			if (!verifyDeveloperPayload(purchase)) {
				return;
			}
			if (purchase.getSku().equals(SKU_ADS_DISABLE)) {
				Toast.makeText(getApplicationContext(), "Purchase for disabling ads done.", Toast.LENGTH_SHORT);
				// сохраняем в настройках, что отключили рекламу
				PreferencesHelper.savePurchase(
								context,
								PreferencesHelper.Purchase.DISABLE_ADS,
								true);
				// отключаем рекламу
				ads.show(!PreferencesHelper.isAdsDisabled());
			}
		}
	};

It is worth talking separately about the verification method:
boolean verifyDeveloperPayload(Purchase p) {
		String payload = p.getDeveloperPayload();
		/*
		 * TODO: здесь необходимо свою верификацию реализовать
		 * Хорошо бы ещё с использованием собственного стороннего сервера.
		 */
		return true;
	}


Right now there is no check of purchases, but in a real application you have to check the received data with the generated line that you sent in the purchase request. You need to check this on your third-party server. For a usually application or offline game this may not be critical, but for an online game it is very important.

In principle, everything, now when you run the application, a verification of the settings will take place (where we saved that we turned off advertising):
PreferencesHelper.loadSettings(this);

After which the advertisement will no longer be shown.

Shopping testing


Now it’s quite convenient to test your application. You can upload .apk as an alpha / beta version and publish. In this case, you can assign a group to Google+, which will be able to test. If you publish an alpha or beta version of the application, then it will not appear in the market, only this group will have access.


Testers will be able to make purchases. Money will be debited without commission and will be returned after 15 minutes after purchase. So don’t worry. But you won’t be able to test the application if your account on the device and the publisher’s account are the same = /

You can see a fully working example on the github .

Also popular now: