چرخه عمر اشتراک

خریدهای اشتراک می‌توانند در طول چرخه عمر خود، بسته به عوامل زیادی از جمله رفتار تمدید خودکار، شرایط عدم پرداخت و اقدامات مدیریت توسعه‌دهنده، چندین حالت مختلف را طی کنند.

مدیریت چرخه عمر برای تمدید خودکار اشتراک‌ها

وقتی وضعیت اشتراک یک کاربر تغییر می‌کند، سرور backend شما یک پیام SubscriptionNotification دریافت می‌کند.

حالت تمدید خودکار زیرمجموعه‌ها
شکل ۱. وضعیت‌های چرخه عمر و رویدادهای انتقال برای خریدهای اشتراک با قابلیت تمدید خودکار.

برای به‌روزرسانی وضعیت در backend خود، API مربوط به purchases.subscriptionsv2.get را با توکن خرید موجود در اعلان فراخوانی کنید. این نقطه پایانی، آخرین وضعیت اشتراک را با توجه به توکن خرید ارائه می‌دهد و منبع حقیقت برای مدیریت اشتراک محسوب می‌شود.

توکن خرید از زمان ثبت اشتراک تا ۶۰ روز پس از انقضا معتبر است. پس از این تاریخ، توکن خرید دیگر برای فراخوانی API توسعه‌دهندگان گوگل پلی معتبر نیست.

خریدهای جدید اشتراک با قابلیت تمدید خودکار

وقتی کاربری اشتراکی را خریداری می‌کند، یک پیام SubscriptionNotification با نوع SUBSCRIPTION_PURCHASED به کلاینت RTDN شما ارسال می‌شود. چه این اعلان را دریافت کنید و چه یک خرید جدید را درون برنامه‌ای از طریق PurchasesUpdatedListener ثبت کنید یا خریدها را به صورت دستی در متد onResume() برنامه خود دریافت کنید، باید خرید جدید را در backend امن خود پردازش کنید. برای انجام این کار، این مراحل را دنبال کنید:

  1. برای دریافت منبع اشتراکی که شامل آخرین وضعیت اشتراک است، نقطه پایانی purchases.subscriptionsv2.get را پرس و جو کنید.
  2. مطمئن شوید که مقدار فیلد subscriptionState SUBSCRIPTION_STATE_ACTIVE باشد.
  3. خرید را تأیید کنید .
  4. به کاربر دسترسی به محتوا را بدهید. حساب کاربری مرتبط با خرید را می‌توان با شیء ExternalAccountIdentifiers از منبع اشتراک شناسایی کرد، اگر شناسه‌ها در زمان خرید با استفاده از setObfuscatedAccountId و setObfuscatedProfileId تنظیم شده باشند.

کتابخانه پرداخت Play همچنین شامل متدی برای تأیید اشتراک، acknowledgePurchase() و متدی برای بررسی وضعیت تأیید، isAcknowledged() است. با این حال، توصیه می‌کنیم برای امنیت بهتر، پردازش خرید را در backend خود انجام دهید.

منبع اشتراک برای خریدهای جدید مشابه مثال زیر است:

{
  "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
      }
    }
  ]
}

نیازی به تایید تمدید اشتراک ندارید.

دوره فیض

اگر در تمدید اشتراک، مشکلی در پرداخت وجود داشته باشد، گوگل به کاربر اطلاع می‌دهد و به صورت دوره‌ای سعی می‌کند اشتراک را برای مدتی قبل از انقضای اشتراک تمدید کند. این دوره بازیابی می‌تواند شامل یک دوره تنفس و به دنبال آن یک دوره نگهداری حساب باشد. در طول دوره تنفس، کاربر همچنان باید به حق اشتراک خود دسترسی داشته باشد.

متد queryPurchasesAsync() همچنان خریدهایی را که در دوره مهلت هستند، برمی‌گرداند. اگر برنامه شما صرفاً به queryPurchasesAsync برای بررسی اینکه آیا کاربر واجد شرایط اشتراک است یا خیر، متکی باشد، برنامه شما باید به طور خودکار دوره‌های مهلت را مدیریت کند، زیرا این اشتراک‌ها از طریق کتابخانه صورتحساب Play به عنوان فعال نشان داده می‌شوند.

