Жизненный цикл подписки

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

Управление жизненным циклом автоматически возобновляемых подписок

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

Рисунок 1. Состояния жизненного цикла и события перехода для покупок с автоматическим продлением подписки.

Чтобы обновить состояние в своем серверном интерфейсе, вызовите API purchases.subscriptionsv2.get , указав токен покупки, включенный в уведомление. Эта конечная точка предоставляет последнее состояние подписки с учетом токена покупки и считается источником достоверной информации для управления подпиской.

Токен покупки действителен с момента регистрации подписки до 60 дней после истечения срока действия. После этой даты токен покупки больше нельзя использовать для вызова API разработчика Google Play.

Новые покупки подписки с автоматическим продлением

Когда пользователь приобретает подписку, вашему клиенту RTDN отправляется сообщение SubscriptionNotification с типом SUBSCRIPTION_PURCHASED . Независимо от того, получили ли вы это уведомление или зарегистрировали новую покупку в приложении через PurchasesUpdatedListener или вручную извлекли покупки с помощью метода onResume() вашего приложения, вам следует обработать новую покупку в своем безопасном бэкэнде. Для этого выполните следующие действия:

  1. Запросите конечную точку purchases.subscriptionsv2.get , чтобы получить ресурс подписки , содержащий последнее состояние подписки.
  2. Убедитесь, что значение поля subscriptionState равно SUBSCRIPTION_STATE_ACTIVE .
  3. Подтвердите покупку .
  4. Предоставьте пользователю доступ к контенту. Учетную запись пользователя, связанную с покупкой, можно идентифицировать с помощью объекта ExternalAccountIdentifiers из ресурса подписки, если идентификаторы были установлены во время покупки с помощью setObfuscatedAccountId и setObfuscatedProfileId .

Библиотека выставления счетов Play также включает метод подтверждения подписки acknowledgePurchase() и метод проверки статуса подтверждения isAcknowledged() . Однако мы рекомендуем вам обрабатывать покупки на своем сервере для повышения безопасности.

Ресурс подписки для новых покупок выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  "startTime": "2022-04-22T18:39:58.270Z",
  "regionCode": "US",
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "latestOrderId": "GPA.3333-4137-0319-36762",
  "acknowledgementState": "ACKNOWLEDGEMENT_STATE_PENDING", // need to acknowledge new purchases
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      }
    }
  ],
}

Продление подписки

Для подписок без рассрочки и с автоматическим продлением при продлении подписки отправляется уведомление SUBSCRIPTION_RENEWED . Для подписок в рассрочку уведомление SUBSCRIPTION_RENEWED отправляется каждый раз, когда за подписку взимается плата в дату выставления счета. Убедитесь, что у пользователя по-прежнему есть право на подписку, а затем обновите состояние подписки, указав новое expiryTime , указанное в ресурсе подписки, возвращенном из API разработчика Google Play. Ресурс подписки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  "startTime": "2022-04-22T18:39:58.270Z",
  "regionCode": "US",
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "latestOrderId": "GPA.3333-4137-0319-36762",
  "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      }
    }
  ]
}

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

Льготный период

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

Метод queryPurchasesAsync() продолжает возвращать покупки, для которых действует льготный период. Если ваше приложение использует исключительно queryPurchasesAsync для проверки того, имеет ли пользователь право на подписку, тогда ваше приложение должно автоматически обрабатывать льготные периоды, поскольку эти подписки отображаются как активные в библиотеке выставления счетов Play.

Синхронизация состояния подписки с вашей серверной частью позволяет вам быть более осведомленным об отклонениях платежей и дает вам больше контекста, когда вы пытаетесь уменьшить непроизвольный отток. Прослушивайте сообщения SubscriptionNotification с типом SUBSCRIPTION_IN_GRACE_PERIOD , чтобы получать уведомления, когда пользователь вступает в льготный период. Пока пользователь находится в льготном периоде, ресурс подписки содержит autoRenewEnabled = true . Google Play динамически продлевает значение expiryTime до истечения льготного периода, поскольку право должно действовать до тех пор, пока пользователь не отменит его или пока льготный период не продлится до максимальной продолжительности. Значение поля subscriptionState в течение этого периода — SUBSCRIPTION_STATE_IN_GRACE_PERIOD . Ресурс подписки выглядит примерно так, как показано в следующем примере:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_IN_GRACE_PERIOD",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_future,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      }
    }
  ],
}

