О подписках

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

Если вы еще не настроили продукты по подписке для своего приложения, см . раздел Создание и настройка продуктов .

Обзор подписок

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

Вы можете иметь несколько подписок в одном приложении, чтобы представлять разные наборы преимуществ или разные уровни одного набора преимуществ (например, уровни «Серебряный» и «Золотой»).

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

Подробный обзор продуктов по подписке, базовых планов и предложений см. в документации в Справочном центре Play Console .

Интеграция предоплаченных планов

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

Для пополнения счета запустите процесс выставления счетов, как при первоначальной покупке. Указывать, что покупка является пополнением счета, не нужно.

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

После пополнения счета следующие поля в объекте «Результат Purchase » обновляются, чтобы отразить самую последнюю покупку пополнения счета:

  • Идентификатор заказа
  • Время покупки
  • Подпись
  • Купить токен
  • Признано

Следующие поля Purchase всегда содержат те же данные, что и в исходной покупке:

  • Имя пакета
  • Состояние покупки
  • Продукты
  • Автоматическое продление

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

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

Из-за вероятности короткого срока действия предоплаченного плана важно подтвердить покупку как можно скорее.

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

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

Интеграция подписки в рассрочку

Подписка в рассрочку — это тип подписки, при котором пользователи оплачивают подписку несколькими частями в течение определенного периода времени, а не платят всю абонентскую плату авансом.

Дополнительные рекомендации по подписке в рассрочку:

  • Доступность в странах : функция подписки в рассрочку доступна только в Бразилии, Франции, Италии и Испании (последние версии доступны в консоли).
  • Установка цены : при установке цены на подписку в рассрочку на консоли цена представляет собой сумму ежемесячного платежа. В сочетании с установленным периодом действия обязательств это формирует общую сумму подписки на экране покупки.
  • Период действия обязательств : общая продолжительность первоначального обязательства по подписке, в течение которого требуются ежемесячные платежи. Например, если базовый план имеет 15-месячный период действия обязательств, пользователь будет производить 15 ежемесячных платежей в течение этого периода.
  • Продление : в контексте подписки в рассрочку «продление» означает завершение периода действия обязательств: либо первоначального периода действия обязательств, либо последующего периода действия обязательств. После первоначальной регистрации первое продление происходит по завершении всего первоначального периода действия обязательств. Последующие продления происходят после завершения каждого последующего периода действия обязательств. Типы продления подписки в рассрочку могут быть «автопродление ежемесячно» или «автопродление на тот же срок». При «автоматическом продлении ежемесячно» последующие обязательства отсутствуют, и план ведет себя как ежемесячная подписка, где каждая ежемесячная плата за подписку представляет собой продление.
  • Расчетный период : в контексте подписки в рассрочку это относится к повторяющемуся интервалу, с которым производятся отдельные платежи, как указано в базовом плане.
  • Изменение плана и поведение при изменении цен : В случае изменения цен и отмены обязательств обязательство является твердым. Это означает, что если пользователь хочет отменить подписку или разработчик хочет изменить цену, изменение вступит в силу в конце периода действия обязательств. В отношении изменений плана обязательства не являются твердыми. Это означает, что смене плана не придется ждать до конца периода действия обязательств, оно вступит в силу либо немедленно, либо в следующую дату платежа в зависимости от установленного режима замены.
  • Изменение плана той же подписки : изменение плана с базового плана с рассрочкой на базовый план без рассрочки для того же продукта подписки не допускается.
  • Уведомления разработчиков в реальном времени (RTDN) : RTDN SUBSCRIPTION_CANCELLATION_SCHEDULED отправляется сразу после отмены по инициативе пользователя, когда платежи остаются в течение периода действия обязательств. Отмена находится на рассмотрении и вступит в силу только в конце периода действия обязательств. Затем, если пользователь не восстановил их, RTDN SUBSCRIPTION_CANCELED и SUBSCRIPTION_EXPIRED отправляются в конце периода действия обязательств.

  • Выплаты/реализация доходов : выплаты разработчикам будут осуществляться по мере того, как пользователи вносят ежемесячные платежи, на тех же условиях, что и для всех остальных подписок. Разработчикам не выплачивается аванс, когда пользователь подписывает подписку в рассрочку.

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

  • Доступность библиотеки платежей Play . Поле installmentDetails доступно только для PBL 7 или более поздней версии. Для PBL 5 и более поздних версий подписка в рассрочку возвращается с помощью queryProductDetails() , но подписка не будет включать подробную информацию о рассрочке, например количество зафиксированных платежей по плану.

Используйте глубокие ссылки, чтобы позволить пользователям управлять подпиской.

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

Вы можете включить глубокую ссылку из своего приложения на центр подписок Google Play для подписок с неистёкшим сроком действия, которые вы можете определить с помощью поля subscriptionState ресурса подписки . Исходя из этого, существует несколько способов создания глубоких ссылок на центр подписок Play Store.

Используйте следующий URL-адрес, чтобы направить пользователей на страницу, на которой показаны все их подписки, как показано на рисунках 1 и 2:

https://play.google.com/store/account/subscriptions
На экране подписок в Play Store отображается статус всех подписок пользователя, оплачиваемых Google Play.
Рисунок 1. На экране подписок в Play Store отображается состояние всех подписок пользователя, оплачиваемых Google Play.


Нажмите на подписку, чтобы увидеть дополнительную информацию.
Рисунок 2. Нажмите на подписку, чтобы просмотреть дополнительные сведения.

Эта глубокая ссылка может быть полезна, чтобы помочь пользователю восстановить отмененную подписку из центра подписок Play Store.

Чтобы напрямую перейти на страницу управления подпиской с неистекшим сроком действия, укажите имя пакета и productId связанный с приобретенной подпиской. Чтобы программно определить productId для существующей подписки, запросите серверную часть вашего приложения или вызовите BillingClient.queryPurchasesAsync() для получения списка подписок, связанных с конкретным пользователем. Каждая подписка содержит соответствующий productId как часть информации о состоянии подписки. Каждый объект SubscriptionPurchaseLineItem , связанный с покупкой подписки, содержит значение productId , связанное с подпиской, которую пользователь приобрел в этой позиции.

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

https://play.google.com/store/account/subscriptions?sku=your-sub-product-id&package=your-app-package

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

Разрешить пользователям обновлять, понижать или изменять свою подписку

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

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

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

На рис. 3 показан пример приложения с тремя различными планами:

Это приложение имеет три уровня подписки.
Рисунок 3. Это приложение имеет три уровня подписки.

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

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

Режимы замены

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

Режим замены

Описание

Пример использования

Зафиксированные платежи учитываются как оплаченные (Для замены подписки в рассрочку)

WITH_TIME_PRORATION

Подписка будет повышена или понижена немедленно. Оставшееся время корректируется на основе разницы в цене и зачисляется в счет новой подписки путем переноса следующей даты выставления счета. Это поведение по умолчанию.

Перейдите на более дорогой уровень без какой-либо немедленной дополнительной оплаты.

0

CHARGE_PRORATED_PRICE

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

Примечание. Эта опция доступна только при обновлении подписки, при котором увеличивается цена за единицу времени.

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

1

CHARGE_FULL_PRICE

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

Примечание. Если новая подписка включает бесплатную пробную версию или ознакомительное предложение, с пользователя взимается 0 долларов США или цена ознакомительного предложения, в зависимости от того, что применимо, во время обновления или понижения версии.

Переход с более короткого расчетного периода на более длительный.

1 (Примечание: 0, если новая подписка имеет бесплатную пробную версию.)

WITHOUT_PRORATION

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

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

0

DEFERRED

Подписка повышается или понижается только при ее продлении, но новая покупка оформляется сразу со следующими двумя позициями:

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

Примечание. При подписке в рассрочку смена плана происходит в начале следующей даты платежа.

Переход на менее дорогой уровень.

1

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

Установить режим замены при покупке

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

Повторная подписка или смена планов в рамках одной подписки

Вы можете указать режим замены по умолчанию в консоли Google Play. Этот параметр позволяет вам выбрать, когда взимать плату с текущих подписчиков, если они приобретут другой базовый план или предлагают ту же подписку или повторно подпишутся после отмены. Доступные варианты: «Взимать немедленно» , что эквивалентно CHARGE_FULL_PRICE , и «Взимать плату на следующую дату выставления счета» , что эквивалентно WITHOUT_PRORATION . Это единственные соответствующие режимы замены при переключении базовых планов в рамках одной подписки.

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

Переключайте планы между подписками или переопределите режим замены по умолчанию.

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

Чтобы правильно указать SubscriptionUpdateParams как часть конфигурации потока покупки во время выполнения, обратите внимание на следующие ограничения:

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

