مرجع صدور پروانه

کلاس‌ها و میاناهای LVL

جدول ۱ همه فایل‌های منبع را در «کتابخانه درستی‌سنجی پروانه» (LVL) که ازطریق کیت توسعه نرم‌افزار Android دردسترس است فهرست می‌کند. همه فایل‌ها بخشی از بسته com.android.vending.licensing هستند.

جدول ۱. خلاصه کلاس‌ها و میاناهای کتابخانه LVL.

دسته نام شرح
بررسی پروانه و نتیجه LicenseChecker کلاسی که برای شروع بررسی پروانه، نمونه‌سازی (یا زیرکلاس) می‌کنید.
LicenseCheckerCallback میانایی که برای رسیدگی به نتیجه بررسی پروانه پیاده‌سازی می‌کنید.
خط‌مشی خط‌مشی میانایی که برای تعیین اینکه آیا دسترسی به برنامه براساس پاسخ پروانه مجاز است یا نه پیاده‌سازی می‌کنید.
ServerManagedPolicy پیاده‌سازی پیش‌فرض Policy. از تنظیمات ارائه‌شده توسط سرور صدور پروانه برای مدیریت فضای ذخیره‌سازی محلی داده‌های پروانه، اعتبار پروانه، و تلاش مجدد استفاده می‌کند.
StrictPolicy پیاده‌سازی جایگزین Policy. صدور پروانه را فقط براساس پاسخ مستقیم پروانه از سرور اعمال می‌کند. بدون ذخیره در حافظه نهان یا امتحان مجدد درخواست.
مبهم‌سازی داده‌ها
(اختیاری)
مبهم‌ساز میانایی که اگر از Policy (مانند ServerManagedPolicy) استفاده می‌کنید که داده‌های پاسخ پروانه را در فضای ذخیره‌سازی ماندگار ذخیره می‌کند، آن را پیاده‌سازی می‌کنید. الگوریتم مبهم‌سازی را برای کدگذاری و رمزگشایی داده‌های درحال نوشتن یا خواندن اعمال می‌کند.
AESObfuscator پیاده‌سازی پیش‌فرض «مبهم‌ساز» که از الگوریتم رمزگذاری/رمزگشایی AES برای مبهم‌سازی/غیرمبهم‌سازی داده‌ها استفاده می‌کند.
محدودیت دستگاه
(اختیاری)
DeviceLimiter میانایی که اگر بخواهید استفاده از برنامه را به دستگاه خاصی محدود کنید، پیاده‌سازی می‌کنید. از LicenseValidator فراخوانی شد. پیاده‌سازی DeviceLimiter برای اکثر برنامه‌ها توصیه نمی‌شود زیرا به سرور زیرینه نیاز دارد و ممکن است باعث شود کاربر دسترسی به برنامه‌های دارای پروانه را ازدست بدهد، مگراینکه با دقت طراحی شده باشد.
NullDeviceLimiter پیاده‌سازی پیش‌فرض DeviceLimiter که بدون عملیات است (دسترسی به همه دستگاه‌ها را مجاز می‌کند).
هسته کتابخانه، بدون نیاز به ادغام ResponseData کلاسی که فیلدهای پاسخ پروانه را نگه می‌دارد.
LicenseValidator کلاسی که پاسخ دریافتی از سرور صدور پروانه را رمزگشایی و تأیید می‌کند.
ValidationException کلاسی که خطاهای رخ‌داده هنگام اعتبارسنجی یکپارچگی داده‌های مدیریت‌شده توسط «مبهم‌ساز» را نشان می‌دهد.
PreferenceObfuscator کلاس سودمندی که داده‌های مبهم را در فروشگاه SharedPreferences سیستم می‌نویسد/می‌خواند.
ILicensingService میانای IPC یک‌طرفه که ازطریق آن درخواست بررسی پروانه به مشتری Google Play ارسال می‌شود.
ILicenseResultListener پیاده‌سازی فراخوانی IPC یک‌طرفه که ازطریق آن برنامه پاسخ ناهمگام را از سرور صدور پروانه دریافت می‌کند.