Play информирует пользователей, находящихся в льготном периоде, о том, что их платеж был отклонен, и предлагает им исправить проблемы со способом оплаты в Play Store. Когда пользователь вступает в льготный период, вы также должны предложить ему исправить свой способ оплаты на случай, если сбой был непреднамеренным. Самый простой способ сделать это — использовать API обмена сообщениями в приложении . Если вы вызываете этот API, когда пользователь открывает ваше приложение, на временной панели снэк-бара ему отображается сообщение Play, информирующее пользователя о том, что его платеж отклонен. Это сообщение также содержит глубокую ссылку, по которой пользователь может исправить свой способ оплаты в Google Play.

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

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

Льготный период доступа и восстановления

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

Рисунок 2. График подписки, которая вступает в льготный период и восстанавливается до его окончания.

Важно помнить следующие моменты:

  • В течение льготного периода пользователь должен сохранять доступ к преимуществам подписки.
  • Когда подписка восстанавливается в течение льготного периода, дата продления не сбрасывается.
  • Если вы увеличите льготный период — например, с 7 дней до 14 дней, — пользователи, находящиеся в льготном периоде, получат расширенный доступ к преимуществам подписки.
  • Если вы уменьшите льготный период, у пользователей, у которых старый льготный период прошел достаточно далеко, чтобы превысить новый льготный период, будут немедленно аннулированы преимущества подписки. Например, если вы уменьшите льготный период с 14 до 7 дней, у пользователей, находящихся на 8–14 днях старого льготного периода, преимущества подписки будут немедленно аннулированы.
  • Подписка остается в активном состоянии, и вы не получите льготный период RTDN, пока не закончится льготный период молчания.

Тихий льготный период

Вы можете установить льготный период в 0 дней, но Play будет ждать минимум 1 день, чтобы обеспечить достаточно времени для повторных попыток оплаты. Этот молчаливый льготный период обеспечивает безопасность при обработке платежей. В течение этого 24-часового периода подписка остается в ACTIVE состоянии .

Лучший способ синхронизировать изменения состояния подписки — прослушивать уведомления разработчиков в режиме реального времени (RTDN) и реагировать на них. Вызовите метод purchases.subscriptionsv2.get() во время RTDN, а не во время истечения срока действия, чтобы получить более точный статус подписки.

В зависимости от статуса подписки после 24-часового льготного периода молчания вы должны получить одно из следующих уведомлений:

  • SUBSCRIPTION_ON_HOLD (если включено)
  • SUBSCRIPTION_CANCELED (в случае отмены)
  • SUBSCRIPTION_EXPIRED (если срок действия истек)
  • SUBSCRIPTION_RENEWED (при успешном продлении)

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

Блокировка счета

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

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

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

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

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

При использовании уведомлений для разработчиков в режиме реального времени вы получаете сообщение SubscriptionNotification с типом SUBSCRIPTION_ON_HOLD , когда подписка блокируется. Вызовите метод purchases.subscriptionsv2.get со своего защищенного внутреннего сервера, чтобы получить информацию о новой подписке. Во время удержания учетной записи поле expiryTime ресурса подписки устанавливается на прошлую временную метку, а поле subscriptionState устанавливается на SUBSCRIPTION_STATE_ON_HOLD :

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ON_HOLD",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_past,
      ...
    }
  ],
}

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

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

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

После восстановления библиотека платежей Play снова возвращает подписку с помощью метода queryPurchasesAsync() . Если вы используете этот метод, чтобы определить, имеет ли пользователь право на подписку, ваше приложение должно автоматически обрабатывать восстановление подписки после блокировки учетной записи.

Прослушайте сообщение SubscriptionNotification с типом SUBSCRIPTION_RECOVERED чтобы получить уведомление, когда подписка будет восстановлена ​​и пользователь должен восстановить доступ. Если вы запросите подписку после получения этого уведомления, в поле expiryTime будет установлена ​​временная метка в будущем, а в поле subscriptionState снова будет установлено значение SUBSCRIPTION_STATE_ACTIVE :

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      ...
    }
  ],
}

Если пользователь не исправит свой способ оплаты до окончания периода удержания учетной записи, вместо этого вы получите RTDN с типом SUBSCRIPTION_CANCELED . Инструкции по обработке отмены см. в разделе «Отмены» . Когда вы запрашиваете подписку, которая была отменена таким образом, в возвращаемом поле expiryTime устанавливается прошедшая временная метка:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_CANCELED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_past,
      ...
    }
  ],
}

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

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

Доступ к заблокированному аккаунту и восстановление

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

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

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

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

Важно помнить следующие моменты:

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

Сроки годности

