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

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

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

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

Синхронизация состояния подписки с вашим бэкэндом позволяет вам быть более осведомленным об отклонениях платежей и дает вам больше контекста, когда вы пытаетесь сократить непреднамеренный отток. Прослушивайте сообщения 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 In-App Messaging . Если вы вызываете этот 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 In-App Messaging . Вызов этого 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 Billing Library снова возвращает подписку через метод 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, чтобы получить последний ресурс подписки . После того, как вы убедитесь, что subscriptionStateSUBSCRIPTION_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, имеет поле subscriptionState, установленное на 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 из API разработчика Play, чтобы перенести следующую дату выставления счета для автоматически продлеваемой подписки. Когда вы это делаете, отправляется сообщение 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 Billing Library не возвращает подписку через метод 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 Store может отображаться кнопка «Повторная подписка» . Эта кнопка позволяет пользователям восстановить доступ к подписке. Она может не отображаться по разным причинам, например, если подписка истекла давно.

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

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

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

После истечения срока действия автоматически продлеваемой подписки вы можете разрешить пользователям приобретать тот же базовый план подписки. Это действие известно как resubscribe в документации разработчика 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 Console или API для разрешения повторной подписки, пользователи могут повторно приобрести истекшую подписку в Google Play Store.

Это новые покупки. 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
      }
    }
  ],
}

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

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

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

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

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

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

Обработка продлений после изменения цен

При снижении цены или при возобновлении повышения цены подписки вы получите сообщение 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 в ресурсе подписки.

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

Поля SubscriptionPurchaseV2 для предоплаченных планов

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

  • [Новое поле] LineItems [0] .prepaid_plan.AllowExtendAftertime : обозначает, когда пользователю будет разрешено покупать еще один пополнение, чтобы расширить свой план предоплаты, поскольку пользователю разрешается иметь только один бессосенный пополнение за раз.
  • [Новое поле] Подписка : указывает состояние объекта подписки. Для планов предоплаты эта стоимость всегда является либо ACTIVE , PENDING или CANCELED .
  • LineItems [0] .ExpiryTime : Это поле всегда присутствует для планов предоплаты.
  • PAUSED_STATE_CONTEXT : это поле никогда не присутствует, поскольку планы предоплаты не могут сделать паузу.
  • LineItems [0] .Auto_Renewing_Plan : не присутствует для планов предоплаты.
  • DENCELLED_STATE_CONTEXT : не присутствовать для планов предоплаты, так как это поле относится только к пользователям, которые активно отменяют подписку.
  • LineItems [0] .ProductId : это поле заменяет subscriptionId на предыдущие версии.