Примеры замены и поведение

Чтобы понять, как работает каждый режим пропорционального распределения, рассмотрим следующий сценарий:

У Samwise есть подписка на онлайн-контент из приложения Country Gardener. У него есть ежемесячная подписка на версию контента первого уровня , которая является только текстовой. Эта подписка обходится ему в 2 доллара в месяц и продлевается первого числа месяца.

15 апреля Samwise решил перейти на годовую версию подписки уровня 2 , которая включает видеообновления и стоит 36 долларов в год .

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

WITH_TIME_PRORATION

Подписка Samwise уровня 1 прекращается немедленно. Поскольку он заплатил за полный месяц (1–30 апреля), но обновил подписку в середине периода подписки, к его новой подписке применяется половина месячной подписки (1 доллар США). Однако, поскольку новая подписка стоит 36 долларов в год, кредитный баланс в 1 доллар оплачивается только за 10 дней (16–25 апреля); поэтому 26 апреля с него взимается 36 долларов за новую подписку и еще 36 долларов 26 апреля каждого последующего года.

Вам следует вызвать PurchasesUpdatedListener вашего приложения в момент успешной покупки, и вы сможете получить новую покупку как часть вызова queryPurchasesAsync() . Ваша серверная часть немедленно получает SUBSCRIPTION_PURCHASED уведомление разработчика в режиме реального времени.

CHARGE_PRORATED_PRICE

Этот режим можно использовать, поскольку цена подписки уровня 2 за единицу времени (36 долларов США в год = 3 доллара США в месяц) выше, чем цена подписки уровня 1 за единицу времени (2 доллара США в месяц). Подписка Samwise уровня 1 прекращается немедленно. Поскольку он заплатил за полный месяц, но использовал только половину, половина месячной подписки (1 доллар США) применяется к его новой подписке. Однако, поскольку новая подписка стоит 36 долларов в год, оставшиеся 15 дней стоят 1,50 доллара; поэтому за новую подписку с него взимается разница в размере 0,50 доллара. 1 мая с Сэмвайса взимается плата в размере 36 долларов США за новый уровень подписки и еще 36 долларов США 1 мая каждого последующего года.

Вам следует вызвать PurchasesUpdatedListener вашего приложения в момент успешной покупки, и вы сможете получить новую покупку как часть вызова queryPurchasesAsync() . Ваша серверная часть немедленно получает SUBSCRIPTION_PURCHASED уведомление разработчика в режиме реального времени.

WITHOUT_PRORATION

Подписка Samwise уровня 1 немедленно повышается до уровня 2 без дополнительной оплаты, и 1 мая с него взимается плата в размере 36 долларов США за новый уровень подписки и еще 36 долларов США 1 мая каждого последующего года.

Вам следует вызвать PurchasesUpdatedListener вашего приложения в момент успешной покупки, и вы сможете получить новую покупку как часть вызова queryPurchasesAsync() . Ваша серверная часть немедленно получает SUBSCRIPTION_PURCHASED уведомление разработчика в режиме реального времени.

DEFERRED

Подписка Samwise уровня 1 действует до истечения срока ее действия 30 апреля. 1 мая вступает в силу подписка уровня 2 , и с Samwise взимается плата в размере 36 долларов США за новый уровень подписки.

Вам следует вызвать PurchasesUpdatedListener вашего приложения в момент успешной покупки, и вы сможете получить новую покупку как часть вызова queryPurchasesAsync() . Ваша серверная часть немедленно получает SUBSCRIPTION_PURCHASED уведомление разработчика в режиме реального времени. Вам следует обработать покупку так же, как и любую другую новую покупку на этом этапе. В частности, убедитесь, что вы подтверждаете новую покупку. Обратите внимание, что startTime новой подписки заполняется в момент вступления в силу замены, что происходит по истечении срока действия старой подписки. В этот момент вы получаете RTDN SUBSCRIPTION_RENEWED для нового плана подписки. Подробнее о поведении ReplacementMode.DEFERRED читайте в разделе «Обработка отложенной замены» .

CHARGE_FULL_PRICE

Подписка Samwise уровня 1 прекращается немедленно. Его подписка уровня 2 начинается сегодня, и с него взимается плата в размере 36 долларов США. Поскольку он заплатил за полный месяц, но использовал только половину, половина месячной подписки (1 доллар США) применяется к его новой подписке. Поскольку эта новая подписка стоит 36 долларов в год, к периоду подписки (~ 10 дней) будет добавлена ​​1/36 года. Таким образом, следующая плата Samwise составит 1 год и 10 дней с сегодняшнего дня и составит 36 долларов США. После этого каждый последующий год с него взимается 36 долларов.

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

Запуск изменений подписки в приложении

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

Котлин

val offerToken = productDetails
        .getSubscriptionOfferDetails(selectedOfferIndex)
        .getOfferToken()

val billingParams = BillingFlowParams.newBuilder().setProductDetailsParamsList(
       listOf(
           BillingFlowParams.ProductDetailsParams.newBuilder()
               .setProductDetails(productDetails)
               .setOfferToken(offerToken)
               .build()
       )
       ).setSubscriptionUpdateParams(
           BillingFlowParams.SubscriptionUpdateParams.newBuilder()
               .setOldPurchaseToken("old_purchase_token")
               .setSubscriptionReplacementMode(
                 BillingFlowParams.ReplacementMode.CHARGE_FULL_PRICE
               )
               .build()
       ).build()

billingClient.launchBillingFlow(
    activity,
    billingParams
   )
// ...

Ява

String offerToken = productDetails
    .getSubscriptionOfferDetails(selectedOfferIndex)
    .getOfferToken();

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(
        ImmuableList.of(
            ProductDetailsParams.newBuilder()
                // fetched via queryProductDetailsAsync
                .setProductDetails(productDetails)
                // offerToken can be found in
                // ProductDetails=>SubscriptionOfferDetails
                .setOfferToken(offerToken)
                .build()))
    .setSubscriptionUpdateParams(
        SubscriptionUpdateParams.newBuilder()
            // purchaseToken can be found in Purchase#getPurchaseToken
            .setOldPurchaseToken("old_purchase_token")
            .setSubscriptionReplacementMode(ReplacementMode.CHARGE_FULL_PRICE)
            .build())
    .build();

BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
// ...

Рекомендации по замене

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

Сценарий Рекомендуемый режим замены Результат
Переход на более дорогой уровень CHARGE_PRORATED_PRICE Пользователь получает доступ немедленно, сохраняя тот же расчетный период.
Переход на более дешевый уровень DEFERRED Пользователь уже заплатил за более дорогой уровень, поэтому доступ сохраняется до следующей даты выставления счета.
Обновление во время бесплатной пробной версии с сохранением пробной версии WITHOUT_PRORATION Пользователь переходит на более высокий уровень на оставшуюся часть пробного периода без дополнительной оплаты.
Обновление во время использования бесплатной пробной версии – прекращение доступа к бесплатной пробной версии CHARGE_PRORATED_PRICE Пользователь получает доступ к новому уровню немедленно, оставшаяся стоимость бесплатной пробной версии сохраняется. Перенесенная стоимость рассчитывается на основе цен базового плана.

Обрабатывать покупки изменений в подписке

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

Поведение в приложении такое же, как и при любой новой покупке. Ваше приложение получает результат новой покупки в PurchasesUpdatedListener , а новая покупка доступна в queryPurchasesAsync .

API разработчика Google Play возвращает linkedPurchaseToken в ресурсе подписки , когда покупка заменяет существующую. Обязательно сделайте недействительным токен, указанный в linkedPurchaseToken , чтобы гарантировать, что старый токен не будет использоваться для получения доступа к вашим службам. Информацию об обработке покупок обновлений и понижений см. в разделе Обновления, понижения версий и повторные регистрации .

Когда вы получите новый токен покупки, выполните тот же процесс проверки, что и при проверке нового токена покупки . Обязательно подтвердите эти покупки с помощью BillingClient.acknowledgePurchase() из библиотеки платежей Google Play или Purchases.subscriptions:acknowledge из API разработчика Google Play.

Обработка отложенной замены

Режим отложенной замены позволяет пользователю использовать оставшиеся права в старом плане перед переходом на новый план.

Когда вы используете replaceMode.DEFERRED для новой покупки, queryPurchasesAsync() возвращает новый токен покупки после потока покупки, который остается связанным со старым продуктом до тех пор, пока не произойдет отложенная замена в следующую дату продления, после чего возвращается новый продукт.