همگام‌سازی وضعیت اشتراک با backend به شما این امکان را می‌دهد که از کاهش پرداخت‌ها آگاه‌تر باشید و در تلاش برای کاهش ریزش غیرارادی، زمینه بیشتری در اختیار شما قرار می‌دهد. منتظر پیام‌های SubscriptionNotification با نوع SUBSCRIPTION_IN_GRACE_PERIOD باشید تا هنگام ورود کاربر به دوره مهلت، مطلع شوید. در حالی که کاربر در دوره مهلت است، منبع اشتراک شامل autoRenewEnabled = true است. گوگل پلی به صورت پویا مقدار 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
      }
    }
  ],
}

پلی به کاربرانی که در دوره مهلت پرداخت هستند اطلاع می‌دهد که پرداختشان رد شده است و از آنها می‌خواهد که مشکلات روش پرداخت خود را در فروشگاه پلی برطرف کنند. وقتی کاربری وارد دوره مهلت پرداخت می‌شود، باید او را تشویق کنید که در صورت عدم موفقیت غیرارادی، روش پرداخت خود را اصلاح کند. یک راه ساده برای انجام این کار استفاده از API پیام‌رسانی درون برنامه‌ای است. اگر وقتی کاربر برنامه شما را باز می‌کند، این API را فراخوانی کنید، یک پیام Play در یک میان وعده موقت به او نشان داده می‌شود که به کاربر اطلاع می‌دهد پرداختش رد شده است. این پیام همچنین شامل یک لینک عمیق برای کاربر است تا روش پرداخت خود را در گوگل پلی اصلاح کند.

به محض اینکه کاربر روش پرداخت خود را اصلاح کند، اشتراک با تاریخ تمدید اولیه خود تمدید می‌شود و شما می‌توانید تمدید را همانطور که در بخش تمدیدها توضیح داده شده است، انجام دهید.

اگر کاربر روش پرداخت خود را در طول دوره مهلت اصلاح نکند، اشتراک وارد حالت تعلیق حساب می‌شود و حق استفاده از آن را از دست می‌دهد.

دسترسی و بازیابی در دوره فیض

شکل ۲ جدول زمانی اشتراکی را نشان می‌دهد که وارد دوره تنفس می‌شود و سپس با اصلاح روش پرداخت توسط کاربر، به حالت عادی برمی‌گردد. پس از پایان دوره تنفس، کاربر باید مزایای اشتراک را از دست بدهد و به حالت تعلیق در حساب کاربری برود.

شکل ۲. جدول زمانی برای اشتراکی که وارد دوره مهلت می‌شود و قبل از پایان آن بازیابی می‌شود.

یادآوری نکات زیر ضروری است:

  • در طول دوره مهلت، کاربر باید دسترسی به مزایای اشتراک را حفظ کند.
  • وقتی اشتراکی در طول دوره‌ی تمدید اعتبار، دوباره فعال می‌شود، تاریخ تمدید دوباره تنظیم نمی‌شود .
  • اگر دوره مهلت را افزایش دهید - مثلاً از ۷ روز به ۱۴ روز - کاربرانی که در دوره مهلت هستند، دسترسی بیشتری به مزایای اشتراک پیدا می‌کنند.
  • اگر دوره‌ی مهلت را کاهش دهید، مزایای اشتراک کاربرانی که به اندازه‌ی کافی از دوره‌ی مهلت قدیمی گذشته‌اند که از دوره‌ی مهلت جدید فراتر بروند، بلافاصله لغو می‌شود. برای مثال، اگر دوره‌ی مهلت را از ۱۴ روز به ۷ روز کاهش دهید، مزایای اشتراک کاربرانی که در روزهای ۸ تا ۱۴ دوره‌ی مهلت قدیمی هستند، بلافاصله لغو می‌شود.
  • اشتراک در حالت فعال باقی می‌ماند و تا پایان دوره مهلت سکوت، RTDN مهلت دریافت نخواهید کرد.

دوره فیض سکوت

