Referencia sobre licencias

Clases e interfaces de la LVL

En la tabla 1, se enumeran todos los archivos de origen de la biblioteca de verificación de licencias (LVL) disponibles con el SDK de Android. Todos los archivos son parte del paquete com.android.vending.licensing.

Tabla 1: Resumen de las clases e interfaces de la biblioteca LVL

Categoría Nombre Descripción
Verificación de licencia y resultado LicenseChecker Es un clase que crea una instancia (o subclase) para iniciar una verificación de licencia.
LicenseCheckerCallback Es la interfaz que implementas para controlar el resultado de la verificación de licencia.
Política Política Es la interfaz que implementas para determinar si debes permitir el acceso a la aplicación en función de la respuesta de la licencia.
ServerManagedPolicy Implementación predeterminada de Policy Utiliza la configuración que proporciona el servidor de licencias para administrar el almacenamiento local de los datos de la licencia, la validez de la licencia y los reintentos.
StrictPolicy Implementación alternativa de Policy. Aplica las licencias basadas en una respuesta de licencia directa del servidor solamente. No hay almacenamiento en caché ni solicitud de reintento.
Ofuscación de datos
(opcional)
Ofuscador Interfaz que implementas si usas un elemento Policy (como ServerManagedPolicy) que almacena datos de respuesta de licencia en un almacenamiento persistente. Aplica un algoritmo de ofuscación para codificar y decodificar datos que se escriben o se leen.
AESObfuscator Es la implementación predeterminada del ofuscador que usa el algoritmo de encriptación o desencriptación AES para ofuscar o desofuscar datos.
Limitación del dispositivo
(opcional)
DeviceLimiter Interfaz que implementas si quieres restringir el uso de una aplicación a un dispositivo específico. Se llama desde LicenseValidator. No se recomienda implementar DeviceLimiter para la mayoría de las aplicaciones, ya que requiere un servidor de backend y puede hacer que el usuario pierda el acceso a las aplicaciones con licencia, a menos que se haya diseñado con cuidado.
NullDeviceLimiter Es la implementación predeterminada de DeviceLimiter que no es operativa (permite el acceso a todos los dispositivos).
Núcleo de la biblioteca; no requiere integración ResponseData Es la clase que contiene los campos de una respuesta de licencia.
LicenseValidator Es la clase que desencripta y verifica una respuesta recibida del servidor de licencias.
ValidationException Es la clase que indica errores que se producen al validar la integridad de los datos que administra un ofuscador.
PreferenceObfuscator Es la clase de utilidad que escribe/lee datos ofuscados en la tienda SharedPreferences del sistema.
ILicensingService Es la interfaz IPC unidireccional sobre la cual se envía una solicitud de verificación de licencia al cliente de Google Play.
ILicenseResultListener Es la implementación de devolución de llamada IPC unidireccional sobre la cual la aplicación recibe una respuesta asíncrona del servidor de licencias.

Respuesta del servidor

En la tabla 2, se enumeran todos los campos de respuesta de licencia que muestra el servidor de licencias.

Tabla 2: Resumen de los campos de respuesta de licencia que muestra el servidor de Google Play

Campo Descripción
responseCode El código de respuesta que muestra el servidor de licencias. Los códigos de respuesta se describen en Códigos de respuesta del servidor.
signedData Una concatenación de cadenas que contiene los datos que muestra el servidor de licencias, de la siguiente manera: responseCode|nonce|packageName|versionCode|userId|timestamp:extras.
  • responseCode: El código de respuesta que muestra el servidor de licencias.
  • nonce: Es el identificador del nonce de la solicitud.
  • packageName: Es el nombre del paquete de la app cuya licencia se debe verificar.
  • versionCode: Es el código de versión de la app para verificar la licencia.
  • userId: Es un ID único para el usuario por app, en el que el mismo usuario obtiene un ID diferente para otra app.
  • timestamp: es la cantidad de milisegundos desde la época del 1970-01-01 00:00:00 UTC hasta la solicitud.
  • extras: Información adicional para ayudar en la administración de licencias de la app. Los campos adicionales se describen en Adicionales de respuesta del servidor.
signature La firma de signedData con una clave específica de la app

Códigos de respuesta del servidor

En la tabla 3, se enumeran todos los códigos de respuesta de licencia admitidos por el servidor de licencias. En general, una aplicación debería manejar todos estos códigos de respuesta. De forma predeterminada, la clase LicenseValidator de la LVL proporciona todo el control necesario de estos códigos de respuesta.

Tabla 3: Resumen de los códigos de respuesta que devuelve el servidor de Google Play en una respuesta de licencia

Código de respuesta Representación de valores de números enteros Descripción ¿Firmado? Adicionales Comentarios
LICENSED 0 La aplicación tiene licencia para el usuario. El usuario compró la aplicación o está autorizado para descargar e instalar la versión Alfa o Beta de la aplicación. VTGT, GR Permitir acceso de acuerdo con restricciones de Policy.
LICENSED_OLD_KEY 2 La aplicación tiene licencia para el usuario, pero hay disponible una versión actualizada de la aplicación que está firmada con una clave diferente. VT, GT, GR, UT Opcionalmente, permite el acceso de acuerdo con las restricciones de Policy.

