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

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

  2. Android in-app purchases, часть 2: инициализация и обработка покупок.

  3. Android in-app purchases, часть 3: получение активных покупок и смена подписки.

  4. Android in-app purchases, часть 4: коды ошибок от Billing Library и как не облажаться с тестированием. — Вы тут.

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

Сегодня мы поговорим о кодах ошибок, которые мы можем получить от Billing Library в методе getResponseCode()

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

Коды ошибок

Начнем с самых простых ошибок – с говорящим названием ERROR (responseCode 6) и чуть более говорящим названием DEVELOPER_ERROR (responseCode 5). Для первого случая гугл пишет в документации «Fatal error during the API action», для второго – «Invalid arguments provided to the API». Например, я смог получить DEVELOPER_ERROR, когда для запроса querySkuDetailsAsync() в билдер в setType() передал пустую строку.

Но не всё так просто. Я пошел дальше и в методе launchBillingFlow() использовал измененный SkuDetails (вытащил json из SkuDetails реального продукта, поменял в нем productId и передал в конструктор новому SkuDetails). По сути это invalid argument, и я ожидал получить DEVELOPER_ERROR, но… получил ERROR.

Отдельного упоминания заслуживает текст, который показывается в диалоге в этом кейсе — сравните английский и русский вариант:

Это, конечно, был искусственный пример. Гораздо ближе к реальности кейс, когда гугл отклонил оплату. Если при тестировании покупок с тестовой карты, о чем мы расскажем в конце статьи, в диалоге покупки выбрать «test card, always declined», вернется также ошибка ERROR, но уже с адекватным текстом.

В третьей статье, где описывалась смена подписки, мы для одного из proration mode увеличили цену годовой подписки почти в 3 раза, но не сказали, какая там должна была быть ошибка, если бы мы этого не сделали. Исправляемся.

Так как там, получается, указан неправильный proration mode, по логике мы должны получить всё ту же DEVELOPER_ERROR. Но нет, мы получаем SERVICE_UNAVAILABLE (responseCode 2). Ее же мы получаем и если указать любое левое число в качестве proration mode (это int, а не enum, нас никто не остановит), и если указать неправильный purchaseToken. Смотрим в документацию про SERVICE_UNAVAILABLE – «Network connection is down». Так, стоп…

При этом еще мы видим интересный диалог.

Что еще любопытно – в кейсе с ERROR при закрытии диалога НЕ через кнопку «ОК» (то есть, теми способами, которые интерпретируются как возврат назад) в onPurchasesUpdated() пришло, собственно, ERROR, а в случае с SERVICE_UNAVAILABLE в аналогичном кейсе приходит USER_CANCELED (но если нажать «ОК» в диалоге, то мы, как и ожидали, получим SERVICE_UNAVAILABLE).

Ну и в случае с отсутствием интернета SERVICE_UNAVAILABLE тоже приходит, тут не соврали.

Вот остальные коды ошибок с небольшими комментариями, так сказать, honorable mentions.

  • BILLING_UNAVAILABLE (responseCode 3). Гугл поясняет, что «Billing API version is not supported for the type requested». Я смог воспроизвести эту ошибку, разлогинившись из Google-аккаунта, а также на Хуавее без Google Play Services. Возможно, она также воспроизведется на старых телефонах, где не обновляли Google Play.

  • SERVICE_DISCONNECTED (responseCode -1). Приложение иногда дисконнектится от сервиса Google Play. Это может произойти, если Play Store вдруг решит обновиться. Поэтому лучше перестраховаться и коннектиться перед каждым вызовом методов Billing Library, как в предыдущих статьях. А еще мы с гуглом советуем добавить какую-нибудь retry policy, если эта ошибка всё же придет в ответе.

  • SERVICE_TIMEOUT (responseCode -3). Название говорит само за себя — мы слишком долго ждали ответ от Google Play.

  • FEATURE NOT SUPPORTED (responseCode -2). В классе BillingClient есть пять констант FeatureType. Их доступность на данном устройстве можно проверять с помощью метода billingClient.isFeatureSupported(BillingClient.FeatureType.НужнаяФича). У меня на телефоне (Xiaomi Mi A2 Lite) FEATURE_NOT_SUPPORTED вернулось только для SUBSCRIPTIONS_ON_VR. При этом для IN_APP_ITEMS_ON_VR, как и для всех остальных фич, вернулось OK.

  • ITEM_NOT_OWNED (responseCode 8). Возникает при попытке законсьюмить покупку, которой у нас нет. Например, повторно после успешного консьюма.

  • ITEM_ALREADY_OWNED (responseCode 7). А тут наоборот – при попытке купить продукт, который у нас уже есть. В таком кейсе просто нужно обновить UI и сделать кнопку покупки некликабельной.

Самая популярная ошибка

Последняя и, наверное, самая популярная ошибка в начале пути внедрения in-app purchases — это ITEM_UNAVAILABLE (responseCode 4). Она говорит о том, что продукт недоступен для покупки, но не говорит, почему. А причины могут быть самые разные: от тестирования на неправильном аккаунте или неправильной сборке до покупки неактивированного продукта.

Вот чек-лист, что нужно сделать, чтобы избежать ее при тестировании:

  1. Отправить в ваш test track сборку с Billing Library. Это обязательное условие — при этом вы можете тестировать и на дебажных сборках с таким же applicationId, но важно, чтобы хотя бы один раз сборка с Billing Library была загружена в Play Console.

  2. Добавить в этот test track гугл-аккаунты тестировщиков, что особенно актуально для internal testing или закрытой альфы/беты. Там же будет ссылка в разделе How testers join your test, по которой тестировщики должны будут принять приглашение.

  3. Покупать можно только активированный продукт. После создания продукта в Play Console есть кнопка activate, более детально процесс создания продукта мы описывали в первой статье.

  4. Удостовериться, что тестирование на устройстве проходит с гугл-аккаунта, который является тестировщиком. Очевидный пункт, но бывает всякое, и это тоже нужно проверить, если вы получили такую ошибку.

  5. applicationId сборки, с которой тестируется покупка, должно полностью совпадать с applicationId из Play Console. Это особенно важно для тех, у кого добавляется суффикс в дебажных сборках.

  6. Добавить email-адреса тестировщиков в раздел Setup → License Testing в левом меню аккаунта (не приложения), чтобы они покупали продукты бесплатно с тестовой карты, а не с реальной. Еще один плюс, что подписки в данном случае будут иметь тестовую длительность. Не связано с этой ошибкой, но тоже полезное знание.

Заключение

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

Про Adapty

Для более простой работы с ошибками советую попробовать Adapty SDK для внедрения внутренних покупок в приложения. Кроме технической части, Adapty даёт много преимуществ:

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

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

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

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

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

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

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

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

Комментарии (1)