پاسخ سرور

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

جدول ۲. خلاصه فیلدهای پاسخ پروانه که توسط سرور Google Play برگردانده شده است.

فیلد شرح
responseCode کد پاسخ برگردانده‌شده توسط سرور صدور پروانه. کدهای پاسخ در کدهای پاسخ سرور به‌طور خلاصه بیان شده است.
signedData یک رشته الحاقی که داده‌های برگردانده‌شده توسط سرور صدور پروانه را به‌صورت زیر نگه می‌دارد: responseCode|nonce|packageName|versionCode|userId|timestamp:extras.
  • responseCode: کد پاسخ برگردانده‌شده توسط سرور صدور پروانه.
  • ‫nonce: شناسه Nonce درخواست.
  • packageName: نام بسته برنامه برای بررسی پروانه.
  • ‫versionCode: کد نسخه برنامه برای بررسی پروانه.
  • userId: شناسه یکتا برای کاربر به‌ازای هر برنامه، که در آن کاربر یکسان برای برنامه‌های متفاوت شناسه متفاوتی دریافت می‌کند.
  • timestamp: تعداد میلی‌ثانیه‌ها از مبدأ زمانی ‫۱۹۷۰-۰۱-۰۱ ۰۰:۰۰:۰۰ UTC تا درخواست.
  • extras: اطلاعات تکمیلی برای کمک به مدیریت پروانه برنامه. فیلدهای اضافی در موارد اضافی پاسخ سرور مشخص شده‌اند.
signature امضای signedData بااستفاده از کلید مختص برنامه.

کدهای پاسخ سرور

جدول ۳ همه کدهای پاسخ پروانه را که سرور صدور پروانه پشتیبانی می‌کند فهرست می‌کند. به‌طور کلی، برنامه باید همه این کدهای پاسخ را مدیریت کند. به‌طور پیش‌فرض، کلاس LicenseValidator در LVL همه رسیدگی‌های لازم به این کدهای پاسخ را برای شما فراهم می‌کند.

جدول ۳. خلاصه کدهای پاسخ برگردانده‌شده توسط سرور Google Play در پاسخ پروانه.

کد پاسخ نمایش مقدار عدد صحیح شرح امضاشده؟ جایزه‌ها نظرات
LICENSED 0 این برنامه برای کاربر پروانه دارد. کاربر برنامه را خریداری کرده است یا برای بارگیری و نصب نسخه آلفا یا بتای برنامه مجاز است. بله ‫VT، GT، GR دسترسی را طبق محدودیت‌های Policy مجاز کنید.
LICENSED_OLD_KEY 2 پروانه برنامه به کاربر داده شده است، اما نسخه به‌روزشده‌ای از برنامه دردسترس است که با کلید دیگری امضا شده است. بله VT، GT، GR، UT به‌طور اختیاری، دسترسی را براساس محدودیت‌های Policy مجاز کنید.

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

NOT_LICENSED 1 این برنامه برای کاربر پروانه ندارد. نه دسترسی را مجاز نکنید.
ERROR_CONTACTING_SERVER 257 خطای محلی — برنامه Google Play نتوانست به سرور صدور پروانه دسترسی پیدا کند، احتمالاً به‌دلیل مشکلات دردسترس بودن شبکه. نه بررسی پروانه را طبق محدودیت‌های تکرار مجدد Policy تکرار کنید.
ERROR_SERVER_FAILURE 4 خطای سرور — سرور نتوانست جفت کلید برنامه را برای صدور پروانه بار کند. نه بررسی پروانه را طبق محدودیت‌های تکرار مجدد Policy تکرار کنید.
ERROR_INVALID_PACKAGE_NAME 258 خطای محلی — برنامه درخواست بررسی پروانه برای بسته‌ای را کرده است که در دستگاه نصب نشده است. نه بررسی پروانه را دوباره امتحان نکنید.

