Classes e interfaces da LVL
A Tabela 1 lista todos os arquivos de origem na Verificação de Licença Library (LVL, na sigla em inglês) disponível pelo SDK do Android. Todos os arquivos fazem parte do pacote com.android.vending.licensing
.
Categoria | Nome | Descrição |
---|---|---|
Verificação de licença e resultado | LicenseChecker | Classe (ou subclasse) instanciada para iniciar uma verificação de licença. |
LicenseCheckerCallback | Interface implementada para gerenciar o resultado da verificação de licença. | |
Política | Policy | Interface implementada para determinar a permissão de acesso ao app com base na resposta da licença. |
ServerManagedPolicy | Implementação padrão de Policy . Usa as configurações fornecidas pelo servidor de licenciamento para gerenciar o armazenamento local de novas tentativas, dados e validade da licença. |
|
StrictPolicy | Implementação alternativa de Policy . Aplica o licenciamento com base em uma resposta de licença direta exclusiva do servidor. Sem cache ou solicitação de nova tentativa. |
|
Ofuscação de dados (opcional) |
Obfuscator | Interface implementada quando você está usando uma Policy (como ServerManagedPolicy) que cria o cache dos dados de resposta de licença em um armazenamento persistente.
Aplica um algoritmo de ofuscação para codificar e decodificar os dados que estão sendo gravados ou lidos. |
AESObfuscator | Implementação padrão do Obfuscator. Usa o algoritmo de codificação/decodificação AES para ofuscar/desofuscar os dados. | |
Limitação de dispositivos (opcional) |
DeviceLimiter | Interface implementada quando você quer restringir o uso de um apppara um dispositivo específico. Chamado do LicenseValidator. Não é recomendado implementar o DeviceLimiter na maioria dos apps porque ele precisa de um servidor de back-end e, a menos que seja desenvolvido com cuidado, pode fazer com que o usuário perca acesso a apps licenciados. |
NullDeviceLimiter | Implementação padrão do DeviceLimiter. É um ambiente autônomo (permite o acesso a todos os dispositivos). | |
Núcleo da biblioteca, sem necessidade de integração | ResponseData | Classe que contém os campos de uma resposta de licença. |
LicenseValidator | Classe que descriptografa e verifica uma resposta recebida do servidor de licenciamento. | |
ValidationException | Classe que indica erros que ocorrem ao validar a integridade de dados gerenciados por um Obfuscator. | |
PreferenceObfuscator | Classe de utilitário que grava/lê dados ofuscados no armazenamento de SharedPreferences do sistema. |
|
ILicensingService | Interface de IPC unidirecional em que uma solicitação de verificação de licença é transmitida ao cliente do Google Play. | |
ILicenseResultListener | Implementação de callback de IPC unidirecional em que o aplicativo recebe uma resposta assíncrona do servidor de licenciamento. |
Resposta do servidor
A Tabela 2 lista todos os campos de resposta de licença retornados pelo servidor de licenciamento.
Campo | Descrição |
---|---|
responseCode |
O código de resposta retornado pelo servidor de licenciamento. Os códigos de resposta estão descritos em Códigos de resposta do servidor. |
signedData |
Uma concatenação de strings que contém os dados retornados pelo servidor de licenciamento, da seguinte maneira:
responseCode|nonce|packageName|versionCode|userId|timestamp:extras .
|
signature |
A assinatura de signedData usando uma chave específica do app.
|
Códigos de resposta do servidor
A Tabela 3 lista todos os códigos de resposta de licença aceitos pelo servidor de licenciamento. O esperado é que um app consiga processar todos esses códigos de resposta. Por padrão, a classe LicenseValidator na LVL oferece todo o processamento necessário desses códigos para você.
Código de resposta | Representação de valor inteiro | Descrição | Assinado? | Extras | Comentários |
---|---|---|---|---|---|
LICENSED |
0 |
O app está licenciado para o usuário. O usuário comprou ou está autorizado a fazer o download e a instalação da versão Alfa ou Beta do app. | Sim | VT , GT , GR |
Permita o acesso de acordo com as restrições de Policy . |
LICENSED_OLD_KEY |
2 |
O app está licenciado para o usuário, mas há uma versão atualizada disponível que está assinada com uma chave diferente. | Sim | VT , GT , GR , UT |
Opcionalmente, conceda o acesso de acordo com as restrições de Policy .
Pode indicar que o par de chaves usado pela versão instalada do app é inválido ou está comprometido. O app pode permitir o acesso se necessário ou informar ao usuário de um upgrade disponível e limitar o uso até que o upgrade seja feito. |
NOT_LICENSED |
1 |
O app não está licenciado para o usuário. | Não | Não permita o acesso. | |
ERROR_CONTACTING_SERVER |
257 |
Erro local: o app Google Play não conseguiu acessar o servidor de licenciamento, possivelmente devido a problemas de disponibilidade da rede. | Não | Tente fazer a verificação da licença novamente de acordo com os limites de novas tentativas da Policy . |
|
ERROR_SERVER_FAILURE |
4 |
Erro de servidor: não foi possível carregar o par de chaves do app para licenciamento no servidor. | Não | Tente fazer a verificação da licença novamente de acordo com os limites de novas tentativas da Policy .
|
|
ERROR_INVALID_PACKAGE_NAME |
258 |
Erro local: o app solicitou uma verificação de licença para um pacote que não está instalado no dispositivo. | Não | Não tente fazer a verificação da licença de novo.
Geralmente causado por um erro de desenvolvimento. |
|
ERROR_NON_MATCHING_UID |
259 |
Erro local: o app solicitou uma verificação de licença para um pacote cujo UID (par de IDs do usuário e pacote) não corresponde ao pacote do app solicitante. | Não | Não tente fazer a verificação da licença de novo.
Geralmente causado por um erro de desenvolvimento. |
|
ERROR_NOT_MARKET_MANAGED |
3 |
Erro de servidor: o app (nome do pacote) não foi reconhecido pelo Google Play. | Não | Não tente fazer a verificação da licença de novo.
Pode indicar que o app não foi publicado pelo Google Play ou que há um erro de desenvolvimento na implementação do licenciamento. |
Observação: como documentado em Como configurar o ambiente de testes, o código de resposta pode ser modificado manualmente pelo desenvolvedor do app e por usuários de teste registrados pelo Google Play Console.
Observação: antes, era possível testar um app fazendo upload de uma versão de "rascunho" não publicada. Essa funcionalidade não está mais disponível. Agora, você precisa publicá-lo nos canais de distribuição Alfa ou Beta. Para saber mais, consulte Aplicativos de rascunho não são mais compatíveis.
Extras de resposta do servidor
Para ajudar seu app a gerenciar o acesso durante o período de reembolso e fornecer outras informações, o servidor de licenciamento inclui várias informações nas respostas da licença. Especificamente, o serviço fornece valores recomendados para o período de validade da licença do app, período de carência da nova tentativa, contagem máxima permitida de novas tentativas e outras configurações. Se o app usar arquivos de expansão do APK, a resposta também incluirá nomes, tamanhos e URLs de arquivos. O servidor anexará as configurações como pares de chave-valor no campo "extras" da resposta de licença.
Qualquer implementação de Policy
pode extrair as configurações extras da resposta de licença e usá-las conforme necessário. A implementação padrão da Policy
da LVL, ServerManagedPolicy
, serve como uma implementação
funcional e uma ilustração de como coletar, armazenar e usar as
configurações.
Extra | Descrição |
---|---|
VT |
Carimbo de data/hora de validade da licença. Especifica a data e a hora em que a resposta de licença atual (armazenada em cache) expirará e precisará ser verificada novamente no servidor de licenciamento. Consulte a seção abaixo sobre Período de validade da licença. |
GT |
Carimbo de data/hora do período de carência. Especifica o fim do período em que uma
política pode permitir acesso ao app, mesmo que o status da resposta seja
RETRY . O valor é gerenciado pelo servidor. No entanto, um valor típico seria de cinco dias ou mais. Consulte a seção abaixo sobre Período e contagem máxima de novas tentativas. |
GR |
Contagem máxima de novas tentativas. Especifica quantas verificações de licença RETRY consecutivas
a Policy permitirá antes de negar o acesso do usuário ao app.
O valor é gerenciado pelo servidor. No entanto, um valor típico seria "10" ou mais. Consulte a seção abaixo sobre Período e contagem máxima de novas tentativas. |
UT |
Carimbo de data/hora da atualização. Especifica o dia/hora em que a atualização mais recente do app foi enviada e publicada. O servidor retorna este extra apenas para respostas |
FILE_URL1 ou FILE_URL2 |
O URL de um arquivo de expansão: 1 é para o arquivo principal, 2 é o arquivo de patch. Use para fazer o download do arquivo por HTTP. |
FILE_NAME1 ou FILE_NAME2 |
O nome do arquivo de expansão: 1 é para o arquivo principal, 2 é o arquivo de patch. Use esse nome ao salvar o arquivo no dispositivo. |
FILE_SIZE1 ou FILE_SIZE2 |
O tamanho do arquivo em bytes: 1 é para o arquivo principal, 2 é o arquivo de patch. Use para ajudar no download e garantir que haja espaço suficiente disponível no local de armazenamento compartilhado do dispositivo antes do download. |
Período de validade da licença
O servidor de licenciamento do Google Play define um período de validade para todos os apps transferidos por download. O período expressa o intervalo de tempo em que o status de licença de um app será considerado inalterável e armazenável em cache por uma Policy
de licenciamento presente no app. O servidor de licenciamento inclui o período de validade na resposta para todas as verificações de licença, anexando um carimbo de fim de validade da resposta como um extra na chave VT
. Uma Policy
pode extrair a chave-valor VT e usá-la para permitir condicionalmente o acesso ao app sem verificar a licença novamente até que o período de validade expire.
A validade da licença enviará um sinal para uma Policy
de licenciamento quando precisar verificar novamente o status de licenciamento no servidor. O objetivo não é sugerir que um app esteja licenciado para uso. Ou seja, a expiração do período de validade de uma licença não significa que o app não esteja mais licenciado para uso. Ela indica apenas que a Policy
precisa verificar novamente o status de licenciamento no servidor. Desde que o período de validade da licença não tenha expirado, é aceitável que Policy
armazene o status da licença inicial em cache localmente e retorne o status da licença em cache em vez de enviar uma nova verificação de licença ao servidor.
O servidor de licenciamento gerencia o período de validade como um meio de ajudar o app a aplicar adequadamente o licenciamento durante o período de reembolso oferecido pelo Google Play a apps pagos. Ele define o período de validade com base no status e no momento de compra do app. O servidor define um período de validade da seguinte maneira:
- Para um app pago, o servidor define o período de validade da licença inicial para que a resposta da licença permaneça válida pelo período de reembolso. Uma
Policy
de licenciamento no app pode armazenar o resultado da verificação de licença inicial em cache e não será necessário verificar novamente a licença até que o período de validade tenha expirado. - Quando um app não é mais reembolsável, o servidor define um período de validade mais longo, normalmente marcado por um número de dias.
- Para um app sem custo financeiro, o servidor define o período de validade como um valor
muito alto (
long.MAX_VALUE
). Isso garante que, contanto quePolicy
tenha armazenado o carimbo de data/hora de validade localmente, não será necessário verificar novamente o status da licença no futuro.
A implementação de ServerManagedPolicy
usa o carimbo de data/hora extraído (mValidityTimestamp
) como condição principal para determinar se é preciso verificar novamente o status da licença com o servidor antes de permitir que o usuário acesse o app.
Período e contagem máxima de novas tentativas
Em alguns casos, as condições do sistema ou da rede podem impedir que uma verificação de licença de app chegue ao servidor de licenciamento ou que a resposta do servidor chegue ao aplicativo cliente do Google Play. Por exemplo, o usuário pode abrir um app quando não há rede celular ou conexão de dados disponível, como no avião, ou quando a conexão de rede está instável ou o sinal celular está fraco.
Quando problemas de rede impedem ou interrompem uma verificação de licença, o cliente do Google Play notifica o app retornando um código de resposta RETRY
ao método processServerResponse()
da Policy
. No caso de problemas do sistema, como quando o app não consegue se vincular à implementação de ILicensingService
do Google Play, a própria biblioteca de LicenseChecker
chama o método processServerResponse()
da política com um código de resposta RETRY
.
Geralmente, o código de resposta RETRY
é um sinal para o app de que ocorreu um erro que impediu a conclusão de uma verificação de licença.
O servidor do Google Play ajuda um app a gerenciar o licenciamento em condições de erro definindo um "período de carência" e uma contagem máxima recomendada de novas tentativas. O servidor inclui esses valores em todas as respostas de verificação de licença, anexando-os como extras nas chaves GT
e GR
.
A Policy
do app pode extrair os extras GT
e GR
e usá-los para permitir condicionalmente o acesso ao app, da seguinte maneira:
- Para uma verificação de licença que resulte em uma resposta
RETRY
, aPolicy
armazenará o código de respostaRETRY
em cache e incrementará uma contagem de respostasRETRY
. - A
Policy
permitirá que o usuário acesse o app, contanto que o período de carência de novas tentativas permaneça ativo ou que a contagem máxima não tenha sido atingida.
A ServerManagedPolicy
usa os valores GT
e GR
fornecidos pelo servidor conforme descrito acima. O exemplo abaixo mostra o gerenciamento condicional das respostas de nova tentativa no método allow()
. A contagem de respostas RETRY
é mantida no método processServerResponse()
, que não é mostrado.
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; }