По истечении срока действия подписки пользователь потеряет доступ к подписке. В этом случае отправляется сообщение SubscriptionNotification типа SUBSCRIPTION_EXPIRED . Получив это уведомление, запросите API разработчика Google Play, чтобы получить последний ресурс подписки . После того, как вы подтвердите, что subscriptionState имеет SUBSCRIPTION_STATE_EXPIRED , удалите право и зарегистрируйте состояние покупки как недействительное в своем серверном интерфейсе. Ресурс подписки выглядит примерно так, как показано в следующем примере:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_EXPIRED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": expiration_time_in_past,
      ...
    }
  ],
}

Отмены

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

При отмене подписки без рассрочки с автоматическим продлением отображается уведомление SUBSCRIPTION_CANCELED . Когда вы получаете это уведомление, ресурс подписки , возвращаемый из API разработчика Google Play, имеет поле subscriptionState со значением SUBSCRIPTION_STATE_CANCELED , а поле expiryTime содержит дату, когда пользователь должен потерять доступ к подписке. Если эта дата уже в прошлом, пользователь должен немедленно потерять право. Это может произойти, например, если пользователь отменяет подписку при блокировке аккаунта из-за отклонения платежа.

Ресурс подписки для отмененной покупки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_CANCELED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": expiration_time,
      ...
    }
  ],
}

Для подписок в рассрочку уведомление SUBSCRIPTION_CANCELLATION_SCHEDULED отправляется при отмене по инициативе пользователя, когда платежи остаются в течение периода действия обязательств. Отмена находится на рассмотрении и вступит в силу в конце текущего периода действия обязательств. Когда вы получаете это уведомление, ресурс подписки, возвращенный из API разработчика Google Play, имеет поле subscribeState, установленное в значение SUBSCRIPTION_STATE_ACTIVE поскольку подписка в рассрочку все еще активна до конца периода действия обязательств. Однако существует пустой объект pendingCancellation. В конце периода действия обязательств отправляется уведомление SUBSCRIPTION_CANCELED , за которым следует SUBSCRIPTION_EXPIRED .

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

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_plan01",
      "expiryTime": expiration_time,
      "autoRenewingPlan": {
        "autoRenewEnabled": true,
        "recurringPrice": {
          "currencyCode": "USD",
          "units": "1",
          "nanos": 990000000
        },
        "installmentDetails": {
          "initialCommittedPaymentsCount": 6,
          "remainingCommittedPaymentsCount": 5,
          "pendingCancellation": {}
      ...
        }
      }
    }
  ],
}

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

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

Отзыв

Подписка может быть отозвана по разным причинам, включая отзыв подписки вашей серверной частью с помощью purchases.subscriptionsv2.revoke или возврат средств за покупку. В этой ситуации немедленно отзовите право пользователя. В этом случае отправляется сообщение SubscriptionNotification с типом SUBSCRIPTION_REVOKED . Когда вы получаете это уведомление, ресурс подписки , возвращенный из API разработчика Google Play, имеет поле subscriptionState , имеющее значение SUBSCRIPTION_STATE_EXPIRED .

Ресурс подписки для отозванной покупки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_EXPIRED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": expiration_time,
      ...
    }
  ]
}

Отложенные подписки

Существует множество причин, по которым вам может потребоваться расширить права пользователя. Например, вы можете предложить пользователям бесплатный доступ в качестве специальной акции, например предоставить одну неделю бесплатно за покупку фильма или предоставить бесплатный доступ клиентам в качестве жеста доброй воли. Вы можете использовать метод purchases.subscriptions.defer из Play Developer API, чтобы перенести следующую дату выставления счета для автоматически возобновляемой подписки. При этом отправляется сообщение SubscriptionNotification типа SUBSCRIPTION_DEFERRED . В течение периода отсрочки пользователь подписывается на ваш контент с полным доступом, но за него не взимается плата. Дата продления подписки обновляется и отражает новую дату.

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

Ресурс подписки для отложенной подписки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_future,
      ...
    }
  ],
}

Приостановленные подписки

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

Повторение подписки Еженедельно Ежемесячно Трехмесячный Шестимесячный Ежегодный
Доступная длительность пауз * 1 неделя
2 недели
3 недели
4 недели
1 месяц
2 месяца
3 месяца
1 месяц
2 месяца
3 месяца
1 месяц
2 месяца
3 месяца
Н/Д
* Возможны изменения в любое время.

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

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

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

Когда подписка пользователя приостановлена, библиотека платежей Play не возвращает подписку через метод queryPurchasesAsync() . Если подписка возобновляется, метод queryPurchasesAsync() возвращает ее снова.

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