Раньше такого взаимодействия с пользователем можно было добиться с помощью устаревшего ProrationMode.DEFERRED , но ProrationMode.DEFERRED устарел в Play Billing Library 6. См. следующую таблицу, чтобы понять, где поведение отличается:

Время

ProrationMode.DEFERRED (устарело)

ЗаменаMode.DEFERRED

Сразу после успешного завершения покупки (приложение)

PurchasesUpdatedListener вызывается после покупки со статусом успешного обновления или понижения версии.

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

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

PurchasesUpdatedListener вызывается после покупки со статусом успешного обновления или понижения версии.

queryPurchasesAsync() сразу же возвращает покупку с новым токеном покупки и исходное право, связанное с ним.

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

Сразу после успешного завершения процесса покупки (бэкэнд)

SUBSCRIPTION_PURCHASED RTDN не отправляется после процесса покупки. Серверная часть еще не уведомлена о новой покупке.

SUBSCRIPTION_PURCHASED RTDN со старым Product_id отправляется сразу после потока покупки для нового токена покупки.

Вызов метода Purchases.subscriptionsv2.get с новым токеном покупки возвращает покупку, имеющую «startTime», указывающую время покупки, с двумя позициями :

  • Один представляет старое право и имеет «expiryTime» в будущем. Старое право не будет продлено и имеет DeferredItemReplacement , содержащий продукт нового права. Это указывает на ожидаемую замену старого права по истечении его срока действия.
  • Один представляет недавно приобретенное право. Для параметра «expiryTime» не установлено значение.

SUBSCRIPTION_EXPIRED отправлен за старым токеном покупки. При вызове метода Purchases.subscriptionsv2.get со старым токеном покупки он отображается как истекший (права на старый план передаются на новую покупку на оставшееся время).

При замене - первое продление после покупки (приложение)

queryPurchasesAsync() возвращает новый объект Purchase с новым токеном покупки и правом.

Новый токен покупки теперь доступен, поэтому его следует обработать .

queryPurchasesAsync() сразу же возвращает покупку с новым токеном покупки и новое право, связанное с ним.

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

При замене - первое продление после потока покупки (бэкенд)

Теперь новая покупка может быть обработана и подтверждена при отправке первого RTDN SUBSCRIPTION_RENEWED.

linkedPurchaseToken в ресурсе подписки можно использовать для определения того, какой пользователь в вашей серверной части подписки, если применимо, должен получить новое право.

Новая покупка была обработана и подтверждена, когда RTDN SUBSCRIPTION_PURCHASED был отправлен для нового токена покупки и записан как «startTime».

При использовании replaceMode.DEFERRED первые продления следуют стандартному поведению любого другого продления, и вам не нужно обрабатывать специальную логику для замен, когда происходит это событие.

При вызове метода Purchases.subscriptionsv2.get с новым токеном покупки возвращается покупка с двумя позициями :

  • Один, представляющий старое право, с `expiryTime` в прошлом и без установленного значения для DeferredItemReplacement .
  • Один, представляющий новое право, с будущим значением `expiryTime` и включенным флагом auto_renewing_enabled.

С этого момента replaceMode.DEFERRED следует использовать вместо устаревшего ProrationMode.DEFERRED, так как он обеспечивает такое же поведение в отношении изменений прав, но предлагает способ управления покупкой, который в большей степени соответствует поведению других новых покупок.

Управление клиентами

Используя уведомления для разработчиков в режиме реального времени, вы можете в режиме реального времени определять, когда пользователь решает отменить подписку. Когда пользователь отменяет подписку, но до истечения срока ее подписки, вы можете отправлять ему push-уведомления или сообщения в приложении с просьбой возобновить подписку.

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

До истечения срока подписки После окончания подписки
В приложении В магазине Play В приложении В магазине Play
Функция возврата Подписка в приложении Восстановить Подписка в приложении Повторно подписаться
Пользователь проходит процедуру оформления заказа Да Нет Да Да
Подписка пользователя остается привязанной к тому же SKU. Пользователь может подписаться на тот же или другой SKU. Да Пользователь может подписаться на тот же или другой SKU. Да
Создает новый токен покупки Да Нет Да Да
Включено по умолчанию Нет Да, поддержка необходима всем разработчикам Нет

Приложения без библиотеки биллинга 2.0+: Нет

Приложения с библиотекой биллинга 2.0+: Да. Разработчики могут отказаться от участия в консоли.

Когда с пользователя взимается плата

При использовании того же SKU: конец текущего расчетного периода.

При использовании другого SKU: зависит от режима пропорционального распределения.

Конец текущего расчетного периода Немедленно Немедленно
Требуется реализация Предоставьте пользовательский интерфейс повторной регистрации в своем приложении.

Обнаружение изменений в состоянии подписки

Глубокая ссылка на Play Store

Предоставьте пользовательский интерфейс повторной регистрации в своем приложении. Обработка покупок вне приложения

До истечения срока подписки - в приложении

Для подписок, которые были отменены, но срок действия которых еще не истек, вы можете разрешить подписчикам восстановить свою подписку в вашем приложении, применив тот же процесс покупки продуктов внутри приложения, что и для новых подписчиков. Убедитесь, что ваш пользовательский интерфейс отражает наличие у пользователя существующей подписки. Например, вы можете захотеть отобразить текущую дату истечения срока действия пользователя и повторяющуюся цену с помощью кнопки «Реактивировать» .

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

  • Инициируйте покупку новой подписки с тем же номером SKU.
  • Новая подписка заменяет старую и продлевается с той же датой истечения срока действия. Старая подписка сразу помечается как истекшая.
  • Например, у Ахиллеса есть подписка на приложение Sample Music, срок действия которой истекает 1 августа. 10 июля он повторно подписывается на месячную подписку по той же цене за месяц. Новая подписка распределяется пропорционально оставшемуся балансу, активируется немедленно и продлевается 1 августа.

Если вы хотите предложить другую цену — например, новую бесплатную пробную версию или скидку на возврат — вместо этого вы можете предложить пользователю другой SKU:

  • Инициируйте обновление или понижение версии с использованием другого SKU, используя режим замены WITHOUT_PRORATION .
  • Новая подписка заменяет старую и продлевается с той же датой истечения срока действия. С пользователя взимается стоимость нового SKU, включая все начальные цены, на дату первоначального истечения срока действия. Если старая подписка была создана с использованием запутанного идентификатора учетной записи, этот же идентификатор следует передать в BillingFlowParams для обновлений и понижений.
  • Например, у Ахиллеса есть подписка на приложение Sample Music, срок действия которой истекает 1 августа. 10 июля он повторно подписывается на годовую подписку по начальной цене. Новая подписка активируется немедленно, и 1 августа с пользователя будет снята начальная цена.
  • Если вы решите включить бесплатную пробную или вступительную цену в свой Winback Sku, убедитесь, что пользователь имеет право, не позволяя Unful One Free Trial Per App Box в консоли Google Play, которая ограничивает пользователя получением одного бесплатного пробного приложения.

Когда вы получаете токен покупки, обработайте покупку так же, как с новой подпиской. Кроме того, API Google Play Developer возвращает linkedPurchaseToken в ресурсе подписки. Обязательно не согласны с токеном, предоставленным в linkedPurchaseToken , чтобы убедиться, что старый токен не используется для получения доступа к вашим услугам.

До истечения срока действия подписки - в игровом магазине

В то время как подписка отменена, но все еще активна, пользователи могут восстановить подписку в центре подписки Google Play, нажав ResubScribe (ранее восстановление ). Это сохраняет такую ​​же подписку и токен покупки.

раздел подписок в приложении Google Play Store с показом             Отмена подписки с кнопкой повторной подписки
Рисунок 8. Раздел «Учетная запись»> «Раздел подписок» в приложении Google Play Store, показывающая отмененную подписку с кнопкой повторной подписки .

Для получения дополнительной информации о восстановлении подписок см. В реставрации .

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

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

  • Чтобы предложить пользователям скидку, вы, возможно, захотите предложить идентификатор продукта со специальными ценами для вашей подписки, также называемой Winback Sku . Вы можете предоставить предложение в своем приложении, или вы можете уведомить пользователя о предложении за пределами приложения, например, в электронной почте.
  • Чтобы запустить подписку Winback, запустите поток покупок в вашем приложении Android, используя библиотеку Google Play Billing. Это тот же процесс, что и при новой подписке, но вы можете определить SKU, доступный для пользователя.
  • Если вы решите включить бесплатную пробную или вступительную цену в свой Winback Sku, убедитесь, что пользователь имеет право, не позволяя Unful One Free Trial Per App Box в консоли Google Play, которая ограничивает пользователя получением одного бесплатного пробного приложения.
  • Если пользователь повторно переписывается на одну и ту же SKU, он больше не имеет права на бесплатные испытания или вступительную цену. Убедитесь, что ваш пользовательский интерфейс отражает это.