Puede indicar que el par de claves utilizado por la versión de la aplicación instalada no es válido o está comprometido. La aplicación puede permitir el acceso si es necesario o informar al usuario que hay una actualización disponible y limitar el uso adicional hasta la actualización.

NOT_LICENSED 1 La aplicación no tiene licencia para el usuario. No No permitir el acceso.
ERROR_CONTACTING_SERVER 257 Error local: La aplicación de Google Play no pudo llegar al servidor de licencias, posiblemente debido a problemas de disponibilidad de la red. No Volver a intentar verificar la licencia según los límites de reintentos de Policy.
ERROR_SERVER_FAILURE 4 Error del servidor: El servidor no pudo cargar el par de claves de la aplicación para la licencia. No Volver a intentar verificar la licencia según los límites de reintentos de Policy.
ERROR_INVALID_PACKAGE_NAME 258 Error local: La aplicación solicitó una verificación de licencia para un paquete que no está instalado en el dispositivo. No No vuelvas a intentar la verificación de licencia.

Suele deberse a un error de desarrollo.

ERROR_NON_MATCHING_UID 259 Error local: La aplicación solicitó una verificación de licencia para un paquete cuyo UID (par de paquete, ID de usuario) no coincide con el de la aplicación solicitante. No No vuelvas a intentar la verificación de licencia.

Suele deberse a un error de desarrollo.

ERROR_NOT_MARKET_MANAGED 3 Error del servidor: Google Play no reconoció la aplicación (nombre del paquete). No No vuelvas a intentar la verificación de licencia.

Puede indicar que no se publicó la aplicación a través de Google Play o que hay un error de desarrollo en la implementación de la licencia.

Nota: Tal como se indica en Cómo configurar el entorno de prueba, el desarrollador de aplicaciones y cualquier usuario de prueba registrado pueden anular el código de respuesta manualmente con Google Play Console.

Nota: Antes, se podía probar el funcionamiento de una app subiendo una versión de "borrador" no publicada. Esta funcionalidad ya no se admite; en cambio, debes realizar la publicación en los canales de distribución Alfa y Beta. Para obtener más información, consulta Ya no se admiten apps de borrador.

Adicionales de respuesta del servidor

Para ayudar a que tu aplicación administre el acceso durante su período de reembolso y proporcionar otra información, el servidor de licencias incluye varios datos en las respuestas de la licencia. Específicamente, el servicio proporciona valores recomendados para el período de validez de la licencia de la aplicación, el período de gracia de los reintentos, el recuento de reintentos máximo permitido y otras opciones de configuración. Si tu aplicación usa archivos de expansión de APK, la respuesta también incluye los nombres de archivo, tamaños y URL. El servidor agrega la configuración como pares clave-valor en el campo "Adicionales" de la respuesta de licencia.

Cualquier implementación de Policy puede extraer la configuración adicional de la respuesta de licencia y usarla según sea necesario. La implementación predeterminada de Policy de la LVL, ServerManagedPolicy, sirve como una implementación funcional y una ilustración de cómo obtener, almacenar y usar la configuración.

Tabla 4. Resumen de la configuración de administración de licencias que proporciona el servidor de Google Play en una respuesta de licencia

AdicionalDescripción
VT Marca de tiempo de validez de la licencia. Especifica la fecha/hora en la que vence la respuesta de licencia actual (en caché) y debe volver a comprobarse en el servidor de licencias. Consulta la siguiente sección sobre el período de validez de la licencia.
GT Marca de tiempo del período de gracia. Especifica el final del período durante el cual una política puede permitir el acceso a la aplicación aunque el estado de respuesta sea RETRY.

El servidor administra el valor; sin embargo, un valor típico sería de 5 o más días. Consulta la siguiente sección sobre el período de reintento y recuento máximo de reintentos.

GR Recuento máximo de reintentos. Especifica cuántas comprobaciones de licencia de RETRY consecutivas debe permitir Policy antes de denegar el acceso del usuario a la aplicación.

El servidor administra el valor; sin embargo, un valor típico sería "10" o más. Consulta la siguiente sección sobre el período de reintento y recuento máximo de reintentos.

UT Marca de tiempo de actualización. Especifica el día y la hora en que se subió y se publicó la actualización más reciente de esta aplicación.

El servidor muestra este valor solo para respuestas de LICENSED_OLD_KEYS a fin de permitir que Policy determine cuánto tiempo transcurrió desde que se publicó una actualización con nuevas claves de licencia antes de negarle al usuario acceso a la aplicación.

FILE_URL1 o FILE_URL2 La URL para un archivo de expansión (1 es para el archivo principal, 2 es el archivo de parche). Usa esta opción para descargar el archivo mediante HTTP.
FILE_NAME1 o FILE_NAME2 El nombre del archivo de expansión (1 es para el archivo principal, 2 es el archivo de parche). Debes usar este nombre cuando guardas el archivo en el dispositivo.
FILE_SIZE1 o FILE_SIZE2 El tamaño del archivo en bytes (1 es para el archivo principal, 2 es el archivo de parche). Usa esto para ayudar en la descarga y asegurarte de que haya suficiente espacio disponible en la ubicación de almacenamiento compartido del dispositivo antes de la descarga.

Período de validez de la licencia

El servidor de licencias de Google Play establece un período de validez de licencia para todas las aplicaciones descargadas. El período expresa el intervalo de tiempo durante el cual el estado de la licencia de una aplicación debe considerarse como inmutable y almacenable en caché mediante una licencia de Policy en la aplicación. El servidor de licencias incluye el período de validez en su respuesta a todas las verificaciones de licencia y agrega una marca de tiempo de finalización a la respuesta como un extra con la clave VT. Un elemento Policy puede extraer el valor clave VT y usarlo para permitir el acceso condicional a la aplicación sin volver a verificar la licencia, hasta que venza el período de validez.

La validez de la licencia le indica al elemento Policy de una licencia cuándo debe volver a verificar el estado de la licencia con el servidor de licencias. No tiene como fin indicar si una aplicación está realmente autorizada para su uso. Es decir, cuando vence el período de validez de la licencia de una aplicación, no significa que la aplicación ya no tiene licencia para su uso, sino que solo indica que Policy debe volver a verificar el estado de la licencia con el servidor. De ello se desprende que, siempre que no haya vencido el período de validez de la licencia, es aceptable que el elemento Policy almacene en caché el estado de la licencia inicial de forma local y devuelva el estado de la licencia en caché en lugar de enviar una nueva verificación de licencia al servidor.

El servidor de licencias administra el período de validez como un medio para ayudar a la aplicación a aplicar correctamente las licencias durante el período de reembolso que ofrece Google Play para aplicaciones pagas. Establece el período de validez en función de si se compró la aplicación y, de ser así, hace cuánto tiempo. Específicamente, el servidor establece un período de validez de la siguiente manera:

  • En el caso de una aplicación pagada, el servidor establece el período de validez de la licencia inicial para que la respuesta de la licencia siga siendo válida mientras la aplicación sea reembolsable. Una licencia de Policy de la aplicación puede almacenar en caché el resultado de la verificación inicial de la licencia y no necesita volver a verificar la licencia hasta que el período de validez haya vencido.
  • Cuando una aplicación ya no es reembolsable, el servidor establece un período de validez más largo (generalmente, de varios días).
  • En el caso de una aplicación gratuita, el servidor establece el período de validez en un valor muy alto (long.MAX_VALUE). Esto garantiza que, siempre que Policy haya almacenado localmente la marca de tiempo de validez, no será necesario volver a comprobar el estado de la licencia de la aplicación en el futuro.

La implementación de ServerManagedPolicy usa la marca de tiempo extraída (mValidityTimestamp) como condición principal para determinar si se debe volver a verificar el estado de la licencia con el servidor antes de permitir que el usuario acceda a la aplicación.

Período de reintento y recuento máximo de reintentos

En algunos casos, las condiciones del sistema o de la red pueden evitar que la verificación de licencia de una aplicación llegue al servidor de licencias o que la respuesta del servidor llegue a la aplicación cliente de Google Play. Por ejemplo, el usuario puede iniciar una aplicación cuando no hay una red móvil o conexión de datos disponible (como en un avión) o cuando la conexión de red es inestable o débil.

Si los problemas de red impiden o interrumpen una verificación de licencia, el cliente de Google Play notifica a la aplicación mediante un código de respuesta RETRY al método processServerResponse() de Policy. En el caso de que haya problemas en el sistema, como cuando la aplicación no puede vincularse con la implementación de ILicensingService de Google Play, la propia biblioteca de LicenseChecker llama al método processServerResponse() de la política con un código de respuesta RETRY.

En general, el código de respuesta de RETRY es una señal que se envía a la aplicación para indicar que se produjo un error que impidió que se completara una verificación de licencia.

El servidor de Google Play ayuda a una aplicación a administrar las licencias en condiciones de error al establecer un "período de gracia" de reintento y un recuento máximo de reintentos recomendado. El servidor incluye estos valores en todas las respuestas de verificación de licencia y los agrega como extras con las claves GT y GR.

La aplicación de Policy puede extraer los objetos GT y GR adicionales, y usarlos para permitir el acceso condicional a la aplicación, de la siguiente manera:

  • Para una verificación de licencia que dé como resultado una respuesta de RETRY, Policy debe almacenar en caché el código de respuesta de RETRY e incrementar un recuento de respuestas de RETRY.
  • El elemento Policy debe permitir que el usuario acceda a la aplicación, siempre que el período de gracia de reintentos continúe activo o que no se haya alcanzado el recuento máximo de reintentos.

ServerManagedPolicy utiliza los valores GT y GR que proporciona el servidor como se describió más arriba. En el siguiente ejemplo, se muestra el manejo condicional de las respuestas de reintento en el método allow(). Se mantiene el recuento de respuestas de RETRY en el método processServerResponse() (no se muestra).

Kotlin

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
    }
}

Java

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;
}