Сообщение SubscriptionNotification с типом SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED отправляется, когда ваш пользователь инициирует приостановку своей подписки. В это время пользователь должен сохранить доступ к своей подписке до следующей даты продления, а ресурс подписки содержит autoRenewEnabled = true . На данный момент значение поля subscriptionState равно SUBSCRIPTION_STATE_ACTIVE .

Сообщение SubscriptionNotification с типом SUBSCRIPTION_PAUSED отправляется, когда пауза вступает в силу. Когда это происходит, пользователь должен потерять доступ к своей подписке, а ресурс подписки содержит autoRenewEnabled = true , а поле subscriptionState имеет значение SUBSCRIPTION_STATE_PAUSED . Вы можете узнать, когда ожидается возобновление подписки, проверив объект PausedStateContext .

Сообщение SubscriptionNotification с типом SUBSCRIPTION_RENEWED отправляется, если подписка возобновляется либо автоматически в конце периода приостановки, либо если пользователь решил возобновить подписку вручную. Это следует обрабатывать, как описано в разделе «Продление» .

Сообщение SubscriptionNotification с типом SUBSCRIPTION_ON_HOLD отправляется, если произошел сбой платежа при попытке возобновить подписку после паузы. Это следует обрабатывать, как описано в разделе Блокировка учетной записи .

Повторно подписаться

Для базовых планов подписки с автоматическим продлением в магазине Google Play может отображаться кнопка «Повторить подписку» . Эта кнопка позволяет пользователям восстановить доступ к подписке. Он может не появиться по разным причинам, например, если срок подписки давно истек.

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

Хотя кнопка всегда помечена как «Возобновить подписку» , ее функциональность зависит от состояния подписки.

Хотя подписка отменена, но срок ее действия еще не истек, пользователь по-прежнему подписан и получает преимущества подписки. Если пользователь нажимает «Повторно подписаться», отмена фактически отменяется, и подписка продолжает продлеваться. В документации и API для разработчиков Play это действие называется восстановлением .

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

Восстановить до истечения срока действия

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

Если ваше приложение синхронизирует состояние подписки с серверной частью, вам следует прослушивать сообщение SubscriptionNotification с типом SUBSCRIPTION_RESTARTED . После того как вы получите этот RTDN, ваше приложение сможет ответить на уведомление, записать, что подписка теперь настроена на продление, и перестать отображать сообщения о восстановлении в вашем приложении. Ресурс подписки выглядит примерно так, как показано в следующем примере:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date
      ...
    }
  ],
}

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

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

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

Обновления, понижения версий и повторная подписка

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

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

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

Если пользователь успешно приобретает обновление, понижение версии или повторную подписку, это новая покупка, которую вы должны подтвердить. Рекомендуемый способ сделать это — использовать API разработчика Google Play . Ресурс подписки выглядит примерно так, как показано в следующем примере:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "linkedPurchaseToken": old_purchase_token,
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      }
    }
  ],
}

Изменения цен

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

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

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

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

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

Если пользователь не принял ваше согласие на повышение цены до того, как ему потребуется продлить подписку по более высокой цене, он автоматически отписывается, и вы получаете сообщение SubscriptionNotification с типом SUBSCRIPTION_CANCELED . Обработайте это событие, как описано в разделе «Отмены» .

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

Обработка жизненного цикла для предоплаченных планов

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

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

Рисунок 8. Состояния жизненного цикла и события перехода для покупок подписки.

Сообщение SubscriptionNotification с типом SUBSCRIPTION_PURCHASED отправляется вашему клиенту RTDN при каждом приобретении подписки на предоплаченный план, включая каждое пополнение счета. Вызовите метод purchases.subscriptionsv2.get , чтобы проверить состояние последней подписки на предоплаченный план.

Для дополнительных покупок выдается новый токен покупки, и вы получаете токен предыдущей покупки в поле linkedPurchaseToken как часть состояния покупки новой подписки. Токен покупки действителен с момента регистрации подписки до 60 дней после истечения срока действия. После этой даты токен покупки больше нельзя использовать для вызова API разработчика Google Play.

Ресурс подписки для покупки плана по предоплате выглядит примерно так, как показано в следующем примере:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  "startTime": "2022-04-22T18:39:58.270Z",
  "regionCode": "US",
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "latestOrderId": "GPA.3333-4137-0319-36762",
  "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
  "lineItems": [
    {
      "productId": "prepaid_plan01",
      "expiryTime": expiry_date,
      "prepaidPlan": {
        "allowExtendAfterTime": timestamp_after_which_topups_are_allowed
      }
    }
  ]
}

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

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

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