- Android in-app purchases, part 1: configuration and adding to the project
- Creating subscription
- Comparing the purchase process in Play Console and App Store Connect
- Getting a list of products in an app
- In-App Purchase в Android приложениях
- Android in-app purchases, часть 2: инициализация и обработка покупок
- Создание экрана с подписками
- Доработка кода для отображения информации о продуктах
- Запуск процесса покупки
- Про Adapty
Android in-app purchases, part 1: configuration and adding to the project
In-app purchases and especially subscriptions are the most popular methods to monetize an app. On the one hand, a subscription allows a developer to develop content and a product, on the other hand, they help a user to get a more high-quality app in general. In-app purchases are subject to 30% commission, but if a user has been subscribed for more than a year or an app earns less than $1Рњ per year, the commission is 15%.
This is the first article from the series dedicated to in-app purchases in Android apps. In this series, we will cover the topics starting with the creation of in-app purchases and up to server validation and analytics:
In this article, we’ll explain how to:В В
- Create a product in Google Play Console;
- Configure subscriptions: how to specify duration, price, trials;В
- Get a list of products in an app.В
Creating subscription
Before we start, make sure you:
- Have a developer account for Google Play.
- Have signed all agreements and are ready to start working.В В
Now, let’s get down to business and create our first product.В В
Switch to your developer account and choose an app.
Then, in the menu on the left, find the Products section, select Subscriptions and press Create a Subscription.В
Then, we’ll see the subscription configurator. Here are some important points.В В В
- Create the ID that will be used in the app. It’s a good idea to add a subscription period or some other useful information to ID, thus, you can create products in one style, as well as analyzing sales statistics will be easier.
- The name of the subscription that a user will see in the store.В В
- Subscription description. A user will see it, too.В В
Scroll down and choose the subscription period. In our case, it’s a week. Set up the price.В В
Usually, you set the price in the basic account currency, and the system converts the price automatically. But you can also edit the price for a specific country manually.В В
Please notice that Google shows the tax for every country. It’s great, App Store Connect doesn’t do so.В В
Scroll down and choose (if needed):В
- Free trial period.
- Introductory price, which is an offer for the first payment periods.В В
- Grace period. If a user has payment issues, you can still provide them with premium access for some number of days.
- An opportunity to resubscribe from the Play Store, not from the app, after cancellation.В
Comparing the purchase process in Play Console and App Store Connect
Regardless of the fact that subscriptions are monetized more effectively on iOS, Play Console’s admin board is more convenient, it’s organized and localized better, and it works faster.
The process of product creation is made as simple as possible. Here we told how to create products on iOS.
Getting a list of products in an app
Once the products are created, let’s work on the architecture for accepting and processing purchases. In general, the process looks like this:В В В
- Add a Billing Library.
- Develop a class for interaction with products from Google Play.
- Implement all methods to process purchases.В В
- Add server validation of a purchase.В В
- Collect analytics.
In this part, let’s take a closer look at the first two points.В В
Adding Billing Library to a project:
At the time of this writing, the latest version is 4.0.0. You can replace it with any other version at any moment.В В
Let’s create a wrapper class that will cover the logic of interaction with Google Play and initialize BillingClient from Billing Library in it. Let’s call this class BillingClientWrapper.
This class will implement PurchasesUpdatedListener interface. We will override a method for it now – onPurchasesUpdated(billingResult: BillingResult, purchaseList: MutableList
?) – it’s needed right after a purchase is made, but we will describe the implementation process in the next article.В
Google recommends to avoid having more than one active connection between BillingClient and Google Play to prevent a callback about a purchase made from being executed several times. Thus, you should have one unique BillingClient in a singleton class. The class in the example isn’t a singleton, but we can use dependency injection (for example, with the help of Dagger or Koin) in the way, allowing only one instance to exist at a single point in time.В
To make any request with Billing Library, BillingClient must have an active connection with Google Play at the moment when the request is being made, but the connection may be lost at some moment. For the sake of convenience, let’s write a wrapper allowing to make any requests only when the connection is active.В В В
To get the products, we need their IDs that we set in the market. But it’s not enough for a request, we also need the product type (subscriptions or one-time purchases) that’s why we can get a general list of products by “combining” the results of two requests.В В В
The request for products is asynchronous, so we need a callback that will either provide us with a list of products or return an error model. When an error occurs, Billing Library returns one of its BillingResponseCodes, as well as debugMessage. Let’s create callback interface and a model for an error:В В
Here’s a code for a private method for getting data about a specific type of products and a public method that will “combine” the results of two requests and provide a user with the final list of products or display an error message.В В
Thus, we got valuable information about the products (SkuDetails) where we can see localized names, prices, product type, as well as billing period and information about introductory price and trial period (if it’s available for this user) for subscriptions. Here’s what the final class looks like:В В В
That’s all for today. In the next articles, we’re going to tell you about purchase implementation, testing, and error handling.В В
Источник
In-App Purchase в Android приложениях
1. Что это такое и зачем это нужно?
In-App Purchase, грубо говоря, представляет собой сервис покупки виртуальных товаров внутри приложения (например игровой валюты, новых уровней, игровых предметов и т.д.). Применяется он в основном в играх, в тех случаях, когда встает вопрос о необходимости заработка на своем творении, а распространять его платно не особо хочется (или нет смысла).
2. In-App Purchase в андроид-приложениях
Когда я столкнулся с необходимостью использования in-app purchase в разрабатываемой игре, было очень трудно найти подробную русскоязычную информацию о том, как прикрутить данный сервис к своей игре. Наиболее хорошо сервис был описан в одной из статей Хабра, но мне бы хотелось показать свое видение по данному вопросу. Поэтому решил сам написать небольшой мануал по подключению сервиса к приложению.
Для начала неплохо было бы разобраться с тем, как это все работает.
В принципе, весь процесс функционирования довольно неплохо был описан в статье, на которую я сослался выше, так что повторять заново то же самое нет особого смысла. Поэтому, я перейду сразу к делу.
Предполагается, что у вас уже есть аккаунт разработчика на Android Market.
Для того, чтобы работать с системой покупок внутри приложения нам понадобится файл с названием IMarketBillingService.aidl. Найти его можно в примере приложения по работе с in-app purchase, который в свою очередь является скачиваемым компонентом Android SDK. Запустите Android SDK and AVD Manager и выберете Available Packages. Далее необходимо будет выбрать Third party add-ons -> Google Inc. add-ons -> Google Market Billing package.
Теперь необходимо из скаченного примера скопировать в свой проект файл IMarketBillingService.aidl. Важно, чтобы он лежал в com.android.vending.billing. После этого в манифесте добавляем расширение: .
В примере приложения кроме вышеописанного файла есть также несколько реализованных классов для работы с системой платежей. Копируем их в свой проект. Что собой представляет каждый из них:
BillingReceiver – получает все асинхронные ответы с маркета и отправляет их далее в BillingService;
BillingService – отправляет запросы на маркет;
Consts – содержит все константы примера приложения;
Dungeons – обеспечивает UI и отображает историю совершенных покупок;
PurchaseDatabase – локальная база данных;
PurchaseObserver – наблюдение за изменениями, связанными с покупками;
ResponseHandler – обновление базы данных и UI;
Security – обеспечение безопасности;
Base64 и Base64DecoderException – кодирование из двоичной системы в base64. Необходимы для функционирования класса Security.
В классе Security ищем строку:
String base64EncodedPublicKey = “…”
и вписываем сюда свой PublicKey, полученный при регистрации аккаунта на Android Market.
В классе Dungeons ищем список товаров, которые предполагается продавать, и меняем их на свои. При этом, товары должны быть залиты в Android Market и опубликованы (само приложение при этом публиковать не обязательно – в случае его тестирования, однако надо не забыть добавить себя (или кого-то другого) в разработчики (делается в настройках профиля)). Далее дописываем интерфейс и в принципе приложение готово.
Однако стоит позаботиться о безопасности. Лучший способ обеспечения безопасности покупок – использование соответствующего сервиса на сервере. После того, как пользователь совершил покупку товара, маркет пришлет JSON строку с информацией о купленном товаре:
< "nonce" : 1836535032137741465,
«orders» :
< "notificationId" : "android.test.purchased",
«orderId» : «transactionId.android.test.purchased»,
«packageName» : «com.example.dungeons»,
«productId» : «android.test.purchased»,
«developerPayload» : «bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ»,
«purchaseTime» : 1290114783411,
«purchaseState» : 0 >
>
и подпись для проверки подлинности запроса.
На серверной части приложения нужно выполнить проверку вернувшейся строки с помощью подписи и вашего ключа (шифрование RSA) и вернуть результат проверки клиенту. Для этого есть небольшая открытая библиотека, написанная на php, я использовал ее.
Более подробно о безопасности при работе с in-app purchase написано тут.
Источник
Android in-app purchases, часть 2: инициализация и обработка покупок
Это вторая статья из нашего цикла о реализации покупок на Android. В первой статье мы рассказывали о том, как создавать продукты в Google Play Console, сконфигурировать подписки и получить список продуктов в приложении. Cоветую познакомиться и с остальными:
Android in-app purchases, часть 2: инициализация и обработка покупок. — Вы тут
В прошлой части мы создали класс-обертку для работы с Billing Library:
Класс-обертка для работы с Billing Library
Перейдем дальше к реализации покупки и дополним наш класс.
Создание экрана с подписками
В любом приложении, которое использует встроенные покупки, присутствует пейволл. Есть требования от Google, которые определяют минимальный набор необходимых элементов и поясняющих текстов для подобных экранов. Если коротко, на пейволле вы должны прозрачно показать пользователю условия, цену и длительность подписки и обязательна ли подписка для использования приложения. Нельзя принуждать пользователя к дополнительным действиям ради получения информации об условиях подписки.
На данном этапе для примера мы сделали упрощённый вариант пейволла:
Итак, на нашем пейволле располагаются следующие элементы:
Набор кнопок для инициализации процесса покупки. На них указаны основные свойства продуктов: название и цена в местной валюте.
Кнопка восстановления прошлых покупок. Этот элемент необходим для всех приложений, в которых используются подписки либо non-consumable покупки.
Доработка кода для отображения информации о продуктах
В нашем примере четыре продукта:
две автовозобновляемые подписки («premium_sub_month» и «premium_sub_year»);
продукт, который нельзя купить повторно, — non-consumable (“unlock_feature”);
продукт, который можно покупать много раз, — consumable (“coin_pack_large”).
Для упрощения примера будем использовать Activity, в которую заинжектим BillingClientWrapper из предыдущей статьи, и layout с жестко заданным количеством кнопок для покупки.
Для удобства добавим словарь, где ключом является sku продукта, а значением — соответствующая кнопка на экране.
Объявим метод для отображения продуктов в UI, опираясь на логику из предыдущей статьи:
product.price — это уже отформатированная строка с указанием местной валюты для данного аккаунта, здесь никакое дополнительное форматирование не нужно; остальные поля в объекте класса SkuDetails также приходят уже с учетом локализации.
Запуск процесса покупки
Для проведения покупки необходимо вызвать метод launchBillingFlow() из главного потока приложения.
Добавим для этого метод purchase() в BillingClientWrapper :
У метода launchBillingFlow() нет колбэка, ответ вернется в метод onPurchasesUpdated() . Помните, мы в прошлой статье его объявили, но оставили на потом? Вот сейчас он нам понадобится.
Метод onPurchasesUpdated() вызывается при каком-либо результате после взаимодействия пользователя с диалогом покупки. Это может быть успешная покупка, отмена покупки (пользователь закрыл диалог, в этом случае приходит код BillingResponseCode.USER_CANCELED) или же какая-то другая ошибка.
По аналогии с интерфейсом OnQueryProductsListener из предыдущей статьи, объявим в классе BillingClientWrapper интерфейс OnPurchaseListener , с помощью которого будем получать либо покупку (объект класса Purchase — о кейсе, когда он может быть null даже в случае успеха, расскажем в следующей статье), либо ошибку, которую мы также объявляли в предыдущей статье:
И реализуем его в PaywallActivity:
Добавим логику в onPurchaseUpdated():
Если purchaseList не пустой, для начала для каждой покупки делаем проверку, что ее purchasedState равен PurchaseState.PURCHASED, потому что покупки также могут быть отложенными, и в этом случае флоу на данном этапе прекращается. Далее, согласно документации, нужно сделать серверную верификацию покупки, о ней мы расскажем в следующих статьях. После этого надо предоставить пользователю доступ к контенту и сообщить об этом в Google. Если не сообщить, то через три дня покупка автоматически отменится. Интересно, что это характерно только для Google Play, в то время как на iOS такого нет. Сообщить о предоставлении доступа к контенту можно двумя способами:
В случае с consumable-продуктом вместо него нужно вызвать метод consumeAsync() , который под капотом делает acknowledge, а заодно дает возможность покупать этот продукт повторно. Это можно сделать только с помощью Billing Library: Google Play Developer API почему-то не предоставляет возможность делать это на бэкенде. Любопытно, что, в отличие от Google Play, в App Store и в AppGallery свойство consumable за продуктом жестко определено на уровне App Store Connect и AppGallery Connect соответственно. Справедливости ради, замечу, что консьюмить такие продукты из AppGallery нужно всё-таки явно.
Напишем методы для acknowledge и consume, а также две версии метода processPurchase() — в случае, когда у нас есть свой бэкенд и когда его нет.
Без серверной верификации:
С серверной верификацией:
Подробнее о серверной верификации покупок мы расскажем в одной из следующих статей.
Во втором примере acknowledge, конечно, тоже можно было сделать на клиенте, но так как здесь у нас есть бэкенд, всё, что можно сделать на бэке, лучше отдать бэку. Что касается ошибок на acknowledge и consume, их нельзя игнорировать, потому что если ни одно из этих действий не произойдет в течение трёх дней после того, как покупка получила статус PurchaseState.PURCHASED, она отменится, а пользователю вернут средства. Поэтому, если мы не можем это сделать на бэкенде, и даже после нескольких повторных попыток всё еще получаем ошибку, самый надежный способ — получать текущие покупки пользователя в каком-нибудь методе жизненного цикла, например в onStart() или onResume(), и пытаться повторить в надежде, что пользователь в течение трёх дней зайдет в наше приложение при работающем интернете :).
Таким образом, текущая версия класса BillingClientWrapper будет выглядеть так:
Вы могли задаться вопросом, почему кнопки активны для всех продуктов, независимо от того, покупал их пользователь или нет. Или что будет, если купить обе подписки: заменит ли вторая первую или они обе будут сосуществовать. Всё это в следующих статьях 🙂
Про Adapty
Он не только упрощает работу по добавлению покупок:
Встроенная аналитика позволяет быстро понять основные метрики приложения.
Когортный анализ отвечает на вопрос, как быстро сходится экономика.
А/Б тесты увеличивают выручку приложения.
Интеграции с внешними системами позволяют отправлять транзакции в сервисы атрибуции и продуктовой аналитики.
Промо-кампании уменьшают отток аудитории.
Open source SDK позволяет интегрировать подписки в приложение за несколько часов.
Серверная валидация и API для работы с другими платформами.
Познакомьтесь подробнее с этими возможностями, чтобы быстрее внедрить подписки в своё приложение и улучшить конверсии.
Источник