شما می‌توانید یک دوره مهلت ۰ روزه تعیین کنید، اما Play حداقل ۱ روز صبر می‌کند تا زمان کافی برای تلاش مجدد برای پرداخت را تضمین کند. این دوره مهلت خاموش، یک شبکه ایمنی برای پردازش پرداخت ارائه می‌دهد. در طول این دوره ۲۴ ساعته، اشتراک در حالت ACTIVE باقی می‌ماند.

بهترین راه برای همگام ماندن با تغییرات وضعیت اشتراک، گوش دادن و واکنش نشان دادن به اعلان‌های توسعه‌دهنده (RTDN) در لحظه است. برای دریافت وضعیت دقیق‌تر اشتراک، متد purchases.subscriptionsv2.get() را در زمان RTDN به جای زمان انقضا فراخوانی کنید.

بسته به وضعیت اشتراک پس از دوره ۲۴ ساعته سکوت، باید یکی از اعلان‌های زیر را دریافت کنید:

  • SUBSCRIPTION_ON_HOLD (در صورت فعال بودن)
  • SUBSCRIPTION_CANCELED (در صورت لغو اشتراک)
  • SUBSCRIPTION_EXPIRED (در صورت منقضی شدن)
  • SUBSCRIPTION_RENEWED (در صورت تمدید موفقیت‌آمیز)

همچنین می‌توانید متد subscriptionV2.get() را در هر زمانی پس از دوره ۲۴ ساعته سکوت فراخوانی کنید تا آخرین وضعیت اشتراک را دریافت کنید.

نگه داشتن حساب

اگر در تمدید اشتراک، مشکلی در پرداخت وجود داشته باشد، پس از پایان هر دوره تنفس ، دوره مسدود شدن حساب شروع می‌شود. وقتی اشتراکی وارد دوره مسدود شدن حساب می‌شود، باید دسترسی به حق اشتراک را مسدود کنید.

در طول مدت تعلیق حساب، شما باید در صورت نیاز به رسیدگی به هرگونه لغو ، بازیابی یا بازخرید اشتراک‌های خود ادامه دهید، زیرا کاربر می‌تواند این تغییرات را در حین تعلیق اشتراک انجام دهد.

RTDNها وقتی کاربر وارد دوره نگهداری حساب می‌شود، به شما اطلاع می‌دهند، بنابراین می‌توانید در اسرع وقت به آنها اطلاع دهید که چرا دسترسی آنها به اشتراک به حالت تعلیق درآمده است. یک راه ساده برای انجام این کار، استفاده از API پیام‌رسانی درون‌برنامه‌ای است. فراخوانی این API هنگام باز کردن برنامه توسط کاربر، پیامی را در یک میان وعده موقت به کاربر نشان می‌دهد که به او اطلاع می‌دهد پرداخت او رد شده است. این پیام همچنین شامل یک لینک عمیق برای کاربر است تا روش پرداخت خود را در Google Play اصلاح کند.

اگر کاربران شما می‌توانند به محتوای اشتراک خارج از برنامه شما دسترسی داشته باشند، ممکن است متوجه شوند که دسترسی خود را در سطوح مختلف از دست داده‌اند. می‌توانید یک اعلان فشاری یا ایمیل برای کاربر ارسال کنید تا به او اطلاع دهید که اشتراک او به دلیل کاهش پرداخت دیگر فعال نیست.

اشتراک در طول مدت نگهداری حساب توسط متد queryPurchasesAsync() برگردانده نمی‌شود، بنابراین اگر برنامه شما برای نمایش خریدهای موجود به این متد متکی است، باید به طور پیش‌فرض از نگهداری حساب پشتیبانی کنید.

با اعلان‌های توسعه‌دهنده‌ی بلادرنگ، وقتی اشتراکی وارد حالت تعلیق حساب می‌شود، یک پیام SubscriptionNotification با نوع SUBSCRIPTION_ON_HOLD دریافت می‌کنید. برای بازیابی اطلاعات جدید اشتراک، متد purchases.subscriptionsv2.get را از سرور backend امن خود فراخوانی کنید. در طول حالت تعلیق حساب، فیلد 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 روی یک timestamp در آینده تنظیم می‌شود و فیلد 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 که نشان‌دهنده این نمونه جدید است، بازگردانده می‌شود.

دسترسی به حساب و بازیابی آن