Когда вы получаете токен покупки, обработайте покупку так же, как с новой подпиской. Вы не получите linkedPurchaseToken в ресурсе подписки.

После истечения срока действия подписки - в игровом магазине

Если они включены, пользователи могут переопределить в одном и том же SKU в течение одного года после истечения срока действия, нажав повторную подписку в центре подписок Google Play. Это генерирует новую подписку и токен покупки.

раздел подписок в приложении Google Play Store с показом             Отмена и срок действия подписки с повторной подписью и удалите             кнопки
Рисунок 9. Раздел «Учетная запись»> «Раздел подписок» в приложении Google Play Store, показывающая отмененную и истекшую подписку с кнопками RebScribe и удалением .

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

Продвигайте свою подписку

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

Для бесплатных испытаний Google Play проверяет, что у пользователя есть действительный способ оплаты, прежде чем начать бесплатную пробную версию. Некоторые пользователи могут рассматривать эту проверку в качестве удержания или платы за свой способ оплаты. Это удержание или заряд является временным, а впоследствии отменяется или возвращается.

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

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

Отменить, возвращать или отменить

Вы можете использовать API разработчика Google Play для отмены , возврата или отозвания подписки. Эта функциональность также доступна в консоли Google Play .

  • Отмена : Пользователи могут отменить подписку в Google Play. Вы также можете предоставить пользователям возможность отменить в вашем приложении или на вашем веб -сайте. Ваше приложение должно обрабатывать эти отмены, как описано при отмене .
  • Возврат : Когда вы возвращаетесь, пользователь может продолжать использовать подписку. Возврат может использоваться, если, например, была техническая ошибка, которая мешала пользователю получить доступ к вашему продукту, но ошибка была разрешена. Обратите внимание, что для возврата больше, чем самый последний платеж, или если вы хотите выпустить частичный возврат средств, вы должны использовать консоль Google Play.
  • Revoe : Когда вы отозваетесь, пользователь немедленно теряет доступ к подписке. Это можно использовать, если, например, была техническая ошибка, которая мешала пользователю получить доступ к вашему продукту, и пользователь не хочет продолжать использовать продукт. Ваше приложение должно обрабатывать эти отмены, как описано при от Revocations .

Следующая таблица иллюстрирует различия между отменой, возвратом и отменой.

Остановка обновления Вернуть деньги Отменить доступ
Отмена Да Нет Нет
Возвращать деньги Нет Да Нет
Отозвать Да Да Да

Отложить выставление счетов за подписчика

Вы можете продвинуть следующую дату выставления счетов для автопроизводного абонента с помощью Purchases.subscriptions:defer от API разработчика Google Play. В течение периода отсрочки пользователь подписывается на ваш контент с полным доступом, но не взимается. Дата продления подписки обновляется, чтобы отразить новую дату.

Для предоплаченных планов вы можете использовать API DEFER BILLING, чтобы отложить время истечения.

Отложенный биллинг позволяет сделать следующее:

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

Счета может быть отложены всего за один день и на один год за вызов API. Чтобы отложить выставление счетов еще дальше, вы можете снова позвонить в API, прежде чем появится новая дата выставления счетов.

Например, у Дарси ежемесячная подписка на онлайн -контент для приложения для рыбалки Quarterly. Обычно она выставляется в 1,25 фунтов стерлингов в первом из каждого месяца. В марте она участвовала в онлайн -опросе для издателя приложений. Издатель вознаграждает ее шестью свободными неделями, откладывая следующий платеж до 15 мая, который составляет шесть недель после того, как ее ранее запланированная дата выставления счетов 1 апреля. Дарси не взимается в течение апреля или начала мая и все еще имеет доступ к контенту. 15 мая ей взимают плату за подписку в 1,25 фунтов стерлингов за месяц. Ее следующая дата обновления сейчас 15 июня.

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

Обработка оплаты снижается

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

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

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

Вы можете указать продолжительность периода изящного базового плана и удерживаемого аккаунта в консоли Google Play. Указание длины меньше, чем значения по умолчанию, может уменьшить количество подписок, возмещенных после снижения платежей.

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

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

Обмен сообщениями в приложении

Если вы включили обмен сообщениями в приложении с InAppMessageCategoryId.TRANSACTIONAL , Google Play покажет обмен сообщениями пользователей в течение периода изящества и удержания учетной записи один раз в день и предоставит им возможность исправить свой платеж, не выходя из приложения.

Snackbar уведомил пользователя, чтобы исправить их оплату
Рисунок 20. Snackbar Уведомление пользователя о исправлении их оплаты.

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

Если пользователь успешно восстановил свою подписку, вы получите код ответа SUBSCRIPTION_STATUS_UPDATED вместе с токеном покупки. Затем вам следует использовать этот токен покупки, чтобы позвонить в API разработчика Google Play и обновить состояние подписки в вашем приложении.

Интегрировать обмен сообщениями в приложении

Чтобы показать сообщения в приложении для пользователя, используйте BillingClient.showInAppMessages() .

Вот пример запуска потока обмена сообщениями в приложении:

Котлин

val inAppMessageParams = InAppMessageParams.newBuilder()
        .addInAppMessageCategoryToShow(InAppMessageCategoryId.TRANSACTIONAL)
        .build()

billingClient.showInAppMessages(activity,
        inAppMessageParams,
        object : InAppMessageResponseListener() {
            override fun onInAppMessageResponse(inAppMessageResult: InAppMessageResult) {
                if (inAppMessageResult.responseCode == InAppMessageResponseCode.NO_ACTION_NEEDED) {
                    // The flow has finished and there is no action needed from developers.
                } else if (inAppMessageResult.responseCode
                        == InAppMessageResponseCode.SUBSCRIPTION_STATUS_UPDATED) {
                    // The subscription status changed. For example, a subscription
                    // has been recovered from a suspend state. Developers should
                    // expect the purchase token to be returned with this response
                    // code and use the purchase token with the Google Play
                    // Developer API.
                }
            }
        })

Ява

InAppMessageParams inAppMessageParams = InAppMessageParams.newBuilder()
        .addInAppMessageCategoryToShow(InAppMessageCategoryId.TRANSACTIONAL)
        .build();

billingClient.showInAppMessages(activity,
        inAppMessageParams,
        new InAppMessageResponseListener() {
            @Override
            public void onInAppMessageResponse(InAppMessageResult inAppMessageResult) {
                if (inAppMessageResult.responseCode
                        == InAppMessageResponseCode.NO_ACTION_NEEDED) {
                    // The flow has finished and there is no action needed from developers.
                } else if (inAppMessageResult.responseCode
                        == InAppMessageResponseCode.SUBSCRIPTION_STATUS_UPDATED) {
                    // The subscription status changed. For example, a subscription
                    // has been recovered from a suspend state. Developers should
                    // expect the purchase token to be returned with this response
                    // code and use the purchase token with the Google Play
                    // Developer API.
                }
            }
        });

Обработка подписки в ожидании транзакций

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

Изменение состояния подписки на первоначальную покупку с ожидающими транзакциями проста. Ваше приложение получает Purchase в PENDING состоянии, когда пользователь инициирует ожидающую транзакцию. Когда транзакция завершена, ваше приложение снова получает Purchase с обновлением штата для PURCHASED . Сообщение SubscriptionNotification с типом SUBSCRIPTION_PURCHASED покупается вашему клиенту RTDN. Следуйте нормальному процессу, чтобы проверить покупку, предоставьте пользователю доступ к контенту и подтвердите покупку. Если транзакция истекает или отменяется, сообщением SubscriptionNotification с типом SUBSCRIPTION_PENDING_PURCHASE_CANCELED отправляется вашему клиенту RTDN. В таких случаях пользователь никогда не должен был получить доступ к контенту.

Пополнение, обновление или понижение с ожидающими транзакциями включает в себя изменения состояния как для старых, так и для новых подписок. Когда пользователь инициирует ожидаемую пополнение, обновление или транзакцию понижения, ваше приложение получает Purchase для старой подписки с объектом PendingPurchaseUpdate . В настоящее время пользователь все еще владеет старой подпиской и еще не получил новую подписку. Вызов getProducts() и getPurchaseToken() на объекте PendingPurchaseUpdate возвращает идентификаторы продукта и токен покупки новой подписки. Когда транзакция будет завершена, ваше приложение получает Purchase с токеном покупки верхнего уровня для новой подписки и состояния, установленного для PURCHASED . Сообщение SubscriptionNotification с типом SUBSCRIPTION_PURCHASED покупается вашему клиенту RTDN. Только в настоящее время вы должны заменить старый токен покупки новым токеном покупки и обновить доступ пользователя к контенту. Если транзакция истекает или отменяется, сообщением SubscriptionNotification с типом SUBSCRIPTION_PENDING_PURCHASE_CANCELED отправляется вашему клиенту RTDN. В таких случаях пользователь все еще должен иметь доступ к содержанию старой подписки.

