- Testing in-app purchases on Android
- Overview
- Testing, according to the documentation
- Static responses
- Test purchases
- Testing, according to real life
- Bonus tip: faster testing for test subscriptions
- Update! 17/01/2018
- Conclusion
- Android In-app Billing: от мобильного приложения до серверной валидации и тестирования
- Зачем вообще это нужно?
- Часть 1: Регистрация приложения в консоли Google Play и создание списка покупок
- Часть 2: Интеграция Android in-app billing в мобильном приложении
- Часть 3: Валидация покупок и подписок на сервере
- Вместо заключения
Testing in-app purchases on Android
An addendum to the official documentation
Overview
Monetization is one of the most important aspects of distributing your product to the rest of the world. It can make or break a small freelance developer or an established startup.
Android, being so widespread, provides ways for users to purchase products from within your app: this is referred to as In-app Billing. Through this set of APIs, developers can offer two types of products:
- Managed in-app products
As the name suggests, these products are managed by the developer, and they branch into consumable and non-consumable. A consumable product is usually temporary and, once consumed, can be bought again, whereas a non-consumable product is a one-off benefit that the user will continue having in your app. - Subscriptions
These products come with a validity period (days, months, weeks, years) and are automatically renewed at the end of each billing cycle. When a subscription is not renewed, the product is no longer active for the user.
The official documentation is very helpful when it comes to the first steps for adding in-app products to your application. In particular, the “Selling In-App Products” training is well structured and walks you through each required step:
- Adding the Play Billing Library to your app (also check out this article by Joe Birch)
- Configuring the products in the Google Play Console
- Testing the in-app products in your app
Let’s focus on the third point.
Testing, according to the documentation
According to the documentation for testing, we have two ways of testing purchases:
- Static responses from Google Play
By using a restricted set of product IDs, you can trigger static responses from Google Play, so you can test that your app correctly handles all the possible states. You should use this when integrating the Play Billing Library into our app, or for instrumentation testing. - Test purchases
A Google account whitelisted as license-test in the Play Console will be able to make purchases without being actually charged. You can use this when the app goes to QA, or for general testing.
Static responses
Using static responses sounds easy enough, right? You just use one on the following product IDs during a purchase operation:
- android.test.purchased
- android.test.canceled
- android.test.refunded
- android.test.item_unavailable
and the Play Store will reply accordingly. The code looks roughly like this:
However, if you are testing subscriptions, you’re out of luck:
Note: If you’re testing subscription purchases, you must use the product ID of an actual subscription, not a reserved product ID. [Reference]
This means that we cannot rely on static responses to test subscriptions; instead, we need to resort to test purchases.
Test purchases
By using the so-called In-app Billing Sandbox, we can enable access to test purchases. These are the closest thing we have to actual purchases, with a few notable exceptions:
- You are not being charged any amount for the product you buy
- If you’re buying a subscription, the billing period recurs on a daily basis, regardless of the duration configured in the Play Console
- You have manual control over the response for each purchase
The last point is particularly interesting, because we have two ways of customizing the test purchase behavior.
The first method allows for fine control over the licensing behavior for all the testers: for example, by leaving it to RESPOND_NORMALLY we have a behavior similar to the real one.
The second method, on the other hand, allows for coarse control over the response of the fake credit card: you can decide whether the card will always approve the purchase or always decline it. Intuitively enough, this second method can be customized by each tester.
In order to be eligible for test purchases, there are a few steps to go through:
- Your APK must be uploaded to the Play Console (drafts are no longer supported)
- Add license testers in the Play Console
- Have testers join the alpha/beta testing group (if available)
- Wait 15 minutes, then start testing
Sounds easy enough, right? The documentation is also very encouraging
It’s easy to set up test purchases [1]
…Sure, let’s see about that. 😒
Testing, according to real life
You religiously follow the documentation, wait 15 minutes (make it 30, just in case), you start testing and…an error occurs. What now?
It turns out that the documentation is fairly optimistic when explaining the required steps for testing in-app purchases. According to this StackOverflow answer, which in turn is a collection of various trial-and-errors by other users, plus my personal experience, there are actually 10+ conditions that you need to meet or account for before being able to properly use test products!
Let’s recap them here:
- Your app is published (i.e., not in draft).
- The APK must be published (either production, alpha or beta channels).
- The APK you uploaded matches the one you’re testing with when it comes to version code, version name, and keystore signature (this point, in my experience, is not needed).
- When testing on the device, you’re using a different account than the one tied to the Play Console (i.e., not your developer account).
- The instructions to wait 15 minutes are a bit too optimistic, as it can take up to 2 hours for changes to propagate from the Play Console.
- Double check that the SKU you’re using in the app matches the one for the product that was configured in the Play Console.
- Double check that you’re not trying to purchase an already owned product or an already active subscription.
- Double check that you have activated your products in the Play Console: by default, products in the console are deactivated and you need to manually activate them.
- If you’re using the alpha/beta channels, make sure that the account you’re testing with is part of the testing group (i.e., has clicked on “Become a tester” after following the opt-in URL).
- If you use ABI flavors, like arm-v7, arm-v8, etc., make sure the APK you’re using for testing contains all the ABI libraries.
- Make sure that, when retrieving the Intent using getBuyIntent , you’re passing the correct product type, i.e., inapp if you’re purchasing managed in-app products or subs if you’re purchasing subscriptions.
- If you’re using the public key for enhanced security, make sure it matches the one on the Play Console because it might change over time (see here).
- Check that Google Play Services are updated on the test device by going to the Google Play Services page on the Play Store.
As you can see, the sandbox is far from straightforward when it comes to real usage, but at least now we have a few extra hints to start looking for a solution!
Bonus tip: faster testing for test subscriptions
We mentioned earlier that test subscriptions have a 1-day expiration period, regardless of their original duration. This means that, even if we cancel the subscription, it will still be considered active for that day. In turn, when the app retrieves the list of purchased products, it will receive the cancelled subscription and present it as an active subscription (because it technically still is). Your UI will then react accordingly and display premium features, instead of the purchase button: again, technically correct, but very inconvenient for us to do quick testing.
However, there’s a nice way of checking whether a subscription’s auto-renewal has been cancelled: the autoRenewing field inside the INAPP_PURCHASE_DATA JSON payload that comes from the billing service (see documentation). When checking the validity of a subscription in a debug environment, you can assume that when autoRenewing is false the subscription is cancelled and you can purchase another one.
⚠️ Be careful though! This check should only be done in debug/staging environments and not in production, so make sure you limit this “strict” check to debug/staging builds only. ⚠️
Update! 17/01/2018
While this post was still being drafted, Google announced that test subscriptions will no longer be renewed daily. Instead, the renewal period will vary from 5 to 30 minutes, depending on the original billing period.
In addition to this, they are limiting the amount of times a test subscription can be renewed to 6 (it is currently unlimited).
All these modifications will be applied starting February 20th 2018.
Conclusion
While far from perfect, the in-app billing support is critical for the Android ecosystem to grow and to being able to generate revenue.
When implementing purchases in your app, it’s worth paying attention to the checklist we reported before to avoid headaches, as well as provide a reliable sandbox environment for you to develop with and for your testers to test the app.
It’s also nice to see that Google is committed for the long run, as they just released the all new Play Billing Library (compared to the old 2013 version!).
A final shout out to the Android community, for being as open and as supportive as ever!
Источник
Android In-app Billing: от мобильного приложения до серверной валидации и тестирования
Всем привет! Недавно передо мной встала задача интегрировать биллинг в наш сервис, и, хотя изначально задача казалась довольно простой, в результате это вылилось в исследование длиной в месяц времени, кучу нервов и открытий. Результатом стало понимание того, что, несмотря на огромное количество документации, не все можно найти простым запросом в Google (а в некоторых местах документация предлагает откровенный бред, о чем я еще расскажу далее).
В результате биллинг от Google Play был успешно интегрирован в наш сервис, валидация покупок и подписок на серверной стороне работает. Кому стало интересно — добро пожаловать под кат: здесь будет полное описание всего, начиная от регистрации покупок в консоли управления Google Play, и заканчивая работой с подписками на своем бекенде.
Для начала коротко о пациенте. Я буду разбирать по кусочкам Google Play In-App Billing V3 а также облачный Android Publisher API, который и поможет нам как с валидацией покупок, так и при работе с подписками. Также не обойдем стороной Консоль управления Google Play — она тоже нам понадобится.
Зачем вообще это нужно?
Если у вас клиент-серверное приложение — то без валидации на сервере вам не обеспечить защиту от пиратства. И хотя можно просто валидировать цифровую подпись покупки на сервере, у запроса на Android Publisher API метода есть некоторые дополнительные возможности. Во-первых, вы можете получить информацию о покупке или подписке в любое время без привязки к устройству пользователя, а, во-вторых, вы можете получить более детальную информацию о подписках и управлять ими (отменять, откладывать и т. п.). К примеру, если вы хотите отобразить дату следующего платежа как в Google Play Music:
То вы можете получить ее только запросом на Android Publisher API.
Полный flow при интеграции биллинга таков:
1. Регистрация приложения в консоли Google Play и создание списка покупок.
2. Интеграция Android in-app billing в мобильном приложении.
3. Валидация покупок и подписок на сервере.
Часть 1: Регистрация приложения в консоли Google Play и создание списка покупок
Зайдите в Консоль управления Google Play (если у вас нет аккаунта — зарегистрируйте его за $25) и создайте ваше первое приложение. Начнем с того момента, когда ваше приложение уже зарегистрировано.
1. Есть ваше приложение не было ранее загружено — подпишите ваше приложение вашим release-сертификатом и загрузите его в закрытое альфа-или бета тестирование.
All Applications / Ваше Приложение / APK / Alpha(Beta) Testing
2. Создайте список тестирования и активируйте его для выбранного вами (Alpha или Beta) типа тестирования.
3. Добавьте в этот список email-ы Google-аккаунтов, которые будет тестировать биллинг. Например, ваш личный email, с помощью которого вы вошли в Google Play на своем устройстве.
Внизу будет ссылка Opt-in URL: по этой ссылке нужно перейти всем пользователям, которые будут тестировать биллинг (и самому тоже), и согласиться на тестирование. Без этого вы не сможете совершать покупки в альфа/бета версии.
4. Перейдите во вкладку Settings / Account Details, найдите раздел LICENSE TESTING и в поле Gmail accounts with testing access добавьте те же email-ы, что и в прошлом шаге. Теперь с этих аккаунтов вы можете тестировать покупки — за них не будет взыматься плата.
Добавить метод оплаты все же придется — сам диалог покупки потребует этого, однако когда вы непострудственно увидите кнопку купить в приложении — будет указано, что это тестовая покупка.
5. Добавьте тестовые покупки в ваше приложение. Для этого пройдите в All Applications / Ваше Приложение / In-app Products и нажмите Add new product. Можете добавить одну покупку (Managed product) и одну подписку (Subscription). В качестве product id можно использовать что-то в стиле com.example.myapp_testing_inapp1 и com.example.myapp_testing_subs1 для покупки и подписки соответственно Нужно как минимум добавить название и описание, установить цену для продукта, выбрать страны, где он доступен (можете выбрать все), для подписки также выбрать период, и активировать продукт. После этого он станет доступен через некоторое время.
ВАЖНО: вы должны опубликовать приложение (как минимум в alpha/beta), иначе покупки работать не будут.
Коротко о типах покупок
1. Managed product (inapp) — одноразовая покупка. После покупки пользователем становится владельцем покупки навсегда, но также такая покупка может быть «использована» (consume) — например, для начисления каких то бонусов. После использования покупка исчезает и ее можно совершить еще раз.
2. Subscription (subs) — подписка. После активации у пользователя снимается определенная сумма раз в определенный период. Пока пользователь платит — подписка активна.
Когда наши покупки будут активированы — мы сможем получить информацию о них непосредственно в мобильном приложении (название, описание, цена в локальной валюте) а также совершить покупку.
Часть 2: Интеграция Android in-app billing в мобильном приложении
Для начала выполним некоторые манипуляции, чтобы работать с биллинг-сервисом в нашем приложении.
Скопируем файлик IInAppBillingService.aidl в наш проект:
IInAppBillingService.aidl это файл Android Interface Definition Language (AIDL), который определяет интерфейс взаимодействия с сервисом In-app Billing Version 3. Вы будете использовать этот интерфейс для выполнения биллинг-запросов с помощью IPC-вызовов.
Чтобы получить файл AIDL:
Откройте Android SDK Manager.
В SDK Manager найдите и раскройте секцию Extras.
Выберите Google Play Billing Library.
Нажмите Install packages чтобы выполнить установку.
Перейдите в папку src/main вашего проекта и создайте папку с именем aidl.
Внутри этот папки создайте пакет com.android.vending.billing.
Скопируйте файл IInAppBillingService.aidl из папки %anroid-sdk%/extras/google/play_billing/ в только что созданный пакет src/main/aidl/com.android.vending.billing
Добавим разрешение в манифест:
И в месте, где мы собираемся совершать покупки, подключимся к сервису:
Теперь можно приступать к работе с покупками. Получим список наших покупок из сервиса с описанием и ценами:
С помощью этого метода мы можем загрузить данные о доступных покупках.
Теперь мы можем прямо из приложения получить список покупок и информацию про них. Цена будет указана в той валюте, в которой пользователь будет платить. Эти методы надо вызывать в фоновом потоке, так как сервис в процессе может загружать данные с серверов Google. Как использовать эти данные — на ваше усмотрение. Вы можете отобразить цены и названия продуктов из полученного списка, а можете названия и цены указать в ресурсах приложения.
Самое время теперь что-то купить!
Отдельно хочется сказать про dataSignature. Пример ее проверки есть тут, но если ваша покупка валидируется на сервере — то это лишний шаг.
Также может быть полезной возможность получить информацию о уже совершенных покупках:
Это тоже нужно выполнять из фонового потока. Здесь вернется список покупок, которые мы совершили ранее. Также можно получить и список активных подписок.
Следующий шаг — использование покупки. Имеется в виду, что вы начисляете пользователю что-то за покупку, а сама покупка пропадает, давая таким возможность совершить покупку еще раз.
После этого вы уже не сможете прочитать данные о покупке — она будет недоступна через getPurchases().
Здесь наши возможности по использованию биллинга непосредственно на устройстве заканчиваются.
Часть 3: Валидация покупок и подписок на сервере
Это самая интересная часть, над которой я бился дольше всего. Все примеры будут на java, для которой Google предоставляет готовую библиотеку для работы со своими сервисами.
Библиотеки и для других языков можно поискать здесь. Документация по Google Publisher API находится тут, в контексте текущей задачи нас интересуют Purchases.products и Purchases.subscriptions.
По сути, главная проблема, с которой я столкнулся, это описание способа авторизации. Даже по самому описанию он выглядит как пятая нога у коня, но проблема не в том, что он не работает, а в том, что он в корне не верный для нашей задачи. Просьба к знатокам не кидаться в меня камнями: OAuth предназначен для работы с ресурсами клиента, в нашем же случае backend-сервис обращается за данными биллинга нашего собственного приложения.
И вот тут нам на помощь приходит IAM (Identy Access Management). Нам нужно создать проект в Google Cloud Console и зайти во вкладку Credentials, выбрать Create credentials → Service account key.
Заполните данные так, как показано на картинке:
Service account: New service account
Service account name: имя на выбор
Role: не выбирайте, она сейчас не нужна
Key type: JSON
Нажимаете Create. Вылезет окошко с предупреждением Service account has no role. Соглашается, выбираем CREATE WITHOUT ROLE. Вам автоматически загрузится JSON-файл с данными для авторизации аккаунта. Сохраните этот файл — в будущем он понадобится для того, чтобы авторизоваться на Google-сервисах.
Теперь возвращаемся на вкладку Credentials нашего проекта и видим внизу список Service account keys. Справа кнопка Manage service accounts — нажимаем на нее и видим:
myaccount@project-name.iam.gserviceaccount.com — это и есть id нашего аккаунта. Копируем его и идем в Google Play Developer Console → Settings → User Accounts & Rights и выбираем Invite new user.
Вставляем id аккаунта в поле Email, добавляем наше прилождение и ставим галочку напротив View financial reports.
Нажимаем Send Invitation. Теперь мы можем использовать наш JSON-файл для авторизации и Google API и доступа к данным покупок и подписок нашего приложения.
Следующий шаг — нужно активировать Google Play Developer API для нашего проекта. Идем в Google Developer Console → Library и ищем Google Play Developer API. Открываем его и нажимаем Enable.
Последний шаг настройки — идем в Google Play Developer Console → Settings → API Access.
В списке находим наш проект (на картинке выше это Google Play Android Developer, но там должно быть имя вашего проекта) и нажимаем Link.
Теперь перейдем к разработке серверной части
Как вы будете хранить JSON-файл с приватными данными IAM-аккаунта оставим на ваше усмотрение. Импортируйте Google Play Developer API в ваш проект (mavencentral) и реализуем проверку.
Данные о покупке нужно отправить с нашего приложения на сервер. Сама реализация проверки на сервере выглядит вот так:
Таким образом мы получаем возможность получить данные о нашей покупке непосредственно от Google, потому пропадает необходимость в проверке подписи. Более того, для подписок вы можете получить намного больше информации, чем непосредственно через IInAppBilligService в мобильном приложении.
В качестве параметров запроса нам нужны:
- packageName — имя пакета приложения (com.example.myapp)
- productId — идентификатор продукта (com.example.myapp_testing_inapp1)
- token — уникальный токен покупки, который вы получили в мобльном приложении:
Детали по ProductPurchase и SubscriptionPurchase описаны в документации, не будем на них останавливаться.
Вместо заключения
Сначала казавшаяся простой задача по интеграции биллинга в наш сервис превратилась в путешествие через документацию, гуглинг и бессилие (OAuth, ты прекрасен), так как про использование IAM для целей доступа в документации ни слова. Серьезно, они предлагают вбить руками какой-то руками состряпанный URL в вашем браузере, добавить origin для редиректа в консоли управления проектом, и все это для того, чтобы получить одноразовый токен, который надо руками передать на сервер, после чего использовать весь флоу OAuth для получения доступа к данным биллинга. Это не говоря о том, что если вы не успеете использовать refresh-token, то вам придется получать новый токен — руками. Согласитесь — это звучит как полный бред для backend-сервиса, который должен работать без вмешательства человека.
Я надеюсь, что этой статьей помогу кому-то сэкономить немного времени и нервов.
Источник