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

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

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

Когда состояние подписки пользователя изменяется, ваш внутренний сервер получает сообщение 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 в ресурсе подписки.

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

,

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

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

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

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

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

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

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

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

  1. Запросите purchases.subscriptionsv2.get Endpoint, чтобы получить ресурс подписки , который содержит последнее состояние подписки.
  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 , чтобы проверить, имеет ли пользователь право на подписку, то ваше приложение должно автоматически обрабатывать льготные периоды, поскольку эти подписки показаны как активные через библиотеку выставления счетов.

Синхронизация состояния подписки с вашей бэкэнд позволяет вам больше знать о снижении оплаты и дает вам больше контекста, когда вы пытаетесь уменьшить непроизвольный отток. Слушайте сообщения SubscriptionNotification SUBSCRIPTION_IN_GRACE_PERIOD В то время как пользователь находится в изящном периоде, ресурс подписки содержит autoRenewEnabled = true . Google играет динамически расширяет значение 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 информирует пользователей, которые находятся в льготном периоде, что их оплата была отклонена, и побуждает их исправить свои проблемы с методом оплаты в игровом магазине. Когда пользователь вступает в льготный период, вы также должны побудить пользователя исправить свой способ оплаты в случае, если неудача будет непроизвольной. Простой способ сделать это-использовать API обмена сообщениями в приложении . Если вы позвоните в этот API, когда пользователь открывает ваше приложение, им отображается игровое сообщение во временной закусочной, информирующей пользователя, что его оплата была отклонена. Это сообщение также включает в себя глубокую ссылку для пользователя, чтобы исправить свой способ оплаты в Google Play.

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

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

Доступ и восстановление льгот.

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

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

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

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

Тихая благодать период

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

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

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

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

Вы также можете позвонить в метод subscriptionV2.get() .

Удержание учетной записи

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

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

RTDNS уведомит вас, когда пользователь входит в период удержания учетной записи, поэтому вы можете сообщить им как можно скорее о том, почему их доступ к подписке был приостановлен. Простой способ сделать это-использовать 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 Informs пользователей в счете с учетом их снижения платежей, и вы также должны побудить их исправить свой способ оплаты.

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

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

После восстановления библиотека Billing Billing снова возвращает подписку с помощью метода 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 Developer, имеет поле 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, имеет поле подписки, установленное на SUBSCRIPTION_STATE_ACTIVE поскольку подписка в рассрочку все еще активна до конца периода обязательств. Тем не менее, присутствует пустой объект, связанный с ваендингом. Уведомление 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,
      ...
    }
  ]
}

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

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

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

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

{
  "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. Когда пользователь возобновляет вручную, дата выставления счета изменяется в дату резюме ручной работы.

Когда подписка пользователя приостановлена, библиотека Billing Billing не возвращает подписку с помощью метода 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 и API. Вы можете настроить эту опцию для каждого базового плана в игровой консоли или с помощью 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 в ресурсе подписки.

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