,

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

Если вы не настроили продукты для подписки для своего приложения, см. Создать и настроить свои продукты .

Обзор подписки

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

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

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

Для получения подробного обзора подписных продуктов, базовых планов и предложений см. Документацию в Центре справочной помощи Play Console .

Интеграция планов предоплаты

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

Для Top-Ups запустите биллинговый поток, как и с оригинальной покупкой. Вам не нужно указывать, что покупка-это пополнение.

Поверхности плана с предоплатой всегда используют режим замены замены CHARGE_FULL_PRICE , и вам не нужно явно устанавливать этот режим. Пользователь сразу же взимается в течение полного выставления счетов, и его право продлевается продолжительностью, указанной в пополнении.

После пополнения, следующие поля в объекте результата Purchase обновляются, чтобы отразить самую последнюю покупку вершины:

  • Идентификатор заказа
  • Время покупки
  • Подпись
  • Покупать токен
  • Признанный

Следующие поля Purchase всегда содержат те же данные, что и в исходной покупке:

  • Название пакета
  • Государство покупки
  • Продукты
  • Авто обновление

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

Подобно автоматическим подпискам, вы должны подтвердить планы предоплаты после покупки. Как первоначальная покупка, так и любые пополнения должны быть признаны. Для получения дополнительной информации см. Закупки обработки .

Из -за потенциала для коротких предоплаченных планов, важно как можно скорее подтвердить покупку.

Планы предоплаты с продолжительностью недели или дольше должны быть признаны в течение трех дней.

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

Подписки для рассрочки интеграция

Подписка в рассрочку - это тип подписки, когда пользователи платят за подписку в несколько рассрочки в течение определенного периода времени, а не платить всю плату за подписку заранее.

Дополнительные соображения для подписок в рассрочку:

  • Доступность страны : Функция подписки на рассрочку доступна только в Бразилии, Франции, Италии и Испании (Check Console для получения последней доступности).
  • Установка цены : при настройке цены для подписки в рассрочку на консоли цена представляет собой ежемесячную сумму платежа. Это, в сочетании с установленным периодом обязательств, генерирует общую сумму для подписки на экране покупки.
  • Период обязательств : общая продолжительность первоначального обязательства по подписке, в течение которых требуются ежемесячные платежи. Например, если базовый план имеет 15-месячный период обязательств, пользователь будет производить 15 ежемесячных платежей в течение этого периода.
  • Обновления : в контексте подписки на рассрочку «продление» означает заключение периода обязательств, либо начального периода обязательств, либо последующего периода обязательств. После первоначальной регистрации первое продление происходит после завершения всего начального периода обязательств. Последующие обновления происходят после выполнения каждого последующего периода обязательств. Типы обновлений для подписок в рассрочку могут быть «автопроизводными ежемесячными» или «автоматическими облегчениями для той же продолжительности». Для «Auto-Prenews Monthly» нет последующих обязательств, и план ведет себя как ежемесячная подписка, где каждый ежемесячный обвинение в подписке представляет собой обновление.
  • ПИТИНГИ ПИТИНГИ : В контексте подписок в рассрочку это относится к повторяющемуся интервалу, в котором производится индивидуальные платежи, как указано в базовом плане.
  • Изменение плана в зависимости от поведения с изменением цен : для изменений цен и отмены обязательство является твердым. Это означает, что если пользователь хочет отменить или разработчик хочет изменить цену, изменение вступает в силу в конце периода обязательств. Для изменений плана обязательство не является твердым. Это означает, что изменение плана не должно ждать до окончания периода обязательств, он вступит в силу либо немедленно, либо на следующую дату платежа на основе режима смены установки.
  • Изменение плана с одинаковым подписанием : План изменения от базового плана рассрочки в базовый план без установки одного и того же продукта подписки не допускается.
  • Уведомления разработчиков в режиме реального времени (RTDNS) : SUBSCRIPTION_CANCELLATION_SCHEDULED RTDN отправляется сразу после аннулированной отмены пользователя, когда платежи остаются за период обязательств. Отмена находится на рассмотрении и вступит в силу только в конце периода обязательств. Затем, если не восстановлено пользователем, SUBSCRIPTION_CANCELED и SUBSCRIPTION_EXPIRED rtdns отправляются в конце периода обязательств.

  • Выплаты / реализация доходов : выплаты разработчиков будут происходить, поскольку пользователи будут делать свои ежемесячные платежи, при условии тех же условий, что и все другие подписки. Разработчики не платят заранее, когда пользователь подписывает подписку на рассрочку.

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

  • Играть в библиотеку библиотеки : поле installmentDetails доступно только для PBL 7 или более поздней версии. Для PBL 5 и позже подписка в рассрочку возвращается с использованием queryProductDetails() , но подписка не будет включать подробную информацию в рассрочку, такую ​​как количество выплат плана.

Используйте глубокие ссылки, чтобы позволить пользователям управлять подпиской

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

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

Используйте следующий URL, чтобы направить пользователей на страницу, которая показывает все их подписки, как показано на рисунках 1 и 2:

https://play.google.com/store/account/subscriptions
На экране подписки на Play Store показывается статус для всех подписок пользователя Google Play.
Рисунок 1. На экране подписки на подписку на Play Store показывает статус для всех подписок пользователя Google Play Play.


Нажмите на подписку, чтобы увидеть дополнительную информацию.
Рисунок 2. Нажмите на подписку, чтобы увидеть дополнительные детали.

Эта глубокая ссылка может быть полезна, чтобы помочь пользователю восстановить отмененную подписку из центра подписок Play Store.

Чтобы напрямую ссылаться на страницу управления для невыполненной подписки, укажите имя пакета и productId связанные с приобретенной подпиской. Чтобы программно определить productId для существующей подписки, запросите бэкэнд вашего приложения или вызовите BillingClient.queryPurchasesAsync() для списка подписок, связанных с конкретным пользователем. Каждая подписка содержит соответствующий productId как часть информации о состоянии подписки. Каждый объект SubscriptionPurchaseLineItem PurchaseLineitem, связанный с покупкой подписки, содержит значение productId , связанное с подпиской, которую пользователь приобрел в этой позиции.

Используйте следующий URL, чтобы направить пользователей на определенный экран управления подпиской, заменив «свой и идентификатор» и « productId и пакета приложений» соответственно:

https://play.google.com/store/account/subscriptions?sku=your-sub-product-id&package=your-app-package

Затем пользователь может управлять своими методами оплаты и функциями доступа, включая отмену, повторную подписку и паузу.

Разрешить пользователям обновлять, понизить или изменить свою подписку

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

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

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

На рисунке 3 показан пример приложения с тремя различными планами:

Это приложение имеет три уровня подписки ..
Рисунок 3. Это приложение имеет три уровня подписки.

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

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

Режимы замены

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

Режим замены

Описание

Пример использования

Совершенные платежи, записанные в качестве оплачиваемых (для замены подписки на рассрочку)

WITH_TIME_PRORATION

Подписка модернизируется или понижена сразу. Каждый раз, когда оставшееся время корректируется в зависимости от разницы в цене и зачисляется на новую подписку, выдвигая следующую дату выставления счетов. Это поведение по умолчанию.

Обновите до более дорогого уровня, без какого -либо немедленного дополнительного платежа.

0

CHARGE_PRORATED_PRICE

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

Примечание. Этот вариант доступен только для обновления подписки, где увеличивается цена за единицу времени.

Обновите до более дорогого уровня, не изменяя дату выставления счетов.

1

CHARGE_FULL_PRICE

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

Примечание. Если новая подписка имеет бесплатное пробное или вступительное предложение, пользователю взимается 0 долл. США или цену вступительного предложения, в зависимости от того, что применяется, во время обновления или понижения.

Обновите с более короткого до более длительного периода выставления счетов.

1 (Примечание: 0 Если новая подписка имеет бесплатную пробную версию.)

WITHOUT_PRORATION

Подписка обновляется или сразу же понижена, а новая цена взимается при обновлении подписки. Биллинг -цикл остается прежним.

Обновите до более высокого уровня подписки при сохранении оставшегося свободного периода.

0

DEFERRED

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

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

Примечание. Для подписки на рассрочку изменение плана происходит в начале следующей даты оплаты.

Понизить до менее дорогого уровня.

1

Чтобы узнать больше о различных приложениях Upsell и Winback о предложениях обновления или понижения, прочитайте руководство по предложениям и рекламным акциям.

Установите режим замены для покупки

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

Переведите или переключайте планы в рамках одной и той же подписки

Вы можете указать режим замены по умолчанию в консоли Google Play. Эта настройка позволяет выбирать, когда заряжать текущие подписчики, если они приобретают другой базовый план или предложение для одной и той же подписки или повторной подписки после отмены. Доступные параметры взимаются немедленно , эквивалентны CHARGE_FULL_PRICE и заряжаются в следующую дату выставления счетов , что эквивалентно WITHOUT_PRORATION . Это единственные соответствующие режимы замены при переключении планов базовых планов в рамках одной и той же подписки.

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

Планы переключения по подписке или переопределить режим замены по умолчанию

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

Чтобы правильно предоставить SubscriptionUpdateParams , а также часть конфигурации потока покупки времени выполнения, обратите внимание на следующие ограничения:

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

Примеры замены и поведение

Чтобы понять, как работает каждый режим пропорции, рассмотрите следующий сценарий:

У Samwise есть подписка на онлайн -контент из приложения для садовника страны. У него ежемесячная подписка на версию контента 1-го уровня , которая является только текстом. Эта подписка стоит ему 2 доллара в месяц , и она продлевается в первом месяце.

15 апреля Samwise решила перейти на годовую версию подписки Tier 2 , которая включает в себя видео обновления и стоит 36 долларов в год .

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

WITH_TIME_PRORATION

Подписка Samwise's Tier 1 заканчивается немедленно. Поскольку он заплатил за полный месяц (1-30 апреля), но повысил рейтинг в середине периода подписки, к его новой подписке применяется пол месяца (1 доллар). Однако, поскольку эта новая подписка стоит 36 долл. США в год, кредитный баланс в размере 1 долл. США оплачивает всего 10 дней (16-25 апреля); Таким образом, 26 апреля ему взимается 36 долларов за новую подписку и еще 36 долларов 26 апреля каждого года.

Вам следует позвонить в приложение PurchasesUpdatedListener в тот момент, когда покупка успешна, и вы можете получить новую покупку в рамках вызова queryPurchasesAsync() . Ваш бэкэнд сразу же получает уведомление о разработчике в реальном времени SUBSCRIPTION_PURCHASED .

CHARGE_PRORATED_PRICE

Этот режим можно использовать, потому что цена подписки уровня 2 за время (36 долл. США/год = 3 долл. США в месяц) выше, чем цена подписки 1 -го уровня за единицу времени (2 долл. США в месяц). Подписка Samwise's Tier 1 заканчивается немедленно. Поскольку он заплатил за полный месяц, но использовал только половину, половина месяца подписки (1 доллар) применяется к его новой подписке. Однако, поскольку эта новая подписка стоит 36 долларов в год, оставшиеся 15 дней стоят 1,50 долл. США; Таким образом, ему взимается разница в 0,50 доллара за свою новую подписку. 1 мая Samwise взимается 36 долларов за его новый уровень подписки и еще 36 долларов 1 мая каждого года после следующего.

Вам следует позвонить в приложение PurchasesUpdatedListener в тот момент, когда покупка успешна, и вы можете получить новую покупку в рамках вызова queryPurchasesAsync() . Ваш бэкэнд сразу же получает уведомление о разработчике в реальном времени SUBSCRIPTION_PURCHASED .

WITHOUT_PRORATION

Подписка Samwise Tier 1 немедленно обновлена ​​до уровня 2 без дополнительной платы, и 1 мая ему взимается 36 долларов за его новый уровень подписки и еще 36 долларов 1 мая каждого года после следующего.

Вам следует позвонить в приложение PurchasesUpdatedListener в тот момент, когда покупка успешна, и вы можете получить новую покупку в рамках вызова queryPurchasesAsync() . Ваш бэкэнд сразу же получает уведомление о разработчике в реальном времени SUBSCRIPTION_PURCHASED .

DEFERRED

Подписка Samwise's Tier 1 продолжается до истечения срока действия 30 апреля. 1 мая подписка на уровень 2 -го уровня вступает в силу, и Samwise взимается 36 долларов США за его новый уровень подписки.

You should call your app's PurchasesUpdatedListener the moment the purchase succeeds, and you are able to retrieve the new purchase as part of a queryPurchasesAsync() call. Your backend immediately receives a SUBSCRIPTION_PURCHASED Real Time Developer Notification. You should process the purchase the same way you would process any other new purchase at that point. In particular, make sure you acknowledge the new purchase. Note that the startTime of the new subscription is populated at the moment the replacement is effective, which happens when the old subscription expires. At that point, you receive a SUBSCRIPTION_RENEWED RTDN for the new subscription plan. Read more about the ReplacementMode.DEFERRED behavior in Handle deferred replacement .

CHARGE_FULL_PRICE

Samwise's Tier 1 subscription ends immediately. His Tier 2 subscription begins today and he is charged $36. Because he paid for a full month but used only half of it, half of a month's subscription ($1) is applied to his new subscription. Because that new subscription costs $36/year, he would get 1/36th of a year added on to his subscription period (~10 days). Therefore, Samwise's next charge would be 1 year and 10 days from today for $36. After that, he is charged $36 each year following.

When choosing a proration mode, be sure to review our replacement recommendations .

Trigger subscription changes in-app

Your app can offer users an upgrade or downgrade using the same steps as with launching a purchase flow . However, when upgrading or downgrading, you need to provide details for the current subscription, the future (upgraded or downgraded) subscription, and the replacement mode to use, as shown in the following example:

Котлин

val offerToken = productDetails
        .getSubscriptionOfferDetails(selectedOfferIndex)
        .getOfferToken()

val billingParams = BillingFlowParams.newBuilder().setProductDetailsParamsList(
       listOf(
           BillingFlowParams.ProductDetailsParams.newBuilder()
               .setProductDetails(productDetails)
               .setOfferToken(offerToken)
               .build()
       )
       ).setSubscriptionUpdateParams(
           BillingFlowParams.SubscriptionUpdateParams.newBuilder()
               .setOldPurchaseToken("old_purchase_token")
               .setSubscriptionReplacementMode(
                 BillingFlowParams.ReplacementMode.CHARGE_FULL_PRICE
               )
               .build()
       ).build()

billingClient.launchBillingFlow(
    activity,
    billingParams
   )
// ...

Ява

String offerToken = productDetails
    .getSubscriptionOfferDetails(selectedOfferIndex)
    .getOfferToken();

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(
        ImmuableList.of(
            ProductDetailsParams.newBuilder()
                // fetched via queryProductDetailsAsync
                .setProductDetails(productDetails)
                // offerToken can be found in
                // ProductDetails=>SubscriptionOfferDetails
                .setOfferToken(offerToken)
                .build()))
    .setSubscriptionUpdateParams(
        SubscriptionUpdateParams.newBuilder()
            // purchaseToken can be found in Purchase#getPurchaseToken
            .setOldPurchaseToken("old_purchase_token")
            .setSubscriptionReplacementMode(ReplacementMode.CHARGE_FULL_PRICE)
            .build())
    .build();

BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
// ...

Replacement recommendations

The following table shows diferrent proration scenarios along with what we recommend for each scenario:

Scenario Recommended replacement mode Результат
Upgrading to a more expensive tier CHARGE_PRORATED_PRICE The user receives access immediately while keeping the same billing period.
Downgrading to a less expensive tier DEFERRED The user already paid for the more expensive tier, so they keep access until the next billing date.
Upgrading while in a free trial, keeping the trial WITHOUT_PRORATION The user upgrades to a higher tier for the remainder of the trial period without extra charge.
Upgrading while in a free trial - ending access to the free trial CHARGE_PRORATED_PRICE The user receives access to the new tier immediately, the remaining value of the free trial is carried over. The carried over value is calculated based on base plan pricing.

Handle subscription change purchases

Changes of plan are new purchases for all terms and purposes, and they should be processed and acknowledged as such after the billing flow completes successfully. In addition to processing the new purchase appropriately, you have to retire the purchase that is being replaced.

The in-app behavior is the same as for any new purchase. Your app receives the outcome of the new purchase in your PurchasesUpdatedListener , and the new purchase is available in queryPurchasesAsync .

The Google Play Developer API returns a linkedPurchaseToken in the subscription resource when a purchase replaces an existing one. Be sure to invalidate the token provided in the linkedPurchaseToken to ensure that the old token is not used to gain access to your services. See Upgrades, downgrades, and resignups for information on handling upgrade and downgrade purchases.

When you receive the new purchase token, follow the same verification process as with verifying a new purchase token . Make sure to acknowledge these purchases with BillingClient.acknowledgePurchase() from the Google Play Billing Library or Purchases.subscriptions:acknowledge from the Google Play Developer API.

Handle deferred replacement

Deferred replacement mode lets you let a user use up the remaining entitlement in their old plan before starting on the new plan.

When you use ReplacementMode.DEFERRED for a new purchase, queryPurchasesAsync() returns a new purchase token after the purchase flow that remains associated with the old product until the deferred replacement takes place on the next renewal date, after which the new product is returned.

In the past you could achieve this user experience with the deprecated ProrationMode.DEFERRED , but ProrationMode.DEFERRED is deprecated with Play Billing Library 6. See the following table to understand where the behavior differs:

Время

ProrationMode.DEFERRED (deprecated)

ReplacementMode.DEFERRED

Right after the purchase flow succeeds (app)

PurchasesUpdatedListener is invoked after purchase with a status of whether the upgrade or downgrade was successful.

Entitlement to the old plan continues until the next renewal date. To ensure that the app gives the right entitlement, queryPurchasesAsync() returns a Purchase object with the original purchase token and the original entitlement until replacement occurs.

The new purchase token is not surfaced, so it can't be processed at this point.

PurchasesUpdatedListener gets invoked after purchase with a status of whether the upgrade or downgrade was successful.

queryPurchasesAsync() returns purchase with the new purchase token right away, and the original entitlement associated with it.

The new purchase token is surfaced, so it should be processed at this point taking into account when the replacement is to take place.

Right after the purchase flow succeeds (backend)

SUBSCRIPTION_PURCHASED RTDN is not sent after the purchase flow. The backend is not made aware of the new purchase yet.

SUBSCRIPTION_PURCHASED RTDN with the old product_id is sent immediately after the purchase flow for the new purchase token.

Calling the purchases.subscriptionsv2.get method with the new purchase token returns a purchase having a 'startTime' indicating the purchase time with two line items :

  • One representing the old entitlement and has an 'expiryTime' in the future. The old entitlement will not be renewed and has a DeferredItemReplacement containing the product of the new entitlement. This indicates a pending replacement of the old entitlement upon its expiration.
  • One representing the newly purchased entitlement. It has no value set for 'expiryTime'.

SUBSCRIPTION_EXPIRED sent for the old purchase token. When calling the purchases.subscriptionsv2.get method with the old purchase token, it appears as expired (the entitlement for the old plan is transferred to the new purchase for the remaining time).

On replacement - first renewal after the purchase flow (app)

queryPurchasesAsync() returns a new Purchase object with the new purchase token and entitlement.

The new purchase token is now surfaced, so it should be processed .

queryPurchasesAsync() returns purchase with the new purchase token right away, and the new entitlement associated with it.

The new purchase should have been processed already when the purchase flow succeeded, so the app shouldn't take any special action apart from making sure the right entitlement is granted.

On replacement - first renewal after the purchase flow (backend)

The new purchase can now be processed and acknowledged when the first SUBSCRIPTION_RENEWED RTDN is sent.

The linkedPurchaseToken in the subscription resource can be used to determine which user in your subscription backend, if applicable, should be updated with the new entitlement.

New purchase was processed and acknowledged when the SUBSCRIPTION_PURCHASED RTDN was sent for the new purchase token and recorded as the 'startTime'.

With ReplacementMode.DEFERRED, first renewals follow the standard behavior of any other renewal and you don't need to handle special logic for replacements when this event happens.

When calling the purchases.subscriptionsv2.get method with the new purchase token returns a purchase with two line items :

  • One representing the old entitlement, with an `expiryTime` in the past and no set value for DeferredItemReplacement .
  • One representing the new entitlement, with an `expiryTime` in the future and the auto_renewing_enabled flag turned on.

ReplacementMode.DEFERRED should be used from now on instead of the deprecated ProrationMode.DEFERRED, as it presents the same behavior regarding entitlement changes, but offers a way to manage the purchase that is more consistent with behaviors for other new purchases.

Customer management

Using Real-time developer notifications, you can detect in real time when a user decides to cancel. When a user cancels, but before their subscription has expired, you can send them push notifications or in-app messages to ask them to resubscribe.

After a user has cancelled their subscription, you can try to win them back either in your app, or through the Play store. The following table describes various subscription scenarios along with associated winback actions and app requirements.

Before subscription expiration After subscription expiration
In-app In Play Store In-app In Play Store
Winback feature In-app subscription Восстановить In-app subscription Resubscribe
User goes through checkout flow Да Нет Да Да
User subscription remains associated with the same SKU User can sign up for same or different SKU Да User can sign up for same or different SKU Да
Creates new purchase token Да Нет Да Да
Enabled by default Нет Yes, support required for all devs Нет

Apps without Billing Library 2.0+: No

Apps with Billing Library 2.0+: Yes. Devs can opt-out in Console.

When user is charged

If using same SKU: end of current billing period.

If using different SKU: depends on proration mode.

End of current billing period Немедленно Немедленно
Implementation required Provide a re-signup UI in your app

Detect change in subscription state

Deep-link to Play Store

Provide a re-signup UI in your app Handle out-of-app purchases

Before subscription expiration - in-app

For subscriptions that have been canceled but have not yet expired, you can allow subscribers to restore their subscription within your app by applying the same in-app product purchase flow as for new subscribers. Ensure your UI reflects that the user has an existing subscription. For example, you might want to display the user's current expiration date and recurring price with a Reactivate button.

Most of the time, you will want to offer the user the same price and SKU they were already subscribed to, as follows:

  • Initiate a new subscription purchase with the same SKU.
  • The new subscription replaces the old one and renews on the same expiration date. The old subscription is immediately marked as expired.
  • As an example, Achilles has a subscription to Example Music App, and the subscription is due to expire on August 1. On July 10, he resubscribes to the one-month subscription at the same price per month. The new subscription is prorated with the remaining credit, is immediately active, and still renews on August 1.

If you would like to offer a different price—for example a new free trial or a winback discount—you can instead offer a different SKU to the user:

  • Initiate an upgrade or downgrade with the different SKU using the replacement mode WITHOUT_PRORATION .
  • The new subscription replaces the old one and renews on the same expiration date. The user is charged the price of the new SKU, including any introductory prices, on the original expiration date. If the old subscription was created using an obfuscated account id, that same id should be passed to the BillingFlowParams for upgrades and downgrades.
  • As an example, Achilles has a subscription to Example Music App, and the subscription is due to expire on August 1. On July 10, he resubscribes to an annual subscription with an introductory price. The new subscription is immediately active, and the user is charged the introductory price on August 1.
  • If you decide to include a free trial or intro price in your winback SKU, ensure that the user is eligible by unchecking the Allow one free trial per app box in the Google Play Console, which restricts the user to getting one free trial per app.

When you receive the purchase token, process the purchase just as you would with a new subscription. Additionally, the Google Play Developer API returns a linkedPurchaseToken in the subscription resource. Be sure to invalidate the token provided in the linkedPurchaseToken to ensure that the old token is not used to gain access to your services.

Before subscription expiration - in Play Store

While the subscription is canceled but still active, users can restore the subscription in the Google Play subscriptions center by clicking Resubscribe (previously Restore ). This keeps the same subscription and purchase token.

subscriptions section in the google play store app showing a
            cancelled subscription with a resubscribe button
Figure 8. Account > Subscriptions section in the Google Play Store app showing a cancelled subscription with a Resubscribe button.

For more information on restoring subscriptions, see Restorations .

After subscription expiration - in-app

You can allow expired subscribers to resubscribe within your app by applying the same in-app product purchase flow as for new subscribers. Note the following:

  • To offer users a discount, you might want to offer a product ID with special pricing for your subscription, also called a winback SKU . You can provide the offer in your app, or you can notify the user of the offer outside of the app, such as in email.
  • To start a winback subscription, launch the purchase flow in your Android app using the Google Play Billing Library. This is the same process as with a new subscription, but you can determine the SKU that is available to the user.
  • If you decide to include a free trial or intro price in your winback SKU, ensure that the user is eligible by unchecking the Allow one free trial per app box in the Google Play Console, which restricts the user to getting one free trial per app.
  • If the user resubscribes to the same SKU, they are no longer eligible for free trials or introductory price. Ensure that your UI reflects this.

When you receive the purchase token, process the purchase just as you would with a new subscription. You will not receive a linkedPurchaseToken in the subscription resource.

After subscription expiration - in Play Store

If enabled, users can resubscribe to the same SKU for up to one year after expiration by clicking Resubscribe in the Google Play subscriptions center. This generates a new subscription and purchase token.

subscriptions section in the google play store app showing a             cancelled and expired subscription with resubscribe and remove             кнопки
Figure 9. Account > Subscriptions section in the Google Play Store app showing a cancelled and expired subscription with Resubscribe and Remove buttons.

Resubscribing is considered an out-of-app purchase, so be sure to follow best practices for handling purchases made from outside your app .

Promote your subscription

You can create promotion codes to give selected users an extended free trial to an existing subscription. To learn more, see Promo codes .

For free trials, Google Play verifies that the user has a valid payment method before starting the free trial. Some users may see this verification as a hold or charge on their payment method. This hold or charge is temporary and is later reversed or refunded.

After the trial period ends, the user's payment method is charged for the full subscription amount.

If a user cancels a subscription at any time during the free trial, the subscription remains active until the end of the trial, and they aren't charged when the free trial period ends.

Cancel, refund, or revoke

You can use the Google Play Developer API to cancel , refund , or revoke a subscription. This functionality is also available in the Google Play Console .

  • Cancel : Users can cancel a subscription on Google Play. You can also provide an option for users to cancel in your app or on your website. Your app should handle these cancellations as described in Cancellations .
  • Refund : When you refund, the user can continue to use the subscription. Refunds can be used if, for example, there was a technical error that prevented the user from accessing your product, but the error has been resolved. Note that to refund more than the most recent payment, or if you want to issue a partial refund, you must use the Google Play Console.
  • Revoke : When you revoke, the user immediately loses access to the subscription. This can be used if, for example, there was a technical error that prevented the user from accessing your product, and the user does not want to continue using the product. Your app should handle these cancellations as described in Revocations .

The following table illustrates the differences between cancel, refund, and revoke.

Stops renewal Refund money Revoke access
Отмена Да Нет Нет
Возвращать деньги Нет Да Нет
Отозвать Да Да Да

Defer billing for a subscriber

You can advance the next billing date for an auto-renewing subscriber by using Purchases.subscriptions:defer from the Google Play Developer API. During the deferral period, the user is subscribed to your content with full access but is not charged. The subscription renewal date is updated to reflect the new date.

For prepaid plans, you can use the defer billing API to defer the expiration time.

Deferred billing allows you to do the following:

  • Give users free access as a special offer, such as giving one week free for purchasing a movie.
  • Give free access to customers as a gesture of goodwill.

Billing can be deferred by as little as one day and by as long as one year per API call. To defer the billing even further, you can call the API again before the new billing date arrives.

As an example, Darcy has a monthly subscription to online content for the Fishing Quarterly app. She is normally billed £1.25 on the first of each month. In March, she participated in an online survey for the app publisher. The publisher rewards her with six free weeks by deferring the next payment until May 15, which is six weeks after her previously scheduled billing date of April 1. Darcy is not charged for April or the beginning of May and still has access to the content. On May 15, she is charged the normal £1.25 subscription fee for the month. Her next renewal date is now June 15.

When deferring, you might want to notify the user by email or within the app to notify them that their billing date has changed.

Handling payment declines

If there are payment issues with a subscription renewal, Google will periodically attempt to renew the subscription for some time before canceling. This recovery period can consists of a grace period, followed by an account hold period. During this time, Google sends the user emails and notifications prompting them to update their payment method.

Upon payment decline, the subscription enters a grace period if one is configured. During the grace period, you should ensure the user still has access to the subscription entitlements.

After any grace period has ended, the subscription enters an account hold period. During account hold, you should ensure the user does not have access to the subscription entitlements.

You can specify the length of each auto-renewing base plan's grace period and account hold in the Google Play Console. Specifying lengths less than the default values may reduce the number of subscriptions recovered from payment declines.

To maximize the likelihood of subscription recovery during a payment decline, you can inform your user of a payment issue and ask them to fix it.

You can either do this yourself, as described in the grace period and account hold sections, or you can implement the in-app messaging API, where Google shows a message to users in your app.

In-app messaging

If you've enabled in-app messaging with InAppMessageCategoryId.TRANSACTIONAL , Google Play will show users messaging during grace period and account hold once per day and provide them an opportunity to fix their payment without leaving the app.

Snackbar notifying the user to fix their payment
Figure 20. Snackbar notifying the user to fix their payment.

We recommend that you call this API whenever the user opens the app to determine whether the message should be shown.

If the user successfully recovered their subscription, you will receive a response code of SUBSCRIPTION_STATUS_UPDATED along with a purchase token. You should then use this purchase token to call the Google Play Developer API and refresh the subscription status in your app.

Integrate in-app messaging

To show in-app messaging to user, use BillingClient.showInAppMessages() .

Here is an example of triggering the in-app messaging flow:

Котлин

val inAppMessageParams = InAppMessageParams.newBuilder()
        .addInAppMessageCategoryToShow(InAppMessageCategoryId.TRANSACTIONAL)
        .build()

billingClient.showInAppMessages(activity,
        inAppMessageParams,
        object : InAppMessageResponseListener() {
            override fun onInAppMessageResponse(inAppMessageResult: InAppMessageResult) {
                if (inAppMessageResult.responseCode == InAppMessageResponseCode.NO_ACTION_NEEDED) {
                    // The flow has finished and there is no action needed from developers.
                } else if (inAppMessageResult.responseCode
                        == InAppMessageResponseCode.SUBSCRIPTION_STATUS_UPDATED) {
                    // The subscription status changed. For example, a subscription
                    // has been recovered from a suspend state. Developers should
                    // expect the purchase token to be returned with this response
                    // code and use the purchase token with the Google Play
                    // Developer API.
                }
            }
        })

Ява

InAppMessageParams inAppMessageParams = InAppMessageParams.newBuilder()
        .addInAppMessageCategoryToShow(InAppMessageCategoryId.TRANSACTIONAL)
        .build();

billingClient.showInAppMessages(activity,
        inAppMessageParams,
        new InAppMessageResponseListener() {
            @Override
            public void onInAppMessageResponse(InAppMessageResult inAppMessageResult) {
                if (inAppMessageResult.responseCode
                        == InAppMessageResponseCode.NO_ACTION_NEEDED) {
                    // The flow has finished and there is no action needed from developers.
                } else if (inAppMessageResult.responseCode
                        == InAppMessageResponseCode.SUBSCRIPTION_STATUS_UPDATED) {
                    // The subscription status changed. For example, a subscription
                    // has been recovered from a suspend state. Developers should
                    // expect the purchase token to be returned with this response
                    // code and use the purchase token with the Google Play
                    // Developer API.
                }
            }
        });

Handle subscription pending transactions

Pending transactions can happen in initial purchase, top-up, upgrade or downgrade. The subscription purchase starts with the SUBSCRIPTION_STATE_PENDING state before transitioning to SUBSCRIPTION_STATE_ACTIVE . If the transaction is expired or canceled by the user, it goes to SUBSCRIPTION_STATE_PENDING_PURCHASE_EXPIRED . You must and should only update the user's entitlement after the transaction is completed.

Subscription state change for initial purchase with pending transactions is straightforward. Your app receives a Purchase with PENDING state when the user initiates a pending transaction. When the transaction is completed, your app receives the Purchase again with state updated to PURCHASED . A SubscriptionNotification message with type SUBSCRIPTION_PURCHASED is sent to your RTDN client. Follow the normal process to verify the purchase, give the user access to the content and acknowledge the purchase. If the transaction expires or is canceled, a SubscriptionNotification message with type SUBSCRIPTION_PENDING_PURCHASE_CANCELED is sent to your RTDN client. In such cases, the user should never have gained access to the content.

Top-up, upgrade or downgrade with pending transactions involves state changes for both the old and new subscriptions. When the user initiates a pending top-up, upgrade or downgrade transaction, your app receives a Purchase for the old subscription with a PendingPurchaseUpdate object. At this time, the user is still owning the old subscription and has not gained the new subscription yet. Calling getProducts() and getPurchaseToken() on the PendingPurchaseUpdate object returns the product ids and purchase token of the new subscription. When the transaction is completed, your app receives a Purchase with the top-level purchase token set for the new subscription and the state set to PURCHASED . A SubscriptionNotification message with type SUBSCRIPTION_PURCHASED is sent to your RTDN client. Only at this time, you should replace the old purchase token with the new purchase token and update the user's access to the content. If the transaction expires or is canceled, a SubscriptionNotification message with type SUBSCRIPTION_PENDING_PURCHASE_CANCELED is sent to your RTDN client. In such cases, the user should still have access to the content of the old subscription.