معمولاً به‌دلیل خطای توسعه ایجاد می‌شود.

ERROR_NON_MATCHING_UID 259 خطای محلی — برنامه درخواست بررسی پروانه برای بسته‌ای را کرده است که UID آن (بسته، جفت شناسه کاربر) با UID برنامه درخواست‌کننده مطابقت ندارد. نه بررسی پروانه را دوباره امتحان نکنید.

معمولاً به‌دلیل خطای توسعه ایجاد می‌شود.

ERROR_NOT_MARKET_MANAGED 3 خطای سرور — برنامه (نام بسته) توسط Google Play شناسایی نشد. نه بررسی پروانه را دوباره امتحان نکنید.

می‌تواند نشان دهد که برنامه ازطریق Google Play منتشر نشده است یا خطای توسعه‌ای در پیاده‌سازی صدور پروانه وجود دارد.

توجه: همان‌طور که در راه‌اندازی محیط آزمایش مستند شده است، کد پاسخ را می‌توان به‌صورت دستی برای توسعه‌دهنده برنامه و هر کاربر آزمایشی ثبت‌شده ازطریق «کنسول Google Play» لغو کرد.

توجه: قبلاً می‌توانستید با بارگذاری نسخه «پیش‌نویس» منتشرنشده، برنامه را آزمایش کنید. این عملکرد دیگر پشتیبانی نمی‌شود؛ درعوض، باید آن را در کانال توزیع آلفا یا بتا منتشر کنید. برای اطلاعات بیشتر، به برنامه‌های پیش‌نویس دیگر پشتیبانی نمی‌شوند مراجعه کنید.

موارد اضافی پاسخ سرور

برای کمک به برنامه شما در مدیریت دسترسی به برنامه درطول دوره استرداد مبلغ برنامه و ارائه اطلاعات دیگر، سرور صدور پروانه چند قطعه اطلاعات را در پاسخ‌های پروانه لحاظ می‌کند. به‌طور خاص، این سرویس مقادیر توصیه‌شده‌ای را برای دوره اعتبار پروانه برنامه، مهلت ارفاقی برای امتحان مجدد، حداکثر تعداد مجاز امتحان مجدد، و تنظیمات دیگر ارائه می‌دهد. اگر برنامه‌تان از فایل‌های توسعه APK استفاده می‌کند، پاسخ شامل نام، اندازه، و نشانی‌های وب فایل نیز می‌شود. سرور تنظیمات را به‌عنوان جفت‌های کلید-مقدار در فیلد «موارد اضافی» پاسخ پروانه اضافه می‌کند.

هر پیاده‌سازی Policy می‌تواند تنظیمات اضافی را از پاسخ پروانه استخراج کند و درصورت نیاز از آن‌ها استفاده کند. پیاده‌سازی پیش‌فرض LVL Policy، ServerManagedPolicy، به‌عنوان یک پیاده‌سازی فعال و نمونه‌ای از نحوه دریافت، ذخیره، و استفاده از تنظیمات عمل می‌کند.

جدول ۴. خلاصه تنظیمات مدیریت پروانه که توسط سرور Google Play در پاسخ پروانه ارائه شده است.

نقش اضافیشرح
VT مُهر زمان اعتبار پروانه. تاریخ/زمان انقضای پاسخ پروانه فعلی (ذخیره‌شده در حافظه پنهان) را مشخص می‌کند و باید در سرور صدور پروانه دوباره بررسی شود. بخش زیر را درباره دوره اعتبار پروانه ببینید.
GT مُهر زمان مهلت ارفاقی. پایان دوره‌ای را مشخص می‌کند که طی آن خط‌مشی ممکن است اجازه دسترسی به برنامه را بدهد، حتی اگر وضعیت پاسخ RETRY باشد.

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

GR حداکثر تعداد تلاش مجدد. مشخص می‌کند که Policy باید چند بررسی متوالی پروانه RETRY را مجاز کند، پیش‌از اینکه دسترسی کاربر به برنامه را رد کند.

این مقدار توسط سرور مدیریت می‌شود، اما مقدار معمول آن «۱۰» یا بیشتر است. بخش زیر را درباره دوره تلاش مجدد و حداکثر تعداد تلاش مجدد ببینید.

UT مُهر زمان به‌روزرسانی. روز/زمانی را که جدیدترین به‌روزرسانی این برنامه بارگذاری و منتشر شده است مشخص می‌کند.

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

FILE_URL1 یا FILE_URL2 نشانی وب برای فایل توسعه (۱ برای فایل اصلی است، ۲ فایل وصله است). از این برای بارگیری فایل ازطریق HTTP استفاده کنید.
FILE_NAME1 یا FILE_NAME2 نام فایل توسعه (۱ برای فایل اصلی است، ۲ برای فایل وصله است). هنگام ذخیره کردن فایل در دستگاه، باید از این نام استفاده کنید.
FILE_SIZE1 یا FILE_SIZE2 اندازه فایل به بایت (۱ برای فایل اصلی، ۲ برای فایل وصله). از این برای کمک به بارگیری و اطمینان از وجود فضای کافی در مکان ذخیره‌سازی مشترک دستگاه قبل‌از بارگیری استفاده کنید.

دوره اعتبار پروانه

سرور صدور پروانه Google Play دوره اعتبار پروانه را برای همه برنامه‌های بارگیری‌شده تنظیم می‌کند. این دوره بیانگر فاصله زمانی‌ای است که در آن وضعیت پروانه برنامه باید به‌عنوان تغییرناپذیر و قابل‌ذخیره در حافظه نهان توسط Policy صدور پروانه در برنامه درنظر گرفته شود. سرور صدور پروانه دوره اعتبار را در پاسخ خود به همه بررسی‌های پروانه لحاظ می‌کند و مُهر زمان پایان اعتبار را به‌عنوان یک مورد اضافی تحت کلید VT به پاسخ اضافه می‌کند. Policy می‌تواند مقدار کلید VT را استخراج کند و از آن برای اجازه دسترسی مشروط به برنامه بدون بررسی مجدد پروانه استفاده کند، تا زمانی که دوره اعتبار منقضی شود.

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

سرور صدور پروانه دوره اعتبار را به‌عنوان ابزاری برای کمک به برنامه مدیریت می‌کند تا پروانه را به‌درستی درطول دوره بازپرداخت ارائه‌شده توسط Google Play برای برنامه‌های پولی اعمال کند. این پاسخ دوره اعتبار را براساس اینکه برنامه خریداری شده است یا نه و اگر خریداری شده است، چه مدت پیش خریداری شده است، تنظیم می‌کند. به‌طور مشخص، سرور دوره اعتبار را به‌صورت زیر تنظیم می‌کند:

  • برای برنامه پولی، سرور دوره اعتبار پروانه اولیه را تنظیم می‌کند تا پاسخ پروانه تا زمانی که برنامه قابل‌استرداد است معتبر باقی بماند. Policy صدور پروانه در برنامه ممکن است نتیجه بررسی اولیه پروانه را ذخیره کند و تا زمانی که دوره اعتبار منقضی نشده باشد، نیازی به بررسی مجدد پروانه ندارد.
  • وقتی برنامه‌ای دیگر قابل‌استرداد نباشد، سرور دوره اعتبار طولانی‌تری را تنظیم می‌کند — معمولاً چند روز.
  • برای برنامه‌های رایگان، سرور دوره اعتبار را روی مقدار بسیار بالایی (long.MAX_VALUE) تنظیم می‌کند. این کار تضمین می‌کند که اگر Policy مُهر زمان اعتبار را به‌صورت محلی ذخیره کرده باشد، نیازی به بررسی مجدد وضعیت پروانه برنامه در آینده نخواهد بود.

پیاده‌سازی ServerManagedPolicy از مُهر زمان استخراج‌شده (mValidityTimestamp) به‌عنوان شرط اصلی برای تعیین اینکه آیا وضعیت پروانه با سرور دوباره بررسی شود یا نه، قبل‌از اینکه به کاربر اجازه دسترسی به برنامه داده شود، استفاده می‌کند.

دوره تلاش مجدد و حداکثر تعداد تلاش مجدد

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

وقتی مشکلات شبکه مانع از بررسی پروانه می‌شود یا در آن وقفه ایجاد می‌کند، سرویس‌گیرنده Google Play با برگرداندن کد پاسخ RETRY به روش processServerResponse() مربوط به Policy، به برنامه اطلاع می‌دهد. درصورت بروز مشکلات سیستمی، مثلاً وقتی برنامه نمی‌تواند با پیاده‌سازی ILicensingService Google Play پیوند برقرار کند، خود کتابخانه LicenseChecker روش خط‌مشی processServerResponse() را با کد پاسخ RETRY فراخوانی می‌کند.

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

سرور Google Play به برنامه کمک می‌کند تا با تنظیم «مهلت ارفاقی» برای تکرار و حداکثر تعداد توصیه‌شده برای تکرار، صدور پروانه را در شرایط خطا مدیریت کند. سرور این مقادیر را در همه پاسخ‌های بررسی پروانه لحاظ می‌کند، و آن‌ها را به‌عنوان موارد اضافی تحت کلیدهای GT و GR پیوست می‌کند.

برنامه Policy می‌تواند موارد اضافی GT و GR را استخراج کند و از آن‌ها برای اجازه دادن مشروط به دسترسی به برنامه به‌صورت زیر استفاده کند:

  • برای بررسی پروانه که منجر به پاسخ RETRY می‌شود، Policy باید کد پاسخ RETRY را در حافظه نهان ذخیره کند و تعداد پاسخ‌های RETRY را افزایش دهد.
  • Policy باید به کاربر اجازه دهد به برنامه دسترسی داشته باشد، مشروط بر اینکه یا مهلت ارفاقی تلاش مجدد هنوز فعال باشد یا حداکثر تعداد تلاش‌های مجدد به‌دست نیامده باشد.

ServerManagedPolicy از مقادیر GT و GR ارائه‌شده توسط سرور، همان‌طور که در بالا توضیح داده شد، استفاده می‌کند. مثال زیر نحوه رسیدگی مشروط به پاسخ‌های تکرار مجدد را در روش allow() نشان می‌دهد. تعداد پاسخ‌های RETRY در روش processServerResponse() حفظ می‌شود، نشان داده نمی‌شود.

کاتلین

fun allowAccess(): Boolean {
    val ts = System.currentTimeMillis()
    return when(lastResponse) {
        LICENSED -> {
            // Check if the LICENSED response occurred within the validity timeout.
            ts <= validityTimestamp  // Cached LICENSED response is still valid.
        }
        RETRY -> {
            ts < lastResponseTime + MILLIS_PER_MINUTE &&
                    // Only allow access if we are within the retry period
                    // or we haven't used up our max retries.
                    (ts <= retryUntil || retryCount <= maxRetries)
        }
        else -> false
    }
}

جاوا

public boolean allowAccess() {
    long ts = System.currentTimeMillis();
    if (lastResponse == LicenseResponse.LICENSED) {
        // Check if the LICENSED response occurred within the validity timeout.
        if (ts <= validityTimestamp) {
            // Cached LICENSED response is still valid.
            return true;
        }
    } else if (lastResponse == LicenseResponse.RETRY &&
                ts < lastResponseTime + MILLIS_PER_MINUTE) {
        // Only allow access if we are within the retry period
        // or we haven't used up our max retries.
        return (ts <= retryUntil || retryCount <= maxRetries);
    }
    return false;
}