In app purchasing android

Android in-app purchases, часть 1: конфигурация и добавление в проект

Всем привет, меня зовут Влад и я разработчик Android SDK для обработки платежей в мобильных приложениях в Adapty.

Внутренние покупки и в частности подписки являются наиболее популярным способом монетизировать приложение. С одной стороны, подписка дает разработчику возможность постоянно развивать контент и продукт, с другой стороны, благодаря им пользователь получает более высокое качество приложения в целом. Внутренние покупки облагаются 30% комиссией, но если пользователь подписан больше года или приложение зарабатывает меньше $1М в год, то комиссия составляет 15%.

Это первая статья из серии, посвящённой работе с внутренними покупками на Android. В этой серии мы охватываем темы от создания in-app purchases до серверной верификации платежей:

Android in-app purchases часть 1: конфигурация и добавление в проект. — Вы тут

В этой статье мы разберём, как:

создавать продукты в Google Play Console;

конфигурировать подписки: указывать длительность, стоимость, пробные периоды;

получать список продуктов в приложении.

Создание подписки/покупки

Перед тем, как мы начнем, убедитесь, что

Вы подписали все соглашения и готовы работать.

Перейдем к делу, а именно создадим наш первый продукт.

Переходим в наш аккаунт разработчика и выбираем нужное приложение.

Дальше в левом меню ищем секцию Продукты, выбираем Подписки и жмем на Создать Подписку.

Дальше попадаем в конфигуратор подписки, разберем важные вещи.

Создаем ID, который потом используем в приложении. Хорошо, когда в ID мы кодируем период подписки и какую-то еще полезную информацию. Это позволяет создавать продукты в одном стиле, чтобы в будущем было проще анализировать статистику по покупкам.

Название подписки, как пользователь ее увидит в магазине.

Описание подписки, пользователь тоже это увидит.

Скроллим ниже и выбираем период подписки, в нашем случае это неделя, и конфигурируем стоимость.

Обычно вы задаете цену в базовой валюте аккаунта, а система автоматически переводит цены в разные валюты разных стран. Но вы также можете поправить цену в конкретной стране вручную.

Обратите внимание, что Google сразу указывает налог в каждой стране, это очень круто, а в App Store Connect такого нет.

Скроллим ниже и опционально выбираем:

Бесплатный пробный период.

Начальная цена. Промо-предложение на первые периоды оплаты.

«Льготный период». То есть, если у пользователя проблема с оплатой, сколько дней вы продолжаете давать ему премиум доступ.

Возможность подписаться заново из Play Market, а не из приложения, после отмены подписки.

Сравнение процесса покупки с App Store Connect

Несмотря на то, что подписки значительно лучше монетизируются на iOS, админка Play Console выглядит намного удобнее. Она работает быстрее, лучше и проще структурирована, качественно локализована.

Сам процесс создания продукта предельно упрощен. Здесь мы описали, как создавать продукты на iOS.

Получение списка продуктов в приложении

После создания продуктов перейдем к созданию архитектуры в приложении для приема и обработки покупок. В целом процесс следующий:

Подключаем платежную библиотеку.

Разрабатываем структуру класса для взаимодействия с продуктами из Google Play.

Реализуем все методы обработки покупки.

Подключаем серверную верификацию покупки.

В этой части разберем первые два пункта.

Подключим Billing Library к проекту:

На момент написания статьи актуальной версией является 4.0.0. Вы можете в любой момент заменить ее на другую версию.

Создадим класс-обертку, который будет инкапсулировать логику взаимодействия с Google Play, и проинициализируем в нем BillingClient из библиотеки Billing Library. Назовем такой класс BillingClientWrapper.

Наш класс будет реализовывать интерфейс PurchasesUpdatedListener. Мы сразу переопределим его метод onPurchasesUpdated(billingResult: BillingResult, purchaseList: MutableList

?) , который вызывается после совершения покупки, но саму реализацию опишем уже в следующей статье.

