خریدها و اشتراکها
قرارداد پیادهسازی خرید مستقیم، خرید استوری، تمدید و بازیابی خرید در SDK نسخه ۲
طراحی فرایند خرید در SDK نسخه ۲
این سند قرارداد اجرایی پیادهسازی خرید در نسخه جدید SDKهای اینپی فای است. هدف اصلی این نسخه، اصلاح فرایند خریدهای کافهبازار و مایکت بدون ایجاد تغییر در رفتار اپهایی است که همچنان از SDK و API نسخه ۱ استفاده میکنند.
اصل سازگاری با نسخه قبل
- API و SDK نسخه ۱ نباید تغییر رفتار داشته باشند.
- متد عمومی
purchaseدر SDK نسخه ۲ نیز حفظ میشود تا مهاجرت برای توسعهدهنده ساده باشد. - SDK در داخل متد
purchaseو بر اساسstorePlatformمسیر مناسب را انتخاب میکند. - پرداخت مستقیم همچنان از فرایند پایدار نسخه ۱ استفاده میکند.
- فقط خریدهای کافهبازار و مایکت به API جدید خرید استوری منتقل میشوند.
بنابراین انتشار SDK نسخه ۲ به معنی حذف یا بازنویسی پرداخت مستقیم نیست. SDK جدید یک API عمومی یکپارچه دارد، اما در لایه داخلی از دو مسیر متفاوت استفاده میکند.
قرارداد عمومی پیشنهادی SDK
نام دقیق کلاسها و callbackها میتواند با زبان SDK هماهنگ شود، ولی رفتار عمومی باید معادل قرارداد زیر باشد:
نتیجه خرید بهتر است حداقل حالتهای زیر را پوشش دهد:
نامها صرفاً پیشنهاد طراحی SDK هستند و جزو قرارداد HTTP محسوب نمیشوند.
انتخاب مسیر خرید
SDK باید مقدار storePlatform دریافتشده از تنظیمات اپ را مرجع انتخاب مسیر قرار دهد. انتخاب مسیر بر اساس اطلاعاتی که اپ میزبان بهصورت دستی ارسال میکند مجاز نیست.
| نوع اپ | مسیر | رفتار |
|---|---|---|
DirectAndroid | /app/v1/purchase | فرایند فعلی پرداخت مستقیم و دریافت لینک درگاه |
DirectIos | /app/v1/purchase | فرایند فعلی پرداخت مستقیم |
DirectWeb | /app/v1/purchase | فرایند فعلی پرداخت وب |
Bazar | /app/v2/store/purchases | خرید با Billing SDK بازار و سپس استعلام سرور به سرور |
Myket | /app/v2/store/purchases | خرید با Billing SDK مایکت و سپس استعلام سرور به سرور |
پرداخت مستقیم
در پرداخت مستقیم، SDK نسخه ۲ باید همان درخواست فعلی /app/v1/purchase را با همان فیلدها و همان نحوه مدیریت redirect و callback ارسال کند.
SDK نباید برای یکسانسازی ظاهری، پاسخ پرداخت مستقیم را به API خرید استوری ارسال کند. یکسانسازی فقط باید در API عمومی SDK و نوع نتیجهای که به اپ میزبان تحویل داده میشود انجام شود.
خرید استوری
فرایند خرید بازار و مایکت به ترتیب زیر است:
- SDK خرید را با Billing SDK رسمی فروشگاه آغاز میکند.
- پس از دریافت نتیجه موفق از فروشگاه، اطلاعات خرید خام در حافظه SDK نگه داشته میشود.
- SDK توکن خرید را به
/app/v2/store/purchasesارسال میکند. - سرور اینپی فای خرید را مستقیماً از سرور فروشگاه استعلام میکند.
- فقط پس از تأیید سرور، پرداخت ثبت و حق دسترسی فعال یا تمدید میشود.
- SDK نتیجه نهایی سرور را به اپ میزبان تحویل میدهد.
موفق بودن callback محلی فروشگاه بهتنهایی به معنی فعال شدن حق دسترسی نیست.
درخواست ثبت خرید
فیلدهای apikey، token، appIdentifier، productIdentifier، offeringIdentifier، country، appVersion، operation و purchase.token الزامیاند. سایر فیلدهای شیء purchase در صورت ارائهشدن توسط SDK فروشگاه ارسال میشوند.
SDK نباید قیمت، درصد تخفیف، حق دسترسی یا شناسه پروژه را بهعنوان داده معتبر خرید ارسال کند. این مقادیر در سرور و از روی تنظیمات محصول محاسبه میشوند.
پاسخ خرید
مقادیر فعلی data.purchase.status عبارتاند از:
| وضعیت | معنی | اقدام SDK |
|---|---|---|
COMPLETED | خرید غیرمصرفی یا اشتراک ثبت شد | نتیجه موفق و دریافت مجدد مشتریInfo |
RESTORED | خرید قبلی بازیابی و دسترسی ثبت شد | نتیجه موفق و دریافت مجدد مشتریInfo |
ALREADY_PROCESSED | این رویداد قبلاً ثبت شده است | موفق در نظر گرفته شود؛ خرید تکرار نشود |
DELIVERY_REQUIRED | کالای مصرفی تأیید شده ولی هنوز تحویل نشده است | تحویل محتوا با کلید deliveryId |
CONSUME_REQUIRED | محتوا تحویل شده و فروشگاه باید consume شود | اجرای consume یا تلاش مجدد |
محصولات مصرفی
برای جلوگیری از از دست رفتن خرید یا تحویل دوباره، ترتیب عملیات کالای مصرفی باید دقیقاً رعایت شود:
- خرید در فروشگاه انجام میشود.
- سرور پاسخ
DELIVERY_REQUIREDو یکdeliveryIdمیدهد. - اپ میزبان محتوا را بهشکل idempotent و با کلید
deliveryIdتحویل میدهد. - SDK تحویل موفق را به سرور اعلام میکند.
- SDK خرید را در Billing SDK فروشگاه consume میکند.
- نتیجه consume به سرور گزارش میشود.
اعلام تحویل
فراخوانی تکراری این endpoint نباید باعث تحویل دوباره محتوا شود. اپ میزبان نیز باید deliveryIdهای تحویلشده را پایدار نگه دارد.
اعلام نتیجه consume
حالت موفق:
حالت ناموفق:
در صورت خطا، SDK باید تلاش consume را با backoff تکرار کند. پیش از دریافت تأیید تحویل از سرور، consume نباید انجام شود؛ چون در صورت شکست شبکه ممکن است خرید از فروشگاه حذف شود ولی محتوا به کاربر نرسیده باشد.
Restore خریدها
restorePurchases برای بازیابی اشتراکها و محصولات غیرمصرفی در نصب مجدد، تعویض دستگاه یا ورود دوباره کاربر است.
SDK باید خریدهای موجود را از Billing SDK فروشگاه دریافت کند و هر خرید را جداگانه به /app/v2/store/purchases بفرستد. بدنه درخواست مشابه خرید عادی است، با این تفاوت:
قواعد Restore:
- فقط برای
SubscriptionوNonConsumableاجرا میشود. - محصول
Consumableقابل Restore نیست. - هر توکن باید ابتدا در سرور فروشگاه تأیید شود.
- رویداد ثبتشده دوباره حق دسترسی یا payment ایجاد نمیکند.
- توکن متعلق به مشتری، اپ یا محصول دیگر پذیرفته نمیشود.
- پس از پایان عملیات، SDK باید
مشتریInfoرا دوباره دریافت کند. - شکست یک آیتم نباید مانع بررسی سایر خریدهای قابل بازیابی شود؛ نتیجه نهایی باید تعداد موفق، تکراری و ناموفق را مشخص کند.
تمدید اشتراک بازار
در بازار، توکن اصلی اشتراک ممکن است در تمدیدها ثابت بماند. سرور هر دوره را با ترکیب توکن و validUntil تأییدشده توسط بازار تشخیص میدهد.
- همان توکن با
validUntilجدید یک تمدید جدید است. - همان توکن با همان
validUntilرویداد تکراری است. autoRenewingوضعیت تمدید خودکار را نشان میدهد، اما بهتنهایی مجوز فعالکردن حق دسترسی نیست.- در صورت دریافت
linkedSubscriptionToken، زنجیره قبلی و توکن جایگزینشده به یک اشتراک متصل میشوند. - تاریخ انقضای زنجیره هیچگاه با پاسخ قدیمی به عقب برگردانده نمیشود.
SDK نباید با مقایسه محلی تاریخها حق دسترسی را تمدید کند؛ تصمیم نهایی پس از استعلام سرور به سرور گرفته میشود.
تمدید اشتراک مایکت
در مایکت هر خرید یا تمدید میتواند توکن متفاوتی داشته باشد. در نتیجه:
- هر purchase token یک رویداد مستقل محسوب میشود.
- SDK باید همه خریدهای فعال برگرداندهشده توسط مایکت را sync کند.
- ارسال دوباره همان توکن idempotent است و پرداخت تکراری ایجاد نمیکند.
- SDK نباید منطق توکن ثابت بازار را برای مایکت اعمال کند.
- مدت حق دسترسی بر اساس محصول و نتیجه استعلام معتبر سرور تعیین میشود.
همگامسازی هنگام راهاندازی SDK
در SDK نسخه ۲، پس از configure و شناسایی مشتری:
- اطلاعات فعلی مشتری دریافت شود.
- برای اپهای بازار و مایکت، خریدهای موجود از Billing SDK خوانده شوند.
- اشتراکها و non-consumableها با عملیات
restoreبه سرور sync شوند. - خریدهای consumable تکمیلنشده وارد چرخه delivery/consume شوند، نه Restore.
- در پایان،
مشتریInfoدوباره دریافت و به listener اپ تحویل شود.
همگامسازی باید در برابر اجرای همزمان، retry شبکه و بازشدن چندباره اپ idempotent باشد.
مدیریت خطا و retry
- خطای validation یا عدم تطابق اپ/محصول نباید بدون تغییر دوباره تلاش شود.
- خطاهای موقت شبکه و فروشگاه باید با exponential backoff تکرار شوند.
- cancel شدن صفحه خرید یک failure فنی نیست و باید جداگانه به اپ میزبان گزارش شود.
- SDK نباید توکن خرید، API key، signature یا JSON خام خرید را در log تولیدی چاپ کند.
- تا دریافت پاسخ قطعی سرور، نتیجه خرید استوری نباید موفق اعلام شود.
ALREADY_PROCESSEDیک نتیجه idempotent موفق است، نه خطای خرید تکراری.
ذخیرهسازی محلی SDK
SDK میتواند یک صف کوچک و رمزگذاریشده برای عملیات تأییدنشده نگه دارد. هر رکورد صف حداقل شامل نوع عملیات، فروشگاه، شناسه محصول و داده لازم برای ارسال مجدد است.
داده صف باید پس از یکی از حالتهای زیر حذف شود:
- پاسخ قطعی
COMPLETED،RESTOREDیاALREADY_PROCESSED؛ - تکمیل چرخه consumable با وضعیت
COMPLETED؛ - خطای دائمی که نیاز به اصلاح تنظیمات یا نسخه اپ دارد.
توکنهای خرید نباید در log یا analytics قرار گیرند.
چکلیست پیادهسازی SDK
- متد عمومی
purchaseبرای سازگاری حفظ شده است. - پرداخت مستقیم همچنان به
/app/v1/purchaseمیرود. - بازار و مایکت از
/app/v2/store/purchasesاستفاده میکنند. - مقدار
operationبرای خریدpurchaseو برای بازیابیrestoreاست. - Restore فقط اشتراک و non-consumable را پردازش میکند.
- محصولات consumable پس از تحویل و تأیید سرور consume میشوند.
- تحویل محتوا با
deliveryIdidempotent است. - retry شبکه باعث خرید، پرداخت، حق دسترسی یا تحویل تکراری نمیشود.
- بازار بر اساس توکن زنجیره و تاریخ معتبر تمدید sync میشود.
- مایکت هر توکن تمدید را مستقل sync میکند.
- پس از خرید یا Restore موفق،
مشتریInfoتازه دریافت میشود. - اطلاعات حساس خرید در log ثبت نمیشود.
- رفتار SDK نسخه ۱ و اپهای فعلی بدون تغییر باقی مانده است.
سناریوهای ضروری تست SDK
- پرداخت مستقیم در SDK نسخه ۲ دقیقاً مانند نسخه قبل باز و تکمیل شود.
- خرید اشتراک بازار پس از تأیید سرور حق دسترسی ایجاد کند.
- ارسال دوباره همان تمدید بازار حق دسترسی را دوباره تمدید نکند.
- تمدید بازار با
validUntilجدید یک دوره جدید ثبت کند. - تمدید مایکت با توکن جدید یک رویداد جدید ثبت کند.
- ارسال دوباره توکن مایکت idempotent باشد.
- Restore اشتراک و non-consumable موفق باشد.
- Restore محصول consumable رد شود.
- قطع شبکه پس از خرید باعث باقیماندن عملیات در صف retry شود.
- کالای consumable قبل از تأیید تحویل consume نشود.
- خطای consume قابل retry باشد و محتوا دوباره تحویل نشود.
- توکن مشتری دیگر یا اپ دیگر قابل استفاده نباشد.