LVL-классы и интерфейсы
В таблице 1 перечислены все исходные файлы в библиотеке проверки лицензий (LVL), доступной через Android SDK. Все файлы являются частью пакета com.android.vending.licensing
.
Категория | Имя | Описание |
---|---|---|
Проверка лицензии и результат | Лицензионная проверка | Класс, экземпляр которого вы создаете (или подкласс), чтобы инициировать проверку лицензии. |
ЛицензияCheckerОбратный вызов | Интерфейс, который вы реализуете для обработки результатов проверки лицензии. | |
Политика | Политика | Интерфейс, который вы реализуете, чтобы определить, разрешить ли доступ к приложению на основе ответа лицензии. |
Серверуправляемая политика | Реализация Policy по умолчанию. Использует настройки, предоставленные сервером лицензирования, для управления локальным хранилищем данных лицензии, сроком действия лицензии и повторной попыткой. | |
СтрогаяПолитика | Реализация альтернативной Policy . Принудительное лицензирование основано только на прямом ответе лицензии от сервера. Никакого кэширования или повтора запроса. | |
Обфускация данных (необязательный) | Обфускатор | Интерфейс, который вы реализуете, если используете Policy (например, ServerManagedPolicy), которая кэширует данные ответа лицензии в постоянном хранилище. Применяет алгоритм обфускации для кодирования и декодирования записываемых или читаемых данных. |
AESОбфускатор | Реализация Obfuscator по умолчанию, которая использует алгоритм шифрования/дешифрования AES для запутывания/разобфускации данных. | |
Ограничение устройства (необязательный) | УстройствоОграничитель | Интерфейс, который вы реализуете, если хотите ограничить использование приложения определенным устройством. Вызывается из LicenseValidator. Реализация DeviceLimiter не рекомендуется для большинства приложений, поскольку для этого требуется внутренний сервер и может привести к потере пользователем доступа к лицензированным приложениям, если они не разработаны с осторожностью. |
NullDeviceLimiter | Реализация DeviceLimiter по умолчанию, которая не работает (разрешает доступ ко всем устройствам). | |
Ядро библиотеки, интеграция не требуется | Данные ответа | Класс, содержащий поля ответа лицензии. |
ЛицензияВалидатор | Класс, который расшифровывает и проверяет ответ, полученный от сервера лицензирования. | |
Исключение проверки | Класс, указывающий ошибки, возникающие при проверке целостности данных, управляемых обфускатором. | |
ПредпочтениеОбфускатор | Служебный класс, который записывает/читает запутанные данные в системное хранилище SharedPreferences . | |
ILicensingService | Односторонний интерфейс IPC, по которому запрос на проверку лицензии передается клиенту Google Play. | |
ILicenseResultListener | Реализация одностороннего обратного вызова IPC, посредством которой приложение получает асинхронный ответ от сервера лицензирования. |
Ответ сервера
В таблице 2 перечислены все поля ответа о лицензии, возвращенные сервером лицензирования.
Поле | Описание |
---|---|
responseCode | Код ответа, возвращенный сервером лицензирования. Коды ответов описаны в разделе Коды ответов сервера . |
signedData | Конкатенация строк, содержащая данные, возвращенные сервером лицензирования, следующим образом: responseCode|nonce|packageName|versionCode|userId|timestamp:extras .
|
signature | Подпись signedData с использованием ключа, специфичного для приложения. |
Коды ответов сервера
В Таблице 3 перечислены все коды ответов лицензий, поддерживаемые сервером лицензирования. В общем, приложение должно обрабатывать все эти коды ответа. По умолчанию класс LicenseValidator в LVL обеспечивает всю необходимую обработку этих кодов ответов.
Код ответа | Целочисленное представление | Описание | Подписано? | Дополнительно | Комментарии |
---|---|---|---|---|---|
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 , ответ также включает имена, размеры и URL-адреса файлов. Сервер добавляет настройки в виде пар «ключ-значение» в поле «дополнительно» ответа лицензии.
Любая реализация Policy
может извлекать дополнительные настройки из ответа лицензии и использовать их по мере необходимости. Реализация Policy
LVL по умолчанию, ServerManagedPolicy
, служит рабочей реализацией и иллюстрацией того, как получать, хранить и использовать настройки.
Дополнительный | Описание |
---|---|
VT | Временная метка срока действия лицензии. Указывает дату/время истечения срока действия текущего (кэшированного) ответа лицензии, и его необходимо повторно проверить на сервере лицензирования. См. раздел ниже о сроке действия лицензии . |
GT | Временная метка льготного периода. Указывает конец периода, в течение которого Политика может разрешить доступ к приложению, даже если статус ответа — RETRY .Значение управляется сервером, однако типичное значение составляет 5 или более дней. См. раздел ниже о периоде повторов и максимальном количестве повторов . |
GR | Максимальное количество повторов. Указывает, сколько последовательных проверок лицензии RETRY должна разрешить Policy , прежде чем отказать пользователю в доступе к приложению.Значение управляется сервером, однако типичное значение — «10» или выше. См. раздел ниже о периоде повторов и максимальном количестве повторов . |
UT | Обновить временную метку. Указывает день/время, когда было загружено и опубликовано самое последнее обновление этого приложения. Сервер возвращает эту дополнительную информацию только для ответов |
FILE_URL1 или FILE_URL2 | URL-адрес файла расширения (1 — основной файл, 2 — файл исправления). Используйте это для загрузки файла через HTTP. |
FILE_NAME1 или FILE_NAME2 | Имя файла расширения (1 — основной файл, 2 — файл патча). Вы должны использовать это имя при сохранении файла на устройстве. |
FILE_SIZE1 или FILE_SIZE2 | Размер файла в байтах (1 — основной файл, 2 — файл патча). Используйте это, чтобы облегчить загрузку и убедиться, что перед загрузкой в общем хранилище устройства доступно достаточно места. |
Срок действия лицензии
Сервер лицензирования Google Play устанавливает срок действия лицензии для всех загруженных приложений. Период выражает интервал времени, в течение которого статус лицензии приложения должен считаться неизменным и кэшируемым в соответствии с Policy
лицензирования в приложении. Сервер лицензирования включает период действия в свой ответ на все проверки лицензии, добавляя к ответу метку времени окончания срока действия в качестве дополнительной под ключом VT
. Policy
может извлечь значение ключа VT и использовать его для условного разрешения доступа к приложению без перепроверки лицензии до истечения срока действия.
Срок действия лицензии сигнализирует Policy
лицензирования, когда ей необходимо перепроверить статус лицензирования на сервере лицензирования. Это не означает, что приложение действительно лицензировано для использования. То есть, когда срок действия лицензии приложения истекает, это не означает, что приложение больше не лицензируется для использования — скорее, это указывает лишь на то, что Policy
должна перепроверить статус лицензирования на сервере. Отсюда следует, что до тех пор, пока срок действия лицензии не истек, для Policy
допустимо кэшировать исходный статус лицензии локально и возвращать кэшированный статус лицензии вместо отправки новой проверки лицензии на сервер.
Сервер лицензирования управляет периодом действия, помогая приложению правильно обеспечивать лицензирование в течение периода возврата, предлагаемого Google Play для платных приложений. Он устанавливает срок действия в зависимости от того, было ли приобретено приложение, и если да, то как давно. В частности, сервер устанавливает период действия следующим образом:
- Для платного приложения сервер устанавливает начальный срок действия лицензии, чтобы ответ на лицензию оставался действительным до тех пор, пока приложение подлежит возврату.
Policy
лицензирования в приложении может кэшировать результат первоначальной проверки лицензии и не требует повторной проверки лицензии до истечения срока действия. - Когда заявка больше не подлежит возврату, сервер устанавливает более длительный период действия — обычно несколько дней.
- Для бесплатного приложения сервер устанавливает очень высокое значение периода действия (
long.MAX_VALUE
). Это гарантирует, что, еслиPolicy
локально кэширует метку времени действия, ей не потребуется перепроверять статус лицензии приложения в будущем.
Реализация ServerManagedPolicy
использует извлеченную метку времени ( mValidityTimestamp
) в качестве основного условия для определения того, следует ли перепроверять состояние лицензии на сервере, прежде чем разрешить пользователю доступ к приложению.
Период повторов и максимальное количество повторов
В некоторых случаях условия системы или сети могут помешать проверке лицензии приложения достичь сервера лицензирования или помешать ответу сервера достичь клиентского приложения Google Play. Например, пользователь может запустить приложение, когда отсутствует сотовая сеть или подключение для передачи данных (например, в самолете), или когда сетевое соединение нестабильно или сигнал сотовой связи слабый.
Когда проблемы с сетью препятствуют или прерывают проверку лицензии, клиент Google Play уведомляет приложение, возвращая код ответа RETRY
в метод Policy
processServerResponse()
. В случае системных проблем, например, когда приложение не может связаться с реализацией ILicensingService
Google Play, сама библиотека LicenseChecker
вызывает метод processServerResponse()
с кодом ответа RETRY
.
В общем случае код ответа RETRY
является сигналом приложению о том, что произошла ошибка, не позволившая завершить проверку лицензии.
Сервер Google Play помогает приложению управлять лицензированием в случае ошибки, устанавливая «льготный период» повторных попыток и рекомендуемое максимальное количество повторных попыток. Сервер включает эти значения во все ответы на проверку лицензии, добавляя их в качестве дополнительных под ключами GT
и GR
.
Policy
приложения может извлекать дополнительные элементы GT
и GR
и использовать их для условного разрешения доступа к приложению следующим образом:
- Для проверки лицензии, которая приводит к ответу
RETRY
,Policy
должна кэшировать код ответаRETRY
и увеличивать количество ответовRETRY
. -
Policy
должна разрешать пользователю доступ к приложению при условии, что либо льготный период повторных попыток все еще активен, либо максимальное количество повторных попыток не достигнуто.
ServerManagedPolicy
использует значения GT
и GR
, предоставленные сервером, как описано выше. В примере ниже показана условная обработка ответов на повтор в методеallow allow()
. Количество ответов RETRY
поддерживается в методеprocessServerResponse 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; }