Google рекомендует, чтобы одновременно было не больше одного активного соединения BillingClient’а с Google Play, чтобы колбэк о совершенной покупке не вызывался несколько раз. Для этого целесообразно иметь единственный экземпляр BillingClient в классе-синглтоне. Класс в примере выше сам по себе синглтоном не является, но мы можем провайдить его с помощью dependency injection (например, используя Dagger или Koin) таким образом, чтобы в один момент времени существовало не больше одного экземпляра.

Для совершения любого запроса с помощью Billing Library нужно, чтобы у BillingClient’а в момент запроса было активное соединение с Google Play, но в какой-то момент оно может быть утеряно. Для удобства напишем обертку, чтобы любой запрос выполнялся только при активном соединении.

Читайте также:  Usb safely remove андроид

Чтобы получить продукты, нам нужно знать их идентификаторы, которые мы задавали в маркете. Но для запроса этого недостаточно, нужно указать еще и тип продуктов (подписки или разовые покупки), поэтому общий список продуктов мы можем получить только путем «склеивания» результатов двух запросов.

Так как запрос на продукты асинхронный, нам нужен колбэк, в котором мы получим либо список продуктов, либо ошибку. Billing Library при ошибке возвращает один из определенных в ней BillingResponseCode, а также debugMessage. Создадим интерфейс колбэка и модель для ошибки:

Напишем приватный метод для получения данных о продуктах конкретного типа, а также публичный метод, который «склеит» результаты от двух запросов и вернет итоговый список продуктов или ошибку.

Таким образом мы получили информацию о продуктах (SkuDetails), где есть локализованные названия, цены, тип продукта, а для подписок еще и период платежа, а также информация о начальной цене и пробном периоде (если доступно данному пользователю). Финальный класс выглядит так:

На этом все, в следующих статьях мы расскажем о реализации покупок, тестировании и обработке ошибок.

Про Adapty

Как видите, в процессе добавления покупок в приложения на Android много нюансов. Если использовать готовые библиотеки, всё будет проще. Советую познакомиться с Adapty — SDK для in-app покупок. Он не только упрощает работу по добавлению покупок:

Встроенная аналитика позволяет быстро понять основные метрики приложения.

Когортный анализ отвечает на вопрос, как быстро сходится экономика.

А/Б тесты увеличивают выручку приложения.

Интеграции с внешними системами позволяют отправлять транзакции в сервисы атрибуции и продуктовой аналитики.

Промо-кампании уменьшают отток аудитории.

Open source SDK позволяет интегрировать подписки в приложение за несколько часов.

Серверная валидация и API для работы с другими платформами.

Познакомьтесь подробнее с этими возможностями, чтобы быстрее внедрить подписки в своё приложение и улучшить конверсии.

Источник

Android In-app purchasing: платное отключение рекламы в своём приложении

Много раз уже просили написать статью о том, как в приложении реализовать платное отключение рекламы. По In-app уже были статьи на хабре. Правда, они старую версию API рассматривали. В принципе, новая версия не особо то и отличается от старой. Была похожая статья, но там больше именно про отображение рекламы рассказывалось, а второй части статьи мы так и не увидели. Как оказалось, многим до сих пор интересен этот вопрос, решил написать как это реализовать в своём приложении.

In-App Purchase представляет собой сервис покупки виртуальных товаров внутри приложения (например игровой валюты, новых уровней и т.д.). Применяется он в основном в играх, в тех случаях, когда встает вопрос о необходимости заработка на своем творении.

В данной статье рассмотрю как можно использовать In-App Purchase для отключения рекламы в своём приложении.

Реклама в приложении

В принципе, можно взять любую площадку. Возьмём, к примеру AdMob. Я для удобства обычно подобные вещи в обёртки запихиваю, чтобы при смене площадки, если потребуется, почти ничего не пришлось менять. Обёртки для рекламной площадки должны реализовывать интерфейс:

Тогда обёртка для AdMob будет выглядеть примерно так:

Тогда инициализация рекламы будет такой:

При такой реализации в случае смены площадки, мы просто создадим инстанс другого класса. Для работы вам нужен лишь ID_приложения. который получите после создания в приложения в админке Admob.

In-app purchasing или внутренние платежи в приложениях

Для того, чтобы работать с системой покупок необходим файл IMarketBillingService.aidl. Лежит он в /user/android-sdk-linux/extras/google/play_billing директории с SDK. Положить файлик надо в com.android.vending.billing пакет вашего приложения.

О типах покупок можно почитать тут. Нас интересую восстанавливаемые покупки, то есть те, что привязываются к аккаунту и повторно их уже не купить. Если вы удалите приложение и постановите заново, то покупка будет восстановлена. В нашем случае, после покупки отключения рекламы, реклама больше не будет беспокоить пользователя. Это касается и других устройств: если пользователь залогиниться на другом устройство под своим аккаунтом, то в приложение будет восстановлена покупка и реклама будет отключена.

Для работы необходимо добавить разрешение в AndroidManifest.xml:

Очень помогает официальная документация и пример из SDK.

Необходимо определить ключик в приложении – PublicKey, полученный при регистрации аккаунта на Android Market
Определяем IabHelper и инициализируем. Если удачно, то пытаемся восстановить покупки.

mGotInventoryListener – слушатель для восстановления покупок.

Теперь надо, собственно, саму покупку реализовать:

SKU_ADS_DISABLE – идентификатор товара, который вы создали в адмике Google Play. mPurchaseFinishedListener – слушатель:

Стоит отдельно поговорить о методе по верификации:

Сейчас нет никакой проверки покупок, но в реальном приложении вы должны сверять полученные данные с той сгенерированой строкой, что вы отправили в запросе на покупку. Проверять это надо на своём стороннем сервере. Для обычно приложения или офф-лайн игры это может и не критично, но для он-лайн игры это очень важно.

В принципе всё, теперь при запуске приложения просиходит проверка настроек (куда мы сохранили, что отключили рекламу):

Читайте также:  Топ андроид автомобильных навигаторов

После чего реклама уже не будет показываться.

Тестирование покупок

Сейчас довольно удобно тестировать своё приложение. Можно залить .apk как альфа/бета версию и опубликовать. При этом можно назначить группу в Google+, которая будет иметь возможность к тестированию. Если вы публикуете альфа или бета версию приложения, то в маркете она не появится, иметь доступ будет только эта группа.

Тестеры смогут осуществлять покупки. Деньги будут списываться без комиссии и будут возвращены после 15 минут после покупки. Так что, не беспокойтесь. Вот только у вас не получится протестировать приложение, если ваш аккаунт на устройстве и аккаунт издателя один и тот же =/

Полностью рабочий пример можете посмотреть на гитхабе.

Источник

In-app purchases: продвинутые механики работы с покупками на Android и iOS

Привет, я Влад, core разработчик Android SDK в Adapty. Это заключительная статья из серии туториалов по внедрению внутренних покупок в мобильные приложения:

iOS in-app purchases:

Android in-app purchases:

Написано совместно с:

Андреем Кяшкиным,

В заключительной статье мы решили не замыкаться на одной платформе, а рассказать о продвинутых практиках работы с покупками на iOS и Android и показать, как сервер расширяет наши возможности при работе с подписками и какие преимущества даёт.

Работа с продуктами на сервере

Для получения данных о продуктах на iOS/Android с помощью StoreKit/Billing Library нам нужно передавать id продуктов, информацию о которых мы хотим запросить — то есть, нет способа получить все доступные продукты, не зная о них вообще ничего. Бэкенд дает нам замечательное преимущество — не зашивать id продуктов на клиенте и тем самым иметь возможность манипулировать списком актуальных продуктов без обновления приложения.

Таким образом, мы можем отдавать на клиент общую модель продукта:

product_id — это id продукта в сторе. Может возникнуть вопрос, почему таких полей, как описание продукта или цена, в этой модели нет. Тут важно понимать, что создание продуктов в соответствующих консолях никто не отменял, просто часть клиентской логики мы переносим на бэк, а другую ее часть мы перенести не можем. Помимо самого совершения покупки, которое без участия сторов невозможно (пока ещё), информацию о продукте по id тоже нужно получать от стора напрямую, потому что Apple и Google отдают локализованные значения в зависимости от того, к какой стране привязан данный аккаунт.

introductory_offer_eligibility , promotional_offer_eligibility и promotional_offer_id — это поля, которые несут в себе информацию о скидочных предложениях, доступных конкретному пользователю. В отличие от предыдущего пункта, эти штуки мы как раз вынесли на бэк, потому что — внезапно — ни AppStore, ни Play Market напрямую не дают информацию, доступно ли intro или promo для конкретного пользователя. Соответственно, у самого продукта может быть intro, но данному пользователю оно недоступно, потому что он его уже использовал. И чтобы отобразить это в UI, вычислять это нужно самостоятельно, лучше на бэке.

И теперь флоу получения продуктов на клиенте будет выглядеть так:

Получаем историю транзакций от стора на девайсе.

Отправляем данные о транзакциях на сервер. В этом месте бэк вычисляет, доступны ли данному пользователю скидочные предложения.

Запрашиваем у бэка продукты.

По id продуктов запрашиваем у стора всю остальную информацию.

Отображаем в UI.

Предоставление кросс-доступа пользователю

Как только вы вынесли продукты на сервер и сделали само понятие «продукт» универсальным, стоит задуматься о том, как сделать то же самое для понятия «статус покупки». Идея в том, что если у вас больше одной платформы, то покупка на одном устройстве должна разблокировать доступ к контенту на любом устройстве вне зависимости от ОС, но в пределах аккаунта, с которого она была совершена. Если у вас больше одного продукта, то сделать это не так просто, т.к. вам на устройстве необходимо понимать, что именно купил пользователь, и давать ему доступ к той или иной части вашего приложения.

Для универсализации статуса покупки удобно ввести понятие «уровень доступа», который выставляется пользователю при совершении покупок из определенного набора. Например, мы добавляем четыре продукта — по два на каждую платформу, недельная премиум и недельная премиум плюс. Пример из жизни — Silver и Gold подписка в Тиндере. Gold стоит дороже и открывает больше возможностей. За обычными недельными мы закрепляем уровень доступа «обычная», а за премиум подписками, соответственно, «премиум». Если пользователь на какой-либо платформе или девайсе покупает подписку, за которой, например, закреплен уровень доступа «обычная» то сервер должен после покупки прислать на устройство этот идентификатор (внутри профиля или каким-то другим способом) и, выполнив обычное сравнение строк, вы сможете понять, что именно купил пользователь и отреагировать на это.

Так выглядит проверка на наличие уровня доступа:

Таким образом, мы абстрагируемся от понятия «покупка» и «платформа», в сторону одного общего абстрактного понятия «доступ». Единственный недостаток этого подхода — что уровни доступа вам придется указывать напрямую в коде, но обычно их не очень много (один или два) и они весьма статичны, так что их поддержка не должна вызывать сложностей. Также не забывайте получать актуальный уровень доступа где-то на запуске приложения, чтобы обрабатывать случай, когда покупка была сделана на другом устройстве / платформе.

Читайте также:  Lego star wars the complete saga android встроенный кэш

В большинстве случаев приложение ограничивается одним уровнем доступа «купленный», т.е. пользователь или что-то купил, или ничего не купил. В этом случае достаточно будет обойтись одним уровнем доступа, но благодаря ему обработка кроссплатформенных покупок не доставит вам проблем в будущем.

Синхронизация истории покупок и восстановление покупок

Помимо всего прочего, также важно уметь правильно работать с историей покупок пользователя. Например, это актуально в случае переустановки приложения, если у вас предусмотрена только анонимная или неявная авторизация, т.е. нельзя сразу понять, есть ли у пользователя платный доступ. В этом случае достаточно будет получить историю покупок и отправить ее на сервер для обработки. Сделать это можно следующими способами:

просто запросив рецепт (receipt) — актуально, если в пределах установки уже были совершены какие-то покупки;

запустив процесс восстановления покупок (restore purchases).

А вот на iOS 15+ появилась возможность получать все entitlements пользователя в любой момент.

О получении рецептов мы уже писали в предыдущих статьях, поговорим чуть больше про восстановление. Восстановление не стоит запускать сразу же на старте, т.к. оно вызывает показ окна для пользователя, где требуется ввести логин и пароль от аккаунта. Подобный интерфейс на старте без каких-либо предшествующих действий со стороны пользователя может отпугнуть и создать ощущение мошенничества.

Как только пользователь сам инициировал процесс восстановления покупок, то тут уже можно спокойно обращаться к системному фреймворку работы с покупками. После успешного восстановления необходимо пересинхронизировать все покупки пользователя на сервер, что позволит определить текущее состояние его подписки; понять, доступны ли ему скидки; возможно составить какую-то аналитику для этого аккаунта.

В iOS 15+ появился listener, который в две строки можно запустить на старте приложения. Этот listener получает все текущие покупки, которые есть у пользователя, в виде массива и на старте обновляет их данные – статус и проч. В целом, при первом запуске приложения рестор покупок больше не нужен, т.к. в реал-тайме можно получить обновления по всем покупкам пользователя между разными девайсами.

Обработка покупок, когда сервер не отвечает

К сожалению, такое бывает. Если сервер лежит и покупка в это время невозможна, вы теряете не только подписчиков, но и деньги, как в настоящем, так и будущие автосписания, которые были бы возможны, если бы покупка состоялась.

При этом с ошибками от сторов на iOS или Android, как правило, сложно что-то сделать, кроме как показать ошибку в UI, а вот в случае недоступности нашего бэка мы можем чуть лучше сгладить углы.

Например, мы можем локально кэшировать продукты после их получения с бэка. Таким образом, если при запросе на продукты код ответа 500 и после нескольких повторных запросов ничего не поменялось, мы просто берем продукты из кэша и идем с ними в стор.

Тогда встаёт вопрос, что делать, если сервер лежал при первом запуске приложения, и в кэше пока ничего нет. Можно, конечно, показать ошибку, а можно «зашить» данные о продуктах прямо в сборку, чтобы в том кейсе, когда сервер упал, а пользователь открыл приложение впервые, мы бы могли ему сразу же на онбординге предложить совершить покупку.

Второе критичное место, где нам очень нужен бэк – это валидация покупки. Чтобы не расстраивать пользователя, можно сразу дать ему доступ, но при этом пытаться провалидировать покупку при любом удобном случае, например, при следующем запуске приложения или при возвращении приложения в foreground. Решение дать пользователю доступ к контенту без всех проверок может показаться поспешным, но если у вас преимущественно онлайн-контент, нечестным пользователям будет сложно пользоваться приложением без интернета, и рано или поздно неправомерный доступ будет отозван.

Заключение

В этой статье мы затронули более сложные механики работы с продуктами и покупками. Как правило, о них задумываются сразу после того, как сделали базовую интеграцию и основные механики уже работают: показ экрана оплаты, отображение актуальной информации о продуктах, покупка, обработка самых популярных ошибок.

Как видите, процесс подключения покупок довольно трудоёмкий и требует учёта очень разных сценариев. Упростить задачу можно с помощью сторонних сервисов. Например, в Adapty все продвинутые кейсы и, тем более, базовое подключение покупок с серверной валидацией уже готовы. Для работы нужно создать аккаунт и подключить Adapty SDK. Так вы сэкономите пару месяцев разработки и начнёте быстрее монетизироваться. Для роста продаж в Adapty есть продвинутая аналитика, когортный анализ, а/б тесты пейволлов и интеграции с сервисами аналитики и атрибуции.

Источник

Оцените статью