شکل ۳ جدول زمانی اشتراکی را نشان می‌دهد که وارد حساب کاربری می‌شود و سپس با اصلاح روش پرداخت کاربر، حساب کاربری بازیابی می‌شود.

شکل ۳. جدول زمانی برای اشتراکی که وارد حساب کاربری می‌شود و قبل از پایان آن بازیابی می‌شود.

مشابه مثال قبلی، شکل ۴ جدول زمانی برای اشتراکی را نشان می‌دهد که ابتدا قبل از ورود به حالت تعلیق حساب، وارد یک دوره تنفس می‌شود و سپس در حین تعلیق، حساب بازیابی می‌شود.

شکل ۴. جدول زمانی برای اشتراکی که وارد دوره تنفس می‌شود، سپس وارد دوره تعلیق حساب می‌شود و در نهایت قبل از پایان دوره تعلیق حساب، بازیابی می‌شود.

یادآوری نکات زیر ضروری است:

  • قبل از اینکه اشتراکی به حالت تعلیق درآید، گوگل پلی تا ۴۸ ساعت تلاش‌های بیشتری برای کسر هزینه از روش پرداخت انجام می‌دهد. کاربر در این مدت مزایای اشتراک را حفظ می‌کند. پس از گذشت این دوره تلاش مجدد، اشتراک وارد حالت تعلیق در حساب می‌شود و کاربر باید دسترسی به مزایای اشتراک را از دست بدهد.
  • اشتراک مستقیماً زمانی که از حالت متوقف شده با پرداخت ناموفق، از سر گرفته می‌شود، وارد حساب نگه داشته شده می‌شود.
  • وقتی اشتراک از حالت مسدود شده خارج می‌شود، تاریخ تمدید دوباره تنظیم می‌شود.

انقضاها

پس از انقضای اشتراک، کاربر باید دسترسی به اشتراک را از دست بدهد. در این صورت، یک پیام SubscriptionNotification با نوع SUBSCRIPTION_EXPIRED ارسال می‌شود. هنگامی که این اعلان را دریافت کردید، از API توسعه‌دهنده Google Play درخواست کنید تا آخرین منبع اشتراک را دریافت کنید. پس از تأیید اینکه subscriptionState SUBSCRIPTION_STATE_EXPIRED است، مجوز را حذف کرده و وضعیت خرید را در backend خود به عنوان نامعتبر ثبت کنید. منبع اشتراک مشابه مثال زیر است:

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

لغو قراردادها

کاربر می‌تواند داوطلبانه اشتراک خود را از مرکز اشتراک‌های Play لغو کند یا اگر پس از مسدود شدن حساب کاربری ، اشتراک خود را بازیابی نکند، اشتراک او به طور خودکار لغو شود. توسعه‌دهندگان همچنین می‌توانند با استفاده از purchases.subscriptionsv2.cancel لغو اشتراک را فعال کنند. هنگامی که اشتراکی لغو می‌شود، کاربر تا پایان چرخه صورتحساب فعلی به محتوا دسترسی دارد. هنگامی که چرخه صورتحساب به پایان می‌رسد، دسترسی باید لغو شود.

لغو اشتراک بدون اقساط و با قابلیت تمدید خودکار، اعلان SUBSCRIPTION_CANCELED را فعال می‌کند. وقتی این اعلان را دریافت می‌کنید، فیلد subscriptionState در منبع اشتراک که از Google Play Developer API برگردانده شده، روی SUBSCRIPTION_STATE_CANCELED تنظیم شده است و فیلد expiryTime حاوی تاریخی است که کاربر باید دسترسی به اشتراک را از دست بدهد. اگر آن تاریخ گذشته باشد، کاربر باید بلافاصله حق استفاده از آن را از دست بدهد. این اتفاق می‌تواند رخ دهد، به عنوان مثال، اگر کاربری در حالی که حسابش را به دلیل کاهش پرداخت نگه داشته است، اشتراک را لغو کند.

منبع اشتراک برای خرید لغو شده مشابه مثال زیر است:

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

برای اشتراک‌های اقساطی، هنگامی که پرداخت‌ها برای دوره تعهد باقی می‌مانند، یک اعلان SUBSCRIPTION_CANCELLATION_SCHEDULED پس از لغو درخواستی کاربر ارسال می‌شود. لغو در حال بررسی است و در پایان دوره تعهد فعلی اعمال می‌شود. هنگامی که این اعلان را دریافت می‌کنید، فیلد subscriptionState در منبع اشتراک بازگردانده شده از Google Play Developer API روی SUBSCRIPTION_STATE_ACTIVE تنظیم شده است زیرا اشتراک اقساطی تا پایان دوره تعهد هنوز فعال است. با این حال، یک شیء pendingCancelation خالی وجود دارد. یک اعلان 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 در منبع subscription نگاه کنید تا بفهمید چرا اشتراک لغو شده است (برای مثال، آیا اشتراک توسط کاربر، توسط سیستم یا توسط شما لغو شده است). اگر اشتراک توسط کاربر لغو شده باشد، می‌توانید به فیلد userInitiatedCancellation نگاه کنید تا بفهمید چرا کاربر اشتراک را لغو کرده است. این می‌تواند به شما در تدوین استراتژی‌های ارتباطی کمک کند.

وقتی اشتراکی لغو می‌شود اما هنوز منقضی نشده است، همچنان از queryPurchasesAsync() برگردانده می‌شود. شاید بخواهید پیامی را در برنامه خود نمایش دهید که به کاربر اطلاع دهد اشتراکش لغو شده و تاریخ انقضا را به او بدهد.

ابطال‌ها

یک اشتراک می‌تواند به دلایل مختلفی لغو شود، از جمله لغو اشتراک توسط backend شما با استفاده از purchases.subscriptionsv2.revoke یا بازپرداخت هزینه خرید. در این شرایط، فوراً حق استفاده از کاربر را لغو کنید. در این صورت، یک پیام SubscriptionNotification با نوع SUBSCRIPTION_REVOKED ارسال می‌شود. وقتی این اعلان را دریافت می‌کنید، فیلد subscriptionState در منبع اشتراک که از Google Play Developer API برگردانده شده، روی 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,
      ...
    }
  ],
}

اشتراک‌های متوقف‌شده

شما می‌توانید با فعال کردن قابلیت توقف اشتراک کاربران، ریزش داوطلبانه آنها را کاهش دهید. وقتی ویژگی توقف را فعال می‌کنید، کاربران می‌توانند بسته به دوره تکرار، اشتراک خود را برای مدت زمانی بین یک هفته تا سه ماه متوقف کنند.

تکرار اشتراک هفتگی ماهانه سه ماهه شش ماهه سالانه
مدت زمان مکث موجود * ۱ هفته
۲ هفته
۳ هفته
۴ هفته
۱ ماه
۲ ماه
۳ ماه
۱ ماه
۲ ماه
۳ ماه
۱ ماه
۲ ماه
۳ ماه
ناموجود
* در هر زمانی قابل تغییر است.

توقف اشتراک تنها پس از پایان دوره صورتحساب فعلی اعمال می‌شود. در طول مدت توقف اشتراک، کاربر به اشتراک دسترسی ندارد و هزینه تمدید را پرداخت نمی‌کند. در پایان دوره توقف، اشتراک از سر گرفته می‌شود و گوگل تلاش می‌کند اشتراک را تمدید کند. اگر از سرگیری موفقیت‌آمیز باشد، اشتراک دوباره فعال می‌شود. اگر از سرگیری به دلیل مشکل پرداخت ناموفق باشد، کاربر همانطور که در شکل‌های ۵ و ۶ نشان داده شده است، وارد حالت تعلیق حساب می‌شود:

شکل ۵. کاربر اشتراک خود را متوقف کرده و سپس از سر می‌گیرد.
شکل ۶. کاربر اشتراک خود را متوقف کرده و سپس وارد حالت نگه داشتن حساب می‌شود.

کاربر همچنین می‌تواند در هر زمانی از دوره مکث، اشتراک را به صورت دستی از سر بگیرد، همانطور که در شکل ۶ نشان داده شده است. وقتی کاربر به صورت دستی اشتراک را از سر می‌گیرد، تاریخ صورتحساب به تاریخ از سرگیری دستی تغییر می‌کند.

وقتی اشتراک یک کاربر متوقف می‌شود، کتابخانه پرداخت Play، اشتراک را از طریق متد queryPurchasesAsync() برنمی‌گرداند، مگر اینکه پارامتر isSuspended برای اشتراک روی true تنظیم شده باشد. اگر اشتراک از سر گرفته شود، متد 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_RECOVERED ارسال می‌شود.

اگر هنگام تلاش برای از سرگیری اشتراک پس از مکث، پرداخت ناموفق باشد، یک پیام SubscriptionNotification با نوع SUBSCRIPTION_ON_HOLD ارسال می‌شود.

هر دو وضعیت باید همانطور که در بخش «نگهداری حساب» توضیح داده شده است، مدیریت شوند.

اشتراک مجدد

برای طرح‌های پایه اشتراک که به صورت خودکار تمدید می‌شوند، فروشگاه گوگل پلی ممکن است دکمه‌ای برای اشتراک مجدد نمایش دهد. این دکمه به کاربران امکان می‌دهد تا دوباره به اشتراک دسترسی پیدا کنند. این دکمه ممکن است به دلایل مختلف، مثلاً زمانی که مدت‌ها پیش اشتراک منقضی شده است، نمایش داده نشود.

شکل ۷. بخش حساب کاربری > اشتراک‌ها در برنامه فروشگاه گوگل پلی که اشتراک لغو شده را به همراه دکمه اشتراک مجدد نشان می‌دهد.

اگرچه این دکمه همیشه با عنوان «اشتراک مجدد» مشخص شده است، اما عملکرد آن به وضعیت اشتراک بستگی دارد.

در حالی که اشتراک لغو شده اما هنوز منقضی نشده است، کاربر همچنان مشترک است و از مزایای اشتراک بهره‌مند می‌شود. اگر کاربر روی «بازگشت به اشتراک» ضربه بزند، لغو لغو می‌شود و اشتراک همچنان تمدید می‌شود. این عمل در اسناد و APIهای توسعه‌دهندگان Play به عنوان «بازیابی» شناخته می‌شود.

پس از انقضای اشتراک تمدید خودکار، می‌توانید به کاربران اجازه دهید همان طرح پایه اشتراک را خریداری کنند. این عمل در مستندات توسعه‌دهندگان و APIهای Play با عنوان resubscribe شناخته می‌شود. می‌توانید این گزینه را برای هر طرح پایه در Play Console یا با استفاده از API پیکربندی کنید.

بازیابی قبل از انقضا

اگر برنامه شما صرفاً به متد queryPurchasesAsync() برای تعیین اینکه آیا کاربر حق اشتراک دارد یا خیر، متکی باشد، برنامه شما باید به طور خودکار بازیابی‌ها را مدیریت کند، زیرا متد queryPurchasesAsync() همچنان خریدهای لغو شده را قبل از تاریخ انقضای آنها برمی‌گرداند. یک اشتراک بازیابی شده همچنان تمدید می‌شود، گویی لغو نشده است.

اگر برنامه شما وضعیت اشتراک را با یک backend همگام‌سازی می‌کند، باید منتظر یک پیام SubscriptionNotification با نوع SUBSCRIPTION_RESTARTED باشید. پس از دریافت این RTDN، برنامه شما می‌تواند به اعلان پاسخ دهد، ثبت کند که اشتراک اکنون برای تمدید تنظیم شده است و نمایش پیام‌های بازیابی را در برنامه خود متوقف کند. منبع اشتراک مشابه مثال زیر است:

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

پس از انقضا، دوباره ثبت نام کنید

اگر یک طرح پایه با قابلیت تمدید خودکار با استفاده از کنسول یا API گوگل پلی پیکربندی شده باشد تا امکان اشتراک مجدد فراهم شود، کاربران می‌توانند اشتراک منقضی شده را در فروشگاه گوگل پلی دوباره خریداری کنند.

اینها خریدهای جدید هستند. گوگل پلی یک توکن خرید کاملاً جدید صادر می‌کند و بک‌اند شما یک RTDN با نوع SUBSCRIPTION_PURCHASED دریافت می‌کند. وضعیت خرید برای این نوع خرید خارج از برنامه شامل یک linkedPurchaseToken مرتبط با خرید اصلی در آن مورد نمی‌شود، زیرا اشتراک اصلی کاملاً منقضی شده است. اینها خریدهای جدیدی هستند که بک‌اند شما باید مانند هر خرید دیگری آنها را پردازش و تأیید کند.

ارتقا، تنزل رتبه و اشتراک مجدد

وقتی کاربری قبل از انقضای اشتراک، برنامه شما را ارتقا، تنزل یا پس از لغو اشتراک، ثبت‌نام می‌کند ، اشتراک قدیمی نامعتبر شده و یک اشتراک جدید با یک توکن خرید جدید ایجاد می‌شود.

علاوه بر این، منبع اشتراک که از API توسعه‌دهندگان گوگل پلی برگردانده می‌شود، حاوی یک فیلد linkedPurchaseToken است که خرید قدیمی که کاربر از آن ارتقا، کاهش یا دوباره مشترک شده است را نشان می‌دهد. می‌توانید از توکن خرید در آن فیلد برای جستجوی اشتراک قدیمی و شناسایی حساب کاربری موجود استفاده کنید تا بتوانید خرید جدید را با همان حساب مرتبط کنید.

قبل از ارائه گزینه‌های ارتقا، تنزل یا اشتراک مجدد به یک کاربر در برنامه خود، باید اشتراک موجود را تأیید کنید. هرگونه تغییر طرح یا اشتراک مجدد در صورتی که اشتراک موجود هنوز در انتظار تأیید باشد، مسدود می‌شود.

اگر کاربر با موفقیت ارتقاء، تنزل یا اشتراک مجدد را خریداری کند، این یک خرید جدید است که باید آن را تأیید کنید. روش پیشنهادی برای انجام این کار استفاده از API توسعه‌دهندگان گوگل پلی است. منبع اشتراک مشابه مثال زیر است:

{
  "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 دریافت خواهید کرد.

مدیریت تأیید کاربر برای تغییر قیمت انتخابی

وقتی کاربری افزایش قیمت اشتراک شما را می‌پذیرد، یک پیام اعلان اشتراک با نوع SUBSCRIPTION_PRICE_CHANGE_UPDATED دریافت می‌کنید.

رسیدگی به تمدیدها پس از اعمال تغییر قیمت

با کاهش قیمت، یا زمانی که افزایش قیمت اشتراک تمدید می‌شود، یک پیام SubscriptionNotification با نوع SUBSCRIPTION_RENEWED دریافت خواهید کرد. با این اعلان مانند هر تمدید دیگری رفتار کنید.

رسیدگی به مواردی که افزایش قیمت انتخابی پذیرفته نمی‌شود

اگر کاربری قبل از نیاز به تمدید با قیمت بالاتر، افزایش قیمت انتخابی شما را نپذیرد، به طور خودکار اشتراکش لغو می‌شود و شما یک پیام اعلان اشتراک با نوع SUBSCRIPTION_CANCELED دریافت خواهید کرد. این رویداد را همانطور که در لغوها توضیح داده شده است، مدیریت کنید.

کاربران همچنین می‌توانند اشتراک‌های خود را برای افزایش قیمت انصراف، با پیروی از همین مکانیزم، لغو کنند.

با توجه به مقررات جدید کره جنوبی (KR)، کاربران اشتراک در منطقه KR باید با هرگونه افزایش قیمتی که پس از پایان دوره آزمایشی رایگان یا دوره مقدماتی آنها رخ می‌دهد، موافقت کنند.

برای کمک به شما در رعایت مقررات، Play به کاربران منطقه KR در مورد الزام رضایت اطلاع می‌دهد و همچنین پاسخ رضایت کاربران را ذخیره می‌کند. اشتراک کاربرانی که قبل از اعمال قیمت بالاتر رضایت خود را ارائه ندهند، به طور خودکار لغو می‌شود. علاوه بر اعلان‌های ارسالی از Play، می‌توانید اعلان‌های افزایش قیمت سفارشی خود را نیز برای کاربران خود ارسال کنید و می‌توانید لینکی به صفحه مدیریت خاص در اعلان‌های خود ارائه دهید.

وقتی دوره رضایت شروع شد یا کاربر رضایت خود را اعلام کرد، یک پیام اعلان اشتراک با نوع SUBSCRIPTION_PRICE_STEP_UP_CONSENT_UPDATED دریافت خواهید کرد.

تفاوت بین افزایش قیمت و تغییر قیمت

price step-up به افزایش قیمت اشتراک به دلیل گذار از یک مرحله پیشنهاد به مرحله دیگر اشاره دارد. به عنوان مثال، تغییر اشتراک از یک دوره آزمایشی رایگان به قیمت معمولی.

با این حال، price change به به‌روزرسانی‌های قیمتی اشاره دارد که توسط شما (توسعه‌دهنده) برای قیمت پایه طرح اشتراک اعمال می‌شود. برای مثال، افزایش قیمت برای عضویت یا افزایش قیمت برای عدم عضویت.

مدیریت چرخه عمر برای طرح‌های پیش‌پرداخت

همانند اشتراک‌های تمدید خودکار، شما باید پس از هر خرید جدید ، طرح‌های پیش‌پرداخت را تأیید کنید. در مورد طرح‌های پیش‌پرداخت، شما باید هم خرید اولیه و هم هرگونه افزایش اعتبار را به طور کامل پردازش کنید، زیرا کاربر باید هر بار جریان خرید را طی کند.

با توجه به احتمال کوتاه بودن مدت زمان طرح‌های پیش‌پرداخت، تأیید خرید در اسرع وقت بسیار مهم است. طرح‌های پیش‌پرداخت با مدت زمان یک هفته یا بیشتر باید ظرف ۳ روز تأیید شوند. طرح‌های پیش‌پرداخت با مدت زمان کمتر از یک هفته باید ظرف نیمی از مدت زمان طرح تأیید شوند. به عنوان مثال، توسعه‌دهندگان ۱.۵ روز فرصت دارند تا خرید یک طرح پیش‌پرداخت سه روزه را تأیید کنند.

شکل ۸. وضعیت‌های چرخه حیات و رویدادهای انتقال برای خریدهای اشتراکی.

A SubscriptionNotification message with type SUBSCRIPTION_PURCHASED is sent to your RTDN client whenever a prepaid plan subscription is purchased, including every top-up. Call the purchases.subscriptionsv2.get method to check for the latest prepaid plan subscription state.

A new purchase token is issued for top-up purchases, and you receive the previous purchase token in the linkedPurchaseToken field as part of the new subscription purchase state. The purchase token is valid from subscription signup until 60 days after expiration. After this date, the purchase token is no longer valid to use to call the Google Play Developer API.

The subscription resource for a prepaid plan purchase looks similar to the following example:

{
  "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
      }
    }
  ]
}

You can see when the entitlement ends in the expiryTime field. Top-up purchases increase the entitlement time by accumulating it. That means that if the user tops up before their original entitlement ends, the new time is added on top of their previous expiration date.

You might want to display a message in your app informing the user that their prepaid subscriptions can be extended with a top-up. To know when a user will be able to top-up, check the allowExtendAfterTime field in the subscription resource.

Prepaid plans don't auto-renew, so they can't be canceled. If a user wants to cancel a prepaid plan, they can let it reach its expiration date.

SubscriptionPurchaseV2 fields for prepaid plans

New fields have been added to support prepaid plans, which are extended by the user instead of automatically renewing. All fields apply to prepaid plans as they do for auto-renewing subscriptions, with the following exceptions:

  • [New field] lineItems[0].prepaid_plan.allowExtendAfterTime : denotes when a user will be allowed to buy another top-up to extend their prepaid plan, as a user is allowed to have only one unconsumed top-up at a time.
  • [New field] SubscriptionState : specifies the subscription object state. For prepaid plans, this value is always either ACTIVE , PENDING , or CANCELED .
  • lineItems[0].expiryTime : This field is always present for prepaid plans.
  • paused_state_context : This field is never present, as prepaid plans cannot pause.
  • lineItems[0].auto_renewing_plan : Not present for prepaid plans.
  • canceled_state_context : Not present for prepaid plans, as this field applies only to users who actively cancel a subscription.
  • lineItems[0].productId : This field replaces subscriptionId from previous versions.