Задача: добавить встроенные покупки в Android приложение. Использовать google in-app billing v3 для реализации одноразовых платежей и подписок.
Монетизация через In-app purchases
Бесплатные приложения позволяют получить больше установок, что логично. Но как в таком случае монетизировать программу, не считая рекламу внутри приложения? Android позволяет проводить микротранзакции внутри приложения. Это могут быть как единоразовые платежи, так и подписки.
Единоразовые платежи в Android приложении
Для реализации таких платежей, необходимо в Google play консоли разработчика создать покупку. Это делается в секции «Ограниченный контент» на странице приложения.
Внутри раздела вы создаете тот «предмет», который можно будет купить в вашем приложении. Необходимо указать идентификатор, имя, описание и цену. Всю эту информацию пользователь увидит в интерфейсе Google play во всплывающем окне подтверждения оплаты.
Подписки в Android приложении
С подписками примерно тоже самое. За исключением того, что секция «цены» содержит дополнительные поля.
Тут необходимо указать также
- Расчетный период — раз в какое время будет происходить оплата
- Бесплатный пробный период — если хотите дать пользователю попробовать функционал в течении нескольких дней
- Начальная цена — тут можно задать льготную цены для новых подписчиков
- Льготный период — сколько есть времени у пользователя, чтобы устранить ошибку с оплатой если таковая имеется, перед тем, как подписка автоматически отменится.
Библиотеки для внедрения покупок в приложение
Можно реализовать покупки внутри приложения, используя напрямую инструменты, предоставленные Гуглом.
Я же предпочитаю использовать стороннюю, зарекомендовавшую себя библиотеку https://github.com/anjlab/android-inapp-billing-v3. Она предоставляет субъективно более дружественный интерфейс к API оплаты от Google.
Инициализация BillingProcessor
Первым делом необходимо инициализировать внутренний процессор и проверить, поддерживаются ли покупки устройством.
mBillingProcessor = new BillingProcessor(this, GPLAY_LICENSE, this);
boolean isAvailable = BillingProcessor.isIabServiceAvailable(this);
if (!isAvailable) {
mProgress.setVisibility(View.GONE);
showMsg(getString(R.string.billing_not_available));
} else {
mBillingProcessor.initialize();
}
Как только процессор подгрузился можно загрузить купленные продукты.
@Override
public void onBillingInitialized() {
/*
* Called when BillingProcessor was initialized and it's ready to purchase
*/
showMsg("onBillingInitialized");
if (mBillingProcessor.loadOwnedPurchasesFromGoogle()) {
handleLoadedItems();
}
}
Восстановление купленных продуктов
После успешной загрузки, библиотека может выдать список уже приобретенных товаров если он доступен в кэше. Также внутри доступна информация о каждом продукте. Например локальная цена в правильной валюте.
К тому же, если например кэш еще не готов, в программу придет асинхронный вызов, что история покупок была восстановлена.
@Override
public void onPurchaseHistoryRestored() {
/*
* Called when purchase history was restored and the list of all owned PRODUCT ID's
* was loaded from Google Play
*/
showMsg("onPurchaseHistoryRestored");
handleLoadedItems();
}
Так или иначе мы получаем список ранее купленных вещей в нашем Android приложении. Давайте его обработаем и покажем в UI.
private void handleLoadedItems() {
mProgress.setVisibility(View.GONE);
boolean isOneTimePurchaseSupported = mBillingProcessor.isOneTimePurchaseSupported();
if (isOneTimePurchaseSupported) {
mSingleTimePaymentButton.setVisibility(View.VISIBLE);
mConsumabelButton.setVisibility(View.VISIBLE);
} else {
showMsg(getString(R.string.one_time_payment_not_supported));
}
boolean isSubsUpdateSupported = mBillingProcessor.isSubscriptionUpdateSupported();
if (isSubsUpdateSupported) {
mSubscriptionButton.setVisibility(View.VISIBLE);
} else {
showMsg(getString(R.string.subscription_not_supported));
}
setupConsumableButtons(mBillingProcessor.listOwnedProducts().contains(ONE_TIME_PAYMENT));
setupSubscription(mBillingProcessor.listOwnedSubscriptions().contains(SUBSCRIPTION));
}
private void setupConsumableButtons(boolean isPurchased) {
mConsumabelButton.setEnabled(isPurchased);
mSingleTimePaymentButton.setEnabled(!isPurchased);
if (isPurchased) {
mSingleTimePaymentButton.setText(R.string.already_bought);
mConsumabelButton.setText(R.string.consume_one_time);
} else {
SkuDetails details = mBillingProcessor.getPurchaseListingDetails(ONE_TIME_PAYMENT);
mSingleTimePaymentButton.setText(getString(R.string.one_time_payment_value, details.priceText));
mConsumabelButton.setText(R.string.not_bought_yet);
}
}
private void setupSubscription(boolean isPurchased) {
mSubscriptionButton.setEnabled(!isPurchased);
if (isPurchased) {
mSubscriptionButton.setText(R.string.already_subscribed);
} else {
SkuDetails details = mBillingProcessor.getSubscriptionListingDetails(SUBSCRIPTION);
mSubscriptionButton.setText(getString(R.string.subscription_value, details.priceText));
}
}
Обработка успешной покупки внутри приложения
Результат о совершенной покупки приходит асинхронно. Нам остается только его обработать и «выдать» цифровой товар пользователю.
Важно: существуют способы обмануть серверы google что покупка успешно состоялась, но на самом деле никакой оплаты не было. Например, есть программы, которые выступают прослойкой и эмулируют успешный ответ. Правильный способ этого избежать — проверять покупки на своем доверенном сервере. Общение server-server намного сложнее подделать, потому что у злоумышленника нет доступа к вашему ресурсу. Как реализовать такую проверку рассказывали на stackoverflow. Также есть уже готовые библиотеки. Например вот одна из них.
В данном примере мы опустим проверку и будем предполагать, что покупка корректная.
@Override
public void onProductPurchased(String productId, TransactionDetails details) {
/*
* Called when requested PRODUCT ID was successfully purchased
*/
showMsg("onProductPurchased");
if (checkIfPurchaseIsValid(details.purchaseInfo)) {
showMsg("purchase: " + productId + " COMPLETED");
switch (productId) {
case ONE_TIME_PAYMENT:
setupConsumableButtons(true);
break;
case SUBSCRIPTION:
setupSubscription(true);
break;
}
} else {
showMsg("fakePayment");
}
}
Тестирование внутренних покупок в Android приложении
Есть 2 способа, с помощью которых можно тестировать встроенные покупки.
Тестирование покупок с помощью статических ответов
Еще до публикации приложения можно использовать тестовые ID покупок, чтобы получать те или иные ответы.
- android.test.purchased
- android.test.canceled
- android.test.item_unavailable
Тестирование покупок с реальными даннымиэ
Куда удобнее проверить, что именно ваши конкретные товары работают правильно. Что ID корректно прописаны, данные корректно приходят. Для этого необходимо опубликовать ваше приложение хотя бы в канале для внутреннего тестирования.
Когда вы сами у себя тестировщик и скачиваете приложение через Google play — все ваши внутренние покупки будут корректно приходить. При этом ничего платить не надо. Гугл предоставляет «тестовые карточки» прямо в своем интерфейсе. Вы сможете проверить как отрабатывает ваше приложение при успешном ответе или отказе.
Реализованный пример покупок внутри приложения с in-app billing v3
Пример можно скачать и посмотреть в Google play





