Aggiunta della verifica delle licenze lato client all'app

Avviso : quando l'app esegue la procedura di verifica della licenza su lato client, è più facile per i potenziali utenti malintenzionati modificare o rimuovere la logica associata a questo processo di verifica.

Per questo motivo, ti invitiamo vivamente a eseguire l'upgrade sul lato server verifica delle licenze.

Dopo aver configurato un account publisher e un ambiente di sviluppo (consulta la sezione Configurazione delle licenze), puoi aggiungere la verifica della licenza a l'app con la License Verification Library (LVL).

L'aggiunta della verifica della licenza con LVL prevede le seguenti attività:

  1. Aggiungi l'autorizzazione per la licenza al file manifest della tua applicazione.
  2. Implementazione di un criterio: puoi scegliere una delle implementazioni complete fornite nella LVL o crearne una personalizzata.
  3. Implementare un Offuscatore, se Policy memorizzerà nella cache i dati delle risposte alle licenze.
  4. Aggiunta di codice per verificare la licenza nella pagina principale dell'applicazione Attività.
  5. Implementare un DeviceLimiter (facoltativo e non consigliato per per la maggior parte delle applicazioni).

Nelle sezioni seguenti vengono descritte queste attività. Al termine integrazione, dovresti essere in grado di compilare correttamente la tua applicazione e iniziare il test, come descritto in Configurazione del test Ambiente.

Per una panoramica del set completo di file sorgente inclusi nella LVL, consulta il Riepilogo delle classi LVL. e interfacce.

Aggiunta dell'autorizzazione di licenza

Per utilizzare l'applicazione Google Play per inviare un controllo delle licenze al server, l'applicazione deve richiedere l'autorizzazione appropriata, com.android.vending.CHECK_LICENSE. Se la tua applicazione non dichiara l'autorizzazione per la licenza, ma tenta di avviare un controllo delle licenze, l'LVL genera un'eccezione di sicurezza.

Per richiedere l'autorizzazione per la licenza nella tua domanda, dichiara un <uses-permission> come elemento secondario di <manifest>, come segue:

<uses-permission android:name="com.android.vending.CHECK_LICENSE" />

Ad esempio, ecco come l'applicazione di esempio LVL dichiara l'autorizzazione:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...">
    <!-- Devices >= 3 have version of Google Play that supports licensing. -->
    <uses-sdk android:minSdkVersion="3" />
    <!-- Required permission to check licensing. -->
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />
    ...
</manifest>

Nota:al momento non puoi dichiarare CHECK_LICENSE nel manifest del progetto della libreria LVL, perché SDK Tools non lo unisce nei manifest dei pod diverse applicazioni. Devi invece dichiarare l'autorizzazione in ogni dipendente del file manifest dell'applicazione.

Implementazione di un criterio

Il servizio di licenze di Google Play non determina autonomamente se un l'utente a cui è stata assegnata una determinata licenza dovrebbe avere accesso alla tua applicazione. Questa responsabilità è invece lasciata all'implementazione di Policy che fornisci tu. nella tua applicazione.

Il criterio è un'interfaccia dichiarata dalla LVL, progettata per contenere le tue la logica dell'applicazione per consentire o impedire l'accesso dell'utente, in base al risultato di un controllo delle licenze. Per utilizzare l'LVL, la tua applicazione deve fornire una implementazione di Policy.

L'interfaccia Policy dichiara due metodi, allowAccess() e processServerResponse(), che vengono chiamati da un LicenseChecker durante l'elaborazione di una risposta dal server delle licenze. Inoltre, dichiara enum chiamato LicenseResponse, che specifica la risposta della licenza valore trasmesso nelle chiamate a processServerResponse().

  • processServerResponse() ti consente di pre-elaborare la risposta non elaborata i dati ricevuti dal server delle licenze, prima di stabilire se concedere l'accesso.

    Una tipica implementazione estrae alcuni o tutti i campi dalla licenza di risposta e archiviare i dati localmente in un archivio permanente, ad esempio SharedPreferences di spazio di archiviazione per garantire che i dati accessibile tramite chiamate delle applicazioni e cicli di spegnimento e riaccensione dei dispositivi. Ad esempio: Policy manterrà il timestamp dell'ultimo controllo della licenza riuscito, numero di nuovi tentativi, il periodo di validità della licenza e informazioni simili in un un archivio permanente, anziché reimpostare i valori ogni volta che l'applicazione è stato avviato.

    Quando i dati delle risposte vengono archiviati localmente, Policy deve garantire che i dati offuscato (vedi Implementazione di un offuscatore, di seguito).

  • allowAccess() stabilisce se concedere all'utente l'accesso a la tua applicazione, in base a tutti i dati disponibili per le risposte alle licenze (da server di licenze o dalla cache) o altre informazioni specifiche dell'applicazione. Per Ad esempio, la tua implementazione di allowAccess() potrebbe prevedere criteri aggiuntivi dell'account, come l'utilizzo o altri dati recuperati da un di backend. In tutti i casi, un'implementazione di allowAccess() deve restituire true solo se l'utente dispone della licenza per utilizzare il come stabilito dal server di licenze o se è presente una problema di rete o di sistema che impedisce il completamento del controllo della licenza. Nella in questi casi, la tua implementazione può mantenere un conteggio delle risposte di nuovo tentativo e consentire temporaneamente l'accesso fino al completamento del successivo controllo della licenza.

Per semplificare la procedura di aggiunta delle licenze alla tua applicazione e fornire un'illustrazione di come dovrebbe essere progettato un Policy, l'LVL include due implementazioni complete di Policy, che puoi utilizzare senza modifiche o alle tue esigenze:

  • ServerManagedPolicy, un'istanza di Policy flessibile che utilizza le impostazioni fornite dal server e le risposte memorizzate nella cache per gestire l'accesso su condizioni di rete diverse.
  • StrictPolicy, che non memorizza nella cache nessuna risposta e consente l'accesso solo se il server restituisce un oggetto la risposta corretta.

Per la maggior parte delle applicazioni, l'uso di ServerManagedPolicy è molto consigliato. ServerManagedPolicy è l'impostazione predefinita di LVL ed è integrata dell'applicazione di esempio LVL.

Linee guida per le norme personalizzate

Nell'implementazione delle licenze, puoi usare una delle norme complete specificato nel valore LVL (ServerManagedPolicy o StrictPolicy) oppure puoi creare un una norma personalizzata. Per qualsiasi tipo di norma personalizzata, esistono diverse impostazioni importanti i punti da comprendere e tenere in considerazione nell'implementazione.

Il server di licenze applica limiti generali alle richieste per evitare un utilizzo eccessivo di risorse che potrebbero causare un denial of service. Quando un'applicazione supera il limite di richieste, il server di licenze restituisce una risposta 503, che trasmesso all'applicazione come un errore generale del server. Ciò significa che la risposta relativa alle licenze sarà disponibile per l'utente fino alla reimpostazione del limite, possono influire sull'utente per un periodo indefinito.

Se stai progettando una norma personalizzata, ti consigliamo di fare in modo che Policy:

  1. Memorizza nella cache (e offusca correttamente) la risposta alla licenza più recente con esito positivo nello spazio di archiviazione permanente locale.
  2. Restituisce la risposta memorizzata nella cache per tutti i controlli delle licenze, finché la risposta memorizzata nella cache sia valida, anziché effettuare una richiesta al server di licenze. Impostazione della validità della risposta in base al valore VT fornito dal server è vivamente consigliato. Consulta Ulteriori opzioni per le risposte del server per ulteriori informazioni.
  3. Utilizza un periodo di backoff esponenziale se ritenta eventuali richieste del risultato errori. Tieni presente che i nuovi tentativi automatici del client Google Play non sono andati a buon fine. pertanto, nella maggior parte dei casi non è necessario che il tuo Policy esegua un nuovo tentativo.
  4. Prevede un "periodo di tolleranza" che permette all'utente di accedere per un periodo di tempo limitato o per un numero di utilizzi, mentre è in corso il controllo delle licenze. nuovo tentativo. Il periodo di tolleranza va a vantaggio dell'utente, in quanto consente l'accesso fino al successivo controllo delle licenze può essere completato correttamente e avvantaggiarti inserendo un se non è disponibile una risposta valida per l'accesso alla tua applicazione disponibili.

Progettare il Policy secondo le linee guida indicate sopra è fondamentale, perché garantisce la migliore esperienza possibile agli utenti offrendoti un controllo efficace sull'applicazione anche in condizioni di errore.

Tieni presente che qualsiasi Policy può utilizzare le impostazioni fornite dal server di licenze per consentono di gestire la validità e la memorizzazione nella cache, il periodo di tolleranza per i nuovi tentativi e altro ancora. L'estrazione del le impostazioni fornite dal server sono semplici e il loro utilizzo è molto consigliato. Vedi l'implementazione di ServerManagedPolicy per un esempio di come estrarre e utilizzare gli extra. Per un elenco delle impostazioni del server e informazioni su su come utilizzarle, consulta Risposta del server Extra.

Criterio gestito dal server

La LVL include un'implementazione completa e consigliata dell'Policy chiamata ServerManagedPolicy. L'implementazione è integrata LVL e il valore predefinito è Policy nella raccolta.

ServerManagedPolicy fornisce tutte le funzionalità di gestione della licenza e riprova diverse. Memorizza nella cache tutti i dati delle risposte localmente in un SharedPreferences, offuscandolo con dell'applicazione Obfuscator. Ciò garantisce che la risposta relativa alla licenza i dati sono sicuri e permangono per tutti i cicli di spegnimento e riaccensione del dispositivo. Criterio gestito dal server fornisce implementazioni concrete dei metodi di interfaccia processServerResponse(), allowAccess() e anche include una serie di metodi e tipologie di supporto per la gestione delle licenze diverse.

È importante sottolineare che una funzionalità chiave di ServerManagedPolicy è l'uso di le impostazioni fornite dal server come base per la gestione delle licenze in dell'applicazione in base a diverse condizioni di rete e di errore. Quando un'applicazione contatta il server di Google Play per un controllo delle licenze, aggiunge diverse impostazioni sotto forma di coppie chiave/valore nel campo degli extra di alcune tipi di risposte alle licenze. Ad esempio, il server fornisce valori consigliati per periodo di validità della licenza dell'applicazione, periodo di tolleranza per i nuovi tentativi e limite massimo consentito numero di nuovi tentativi. ServerManagedPolicy estrae i valori dalla classe risposta alla licenza nel relativo metodo processServerResponse() e nei controlli nel suo metodo allowAccess(). Per un elenco dei parametri forniti dal server utilizzate da ServerManagedPolicy, consulta Risposta del server Extra.

Per comodità, prestazioni ottimali e vantaggio dell'utilizzo delle impostazioni delle licenze dal server di Google Play, utilizzando ServerManagedPolicy come è vivamente consigliata la licenza di Policy.

Se sei preoccupato per la sicurezza dei dati delle risposte alle licenze che vengono archiviati localmente in SharedPreferences, puoi utilizzare un offuscamento più forte o progettare un Policy più restrittivo che non archivi i dati delle licenze. LVL include un esempio di Policy. Consulta StrictPolicy per ulteriori informazioni.

Per utilizzare ServerManagedPolicy, importalo nella tua attività, crea un e passiamo un riferimento all'istanza quando crei LicenseChecker. Consulta Creare istanze di LicenseChecker e LicenseCheckerCallback per ulteriori informazioni.

Criteriorigoroso

L'LVL include un'implementazione completa alternativa dell'interfaccia Policy chiamato StrictPolicy. L'implementazione di StrictPolicy offre una limitazione rispetto a ServerManagedPolicy, in quanto non consente all'utente di accedere l'applicazione a meno che non venga ricevuta una risposta relativa alla licenza dal server all'indirizzo che indica che l'utente dispone della licenza.

La funzionalità principale di StrictPolicy è che non memorizza nessuno i dati delle risposte alle licenze localmente, in un archivio permanente. Poiché non vengono archiviati dati, le richieste di nuovo tentativo non vengono monitorate e le risposte memorizzate nella cache non possono essere utilizzate per soddisfare controlli delle licenze. Policy consente l'accesso solo se:

  • La risposta relativa alla licenza viene ricevuta dal server di licenze e
  • La risposta relativa alla licenza indica che l'utente dispone della licenza per accedere al un'applicazione.

L'utilizzo di StrictPolicy è appropriato se la tua principale preoccupazione è garantire che, in tutti i casi possibili, nessun utente sarà autorizzato ad accedere all'applicazione a meno che viene confermato che l'utente è autorizzato al momento dell'utilizzo. Inoltre, Policy Controller offre una sicurezza leggermente superiore rispetto a ServerManagedPolicy, poiché non ci sono dati memorizzati nella cache locale, non c'è modo che un utente malintenzionato possa manomettere con i dati memorizzati nella cache e di ottenere l'accesso all'applicazione.

Allo stesso tempo, questo Policy rappresenta una sfida per gli utenti normali, poiché significa che non potranno accedere all'applicazione in assenza di rete (rete cellulare o Wi-Fi) disponibile. Un altro effetto collaterale è che invierà al server più richieste di controllo delle licenze, poiché l'uso di non è possibile ottenere una risposta memorizzata nella cache.

Nel complesso, queste norme rappresentano un compromesso tra la praticità degli utenti per una sicurezza assoluta e un controllo sull'accesso. Valuta il compromesso con attenzione prima di utilizzare questo Policy.

Per utilizzare StrictPolicy, importalo nella tua attività, crea un'istanza, e passare un riferimento a quest'ultimo durante la creazione di LicenseChecker. Consulta Istanziare LicenseChecker e LicenseCheckerCallback per ulteriori informazioni.

Una tipica implementazione di Policy deve salvare i dati delle risposte alle licenze per di un'applicazione in un archivio permanente, in modo che sia accessibile le chiamate alle applicazioni e i cicli di spegnimento e riaccensione del dispositivo. Ad esempio, Policy mantenere il timestamp dell'ultimo controllo della licenza riuscito, il numero di nuovi tentativi il periodo di validità della licenza e informazioni simili in un archivio permanente, anziché reimpostare i valori a ogni avvio dell'applicazione. La Policy predefinito incluso in LVL, ServerManagedPolicy, archivia risposta alla licenza di dati in un'istanza SharedPreferences, per garantire che i dati sono permanenti.

Perché Policy utilizzerà i dati delle risposte alle licenze memorizzati per determinare se per consentire o negare l'accesso all'applicazione, deve garantire che qualsiasi i dati archiviati sono sicuri e non possono essere riutilizzati o manipolati da un utente root su un dispositivo. Nello specifico, Policy deve sempre offuscare i dati prima di archiviarli utilizzando una chiave univoca per l'applicazione e il dispositivo. Offuscamento tramite una chiave specifica per l'applicazione e per il dispositivo è fondamentale, impedisce la condivisione dei dati offuscati tra le applicazioni dispositivi mobili.

L'LVL aiuta l'applicazione ad archiviare i dati delle risposte alle licenze in un sicura e persistente. Innanzitutto, fornisce un valore Obfuscator che consenta all'applicazione di fornire l'algoritmo di offuscamento per i dati archiviati. Basandosi su questo, l'LVL fornisce la classe di supporto PreferenceObfuscator, che gestisce la maggior parte del lavoro di chiamata Obfuscator dell'applicazione e di leggere e scrivere i dati offuscati in un SharedPreferences istanza.

L'LVL fornisce un'implementazione Obfuscator completa denominata AESObfuscator che utilizza la crittografia AES per offuscare i dati. Puoi Utilizzare AESObfuscator nella tua applicazione senza modifiche o adattarlo alle tue esigenze. Se utilizzi un Policy (ad esempio ServerManagedPolicy) che memorizza nella cache i dati delle risposte alle licenze, utilizzando AESObfuscator come per la tua implementazione di Obfuscator. Per ulteriori informazioni, consulta la sezione successiva.

AESOoffuscatore

La LVL include un'implementazione completa e consigliata dell'Obfuscator chiamata AESObfuscator. L'implementazione è integrata L'applicazione di esempio LVL e viene utilizzata come Obfuscator predefinita nella libreria.

AESObfuscator offre un offuscamento sicuro dei dati utilizzando AES per crittografare e decriptare i dati mentre sono scritti o letti dallo spazio di archiviazione. Obfuscator avvia la crittografia utilizzando tre campi di dati forniti dall'applicazione:

  1. Un sale: un array di byte casuali da utilizzare per ogni (non)offuscamento.
  2. Una stringa identificatore dell'applicazione, in genere il nome del pacchetto dell'applicazione.
  3. Una stringa di identificazione del dispositivo, derivata da tante origini specifiche del dispositivo il più possibile, in modo da renderla il più possibile unica.

Per utilizzare AESObfuscator, importalo prima nella tua Attività. Dichiara come privato statico finale per contenere i byte di sale e inizializzarli a 20 in modo casuale di byte generati.

Kotlin

// Generate 20 random bytes, and put them here.
private val SALT = byteArrayOf(
        -46, 65, 30, -128, -103, -57, 74, -64, 51, 88,
        -95, -45, 77, -117, -36, -113, -11, 32, -64, 89
)

Java

...
    // Generate 20 random bytes, and put them here.
    private static final byte[] SALT = new byte[] {
     -46, 65, 30, -128, -103, -57, 74, -64, 51, 88, -95,
     -45, 77, -117, -36, -113, -11, 32, -64, 89
     };
    ...

Quindi, dichiara una variabile che contenga un identificatore di dispositivo e genera un valore per necessario in qualsiasi modo. Ad esempio, l'applicazione di esempio inclusa nella LVL interroga le impostazioni di sistema android.Settings.Secure.ANDROID_ID, univoco per ogni dispositivo.

Tieni presente che, a seconda delle API che utilizzi, la tua applicazione potrebbe dover richiedere autorizzazioni aggiuntive per acquisire informazioni specifiche del dispositivo. Ad esempio, per eseguire query su TelephonyManager per ottenere l'IMEI del dispositivo o i dati correlati, l'applicazione dovrà inoltre richiedere il android.permission.READ_PHONE_STATE autorizzazione nel relativo file manifest.

Prima di richiedere nuove autorizzazioni al unico scopo di acquisire specifiche per il dispositivo da utilizzare in Obfuscator, considera l'utilizzo in che modo questa operazione potrebbe influire sulla tua applicazione o sul suo filtro su Google Play poiché con alcune autorizzazioni gli strumenti di creazione dell'SDK possono aggiungere il relativo <uses-feature> associato).

Infine, costruisci un'istanza di AESObfuscator, passando il sale, identificatore dell'applicazione e dell'identificatore del dispositivo. Puoi creare l'istanza direttamente, mentre crei i tuoi Policy e LicenseChecker. Ad esempio:

Kotlin

    ...
    // Construct the LicenseChecker with a Policy.
    private val checker = LicenseChecker(
            this,
            ServerManagedPolicy(this, AESObfuscator(SALT, packageName, deviceId)),
            BASE64_PUBLIC_KEY
    )
    ...

Java

    ...
    // Construct the LicenseChecker with a Policy.
    checker = new LicenseChecker(
        this, new ServerManagedPolicy(this,
            new AESObfuscator(SALT, getPackageName(), deviceId)),
        BASE64_PUBLIC_KEY // Your public licensing key.
        );
    ...

Per un esempio completo, vedi MainActivity nell'applicazione di esempio LVL.

Controllare la licenza da un'attività

Dopo aver implementato un'Policy per la gestione dell'accesso all'applicazione, il passaggio successivo consiste nell'aggiungere un controllo della licenza alla tua applicazione, che avvia una query al server di licenze, se necessario, e gestisce l'accesso all'applicazione in base la risposta sulla licenza. Tutto il lavoro di aggiunta del controllo e della gestione delle licenze la risposta viene eseguita nel file di origine Activity principale.

Per aggiungere il controllo della licenza e gestire la risposta, devi:

  1. Aggiungere importazioni
  2. Implementa LicenseCheckerCallback come classe interna privata
  3. Crea un gestore per la pubblicazione di LicenseCheckerCallback nel thread dell'interfaccia utente
  4. Istante LicenseChecker e LicenseCheckerCallback
  5. Chiama checkAccess() per avviare il controllo delle licenze
  6. Incorpora la chiave pubblica per le licenze
  7. Chiama il metodo onDestroy() di LicenseChecker per chiudere le connessioni IPC.

Nelle sezioni seguenti vengono descritte queste attività.

Panoramica del controllo della licenza e della risposta

Nella maggior parte dei casi, devi aggiungere il controllo delle licenze alla pagina principale Activity, nel metodo onCreate(). Questo assicura che, quando l'utente avvia direttamente la tua applicazione, il controllo della licenza verrà richiamato immediatamente. In alcuni casi, puoi aggiungere controlli delle licenze di questi luoghi. Ad esempio, se la tua applicazione include più attività componenti che altre applicazioni possono iniziare con Intent, potresti aggiungere controlli delle licenze in queste attività.

Un controllo delle licenze prevede due azioni principali:

  • Una chiamata a un metodo per avviare il controllo delle licenze: nell'LVL, una chiamata al metodo checkAccess() di un oggetto LicenseChecker che che crei.
  • Un callback che restituisce il risultato del controllo delle licenze. Nel LVL, un'interfaccia LicenseCheckerCallback implementata da te. La dichiara due metodi, allow() e dontAllow(), che vengono richiamati dalla libreria in base al risultato del controllo delle licenze. Puoi implementare questi due metodi con qualsiasi logica per consentire o impedire l'accesso dell'utente alla tua applicazione. Tieni presente che questi metodi non determinano se consentire l'accesso, ma è responsabilità dell'implementazione di Policy. Piuttosto, questi forniscono semplicemente i comportamenti dell'applicazione per come consentire e non consentire l'accesso (e gestire gli errori dell'applicazione).

    I metodi allow() e dontAllow() forniscono un "motivo" per la risposta, che può essere uno dei valori Policy, LICENSED, NOT_LICENSED o RETRY. In particolare, dovresti gestire il caso in cui il metodo riceve la risposta RETRY per dontAllow() e fornisce all'utente una "Riprova" accaduto perché il servizio non era disponibile durante richiesta.

Figura 1. Panoramica di tipica interazione con il controllo delle licenze.

Il diagramma riportato sopra illustra come avviene un tipico controllo delle licenze:

  1. Il codice nell'Attività principale dell'applicazione crea un'istanza di LicenseCheckerCallback e LicenseChecker di oggetti. Quando si crea LicenseChecker, il codice passa Context, un'implementazione Policy da usare e chiave pubblica dell'account editore per la licenza come parametri.
  2. Il codice quindi chiama il metodo checkAccess() sul Oggetto LicenseChecker. L'implementazione del metodo chiama Policy per determinare esiste una risposta a una licenza valida memorizzata nella cache localmente, SharedPreferences.
    • In questo caso, l'implementazione di checkAccess() chiama allow().
    • In caso contrario, LicenseChecker avvia una richiesta di controllo della licenza che viene inviata al server di licenze.

    Nota: il server di licenze restituisce sempre LICENSED quando esegui un controllo della licenza di un'applicazione bozza.

  3. Quando riceve una risposta, LicenseChecker crea un LicenseValidator che verifica i dati della licenza firmata ed estrae i campi della risposta, quindi le passa al tuo Policy per un'ulteriore valutazione.
    • Se la licenza è valida, Policy memorizza la risposta nella cache in SharedPreferences e invia una notifica allo strumento di convalida, che chiama lo strumento allow() nell'oggetto LicenseCheckerCallback.
    • Se la licenza non è valida, Policy invia una notifica allo strumento di convalida, che chiama il metodo dontAllow() su LicenseCheckerCallback.
  4. In caso di errore locale o del server recuperabile, ad esempio quando la rete non disponibile per inviare la richiesta, LicenseChecker passa una risposta RETRY a il metodo processServerResponse() dell'oggetto Policy.

    Inoltre, entrambi i metodi di callback allow() e dontAllow() ricevono un reason argomento. In genere, il motivo del metodo allow() è Policy.LICENSED o Policy.RETRY, mentre dontAllow() è Policy.NOT_LICENSED o Policy.RETRY. I valori di risposta sono utili per mostrare una risposta appropriata per l'utente, ad esempio fornendo un "Riprova" quando dontAllow() risponde con Policy.RETRY, il che potrebbe essere dovuto al fatto che il servizio non disponibile.

  5. In caso di errore dell'applicazione, ad esempio quando l'applicazione tenta di controlla la licenza di un nome pacchetto non valido, LicenseChecker passa un errore risposta al applicationError() di LicenseCheckerCallback .

Tieni presente che, oltre ad avviare il controllo della licenza e gestire descritti nelle sezioni seguenti, la tua applicazione deve avere anche per fornire un'implementazione delle norme e, se Policy archivia i dati di risposta (ad esempio ServerManagedPolicy), un'implementazione Obfuscator.

Aggiungi importazioni

Per prima cosa, apri il file della classe dell'attività principale dell'applicazione ed esegui l'importazione LicenseChecker e LicenseCheckerCallback del pacchetto LVL.

Kotlin

import com.google.android.vending.licensing.LicenseChecker
import com.google.android.vending.licensing.LicenseCheckerCallback

Java

import com.google.android.vending.licensing.LicenseChecker;
import com.google.android.vending.licensing.LicenseCheckerCallback;

Se utilizzi l'implementazione Policy predefinita fornita con l'LVL, ServerManagedPolicy, importalo anche insieme all'AESObfuscator. Se utilizzando un elemento Policy o Obfuscator personalizzato, importali.

Kotlin

import com.google.android.vending.licensing.ServerManagedPolicy
import com.google.android.vending.licensing.AESObfuscator

Java

import com.google.android.vending.licensing.ServerManagedPolicy;
import com.google.android.vending.licensing.AESObfuscator;

Implementare LicenseCheckerCallback come classe interna privata

LicenseCheckerCallback è un'interfaccia fornita da LVL per la gestione il risultato di un controllo delle licenze. Per supportare le licenze tramite la LVL, devi: implementare LicenseCheckerCallback e i suoi metodi per consentire o meno l'accesso all'applicazione.

Il risultato di un controllo delle licenze è sempre una chiamata a uno dei LicenseCheckerCallback metodi, creati in base alla convalida della risposta il codice di risposta del server stesso ed eventuali altre elaborazioni fornite dal tuo Policy. La tua applicazione può implementare i metodi in qualsiasi modo necessario. Nella in generale, è meglio mantenere i metodi semplici, limitandoli alla gestione dell'interfaccia utente lo stato e l'accesso alle applicazioni. Se vuoi aggiungere ulteriori elaborazioni delle licenze risposte, ad esempio contattando un server di backend o applicando vincoli personalizzati, ti consigliamo di incorporare questo codice nel tuo Policy, anziché inserendolo nei metodi LicenseCheckerCallback.

Nella maggior parte dei casi, devi dichiarare l'implementazione LicenseCheckerCallback come classe privata all'interno dell'istanza principale dell'applicazione Corso di attività.

Implementa i metodi allow() e dontAllow() come necessaria. Per iniziare, puoi utilizzare semplici comportamenti di gestione dei risultati come la visualizzazione dei risultati della licenza in una finestra di dialogo. Questo ti aiuta a ottenere l'esecuzione dell'applicazione prima e può aiutarti con il debug. In seguito, dopo hai determinato i comportamenti esatti che vuoi, puoi aggiungerne una più complessa.

Alcuni suggerimenti per la gestione delle risposte senza licenza in dontAllow() includono:

  • Mostrare il messaggio "Riprova" finestra di dialogo all'utente, includendo un pulsante per avviare una nuova licenza controlla se il valore reason fornito è Policy.RETRY.
  • Visualizzare il messaggio "Acquista questa applicazione" di dialogo, tra cui un pulsante Consente di collegare l'utente alla pagina dei dettagli dell'applicazione su Google Play, da cui possono acquistare l'applicazione. Per ulteriori informazioni su come configurare consulta la pagina Collegamento ai tuoi prodotti.
  • Mostra una notifica Toast che indichi che le funzioni del sono limitate perché non sono concesse in licenza.

L'esempio seguente mostra come l'applicazione di esempio LVL implementa LicenseCheckerCallback, con i metodi che mostrano il controllo delle licenze generano un .

Kotlin

private inner class MyLicenseCheckerCallback : LicenseCheckerCallback {

    override fun allow(reason: Int) {
        if (isFinishing) {
            // Don't update UI if Activity is finishing.
            return
        }
        // Should allow user access.
        displayResult(getString(R.string.allow))
    }

    override fun dontAllow(reason: Int) {
        if (isFinishing) {
            // Don't update UI if Activity is finishing.
            return
        }
        displayResult(getString(R.string.dont_allow))

        if (reason == Policy.RETRY) {
            // If the reason received from the policy is RETRY, it was probably
            // due to a loss of connection with the service, so we should give the
            // user a chance to retry. So show a dialog to retry.
            showDialog(DIALOG_RETRY)
        } else {
            // Otherwise, the user isn't licensed to use this app.
            // Your response should always inform the user that the application
            // isn't licensed, but your behavior at that point can vary. You might
            // provide the user a limited access version of your app or you can
            // take them to Google Play to purchase the app.
            showDialog(DIALOG_GOTOMARKET)
        }
    }
}

Java

private class MyLicenseCheckerCallback implements LicenseCheckerCallback {
    public void allow(int reason) {
        if (isFinishing()) {
            // Don't update UI if Activity is finishing.
            return;
        }
        // Should allow user access.
        displayResult(getString(R.string.allow));
    }

    public void dontAllow(int reason) {
        if (isFinishing()) {
            // Don't update UI if Activity is finishing.
            return;
        }
        displayResult(getString(R.string.dont_allow));

        if (reason == Policy.RETRY) {
            // If the reason received from the policy is RETRY, it was probably
            // due to a loss of connection with the service, so we should give the
            // user a chance to retry. So show a dialog to retry.
            showDialog(DIALOG_RETRY);
        } else {
            // Otherwise, the user isn't licensed to use this app.
            // Your response should always inform the user that the application
            // isn't licensed, but your behavior at that point can vary. You might
            // provide the user a limited access version of your app or you can
            // take them to Google Play to purchase the app.
            showDialog(DIALOG_GOTOMARKET);
        }
    }
}

Inoltre, devi implementare l'applicationError() che l'LVL chiama per consentire all'applicazione di gestire errori che non sono non ripetibile. Per un elenco di questi errori, consulta Codici di risposta nella sezione Riferimento alle licenze. Puoi implementare il metodo in qualsiasi modo necessario. Nella maggior parte dei casi, dovrebbe registrare il codice di errore e chiamare dontAllow().

Crea un gestore per la pubblicazione da LicenseCheckerCallback al thread della UI

Durante un controllo delle licenze, la LVL passa la richiesta a Google Play. che gestisce la comunicazione con il server di licenze. LVL passa la richiesta tramite IPC asincrono (utilizzando Binder) in modo che l'elaborazione effettiva e la comunicazione di rete non avvengono su un thread gestiti dalla tua applicazione. Analogamente, quando l'app Google Play riceve il risultato, richiama un metodo di callback su IPC, che a sua volta viene eseguito in un pool di thread IPC nel processo dell'applicazione.

La classe LicenseChecker gestisce la comunicazione IPC della tua applicazione con l'applicazione Google Play, inclusa la chiamata che invia la richiesta e il callback che riceve la risposta. LicenseChecker monitora anche una licenza aperta e gestisce i rispettivi timeout.

In modo che possa gestire correttamente i timeout ed elaborare le risposte in arrivo senza influire sul thread dell'interfaccia utente della tua applicazione, LicenseChecker genera un il thread in background durante la creazione dell'istanza. Nel thread esegue tutta l'elaborazione risultati del controllo delle licenze, se il risultato è una risposta ricevuta dal server o un errore di timeout. Al termine dell'elaborazione, la LVL chiama LicenseCheckerCallback metodi dal thread in background.

Per la tua applicazione, questo significa che:

  1. I tuoi metodi LicenseCheckerCallback verranno richiamati, in molti casi, da un in background.
  2. Questi metodi non saranno in grado di aggiornare lo stato o richiamare alcuna elaborazione nel Thread UI, a meno che tu non crei un gestore nel thread dell'interfaccia utente e non abbia il callback vengono pubblicati sul gestore.

Se vuoi che i metodi LicenseCheckerCallback aggiornino il thread dell'interfaccia utente, crea un'istanza di Handler nell'elenco delle attività onCreate(), come mostrato di seguito. In questo esempio, il modello di applicazione LicenseCheckerCallback metodo (vedi sopra) chiama displayResult() a aggiornare il thread dell'interfaccia utente tramite post().

Kotlin

    private lateinit var handler: Handler

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        handler = Handler()
    }

Java

    private Handler handler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        handler = new Handler();
    }

Poi, nei tuoi metodi LicenseCheckerCallback, puoi utilizzare i metodi Gestori per pubblicare oggetti eseguibili o messaggi nel gestore. Ecco come funziona l'esempio L'applicazione inclusa nell'LVL pubblica un elemento Runnable to a Gestori nel thread dell'interfaccia utente per visualizzare lo stato della licenza.

Kotlin

private fun displayResult(result: String) {
    handler.post {
        statusText.text = result
        setProgressBarIndeterminateVisibility(false)
        checkLicenseButton.isEnabled = true
    }
}

Java

private void displayResult(final String result) {
        handler.post(new Runnable() {
            public void run() {
                statusText.setText(result);
                setProgressBarIndeterminateVisibility(false);
                checkLicenseButton.setEnabled(true);
            }
        });
    }

Creare un'istanza LicenseChecker e LicenseCheckerCallback

Nella sezione delle attività onCreate() metodo, creare istanze private di LicenseCheckerCallback e LicenseChecker. Devi creare prima un'istanza LicenseCheckerCallback, perché devi passare un riferimento a quell'istanza quando chiami il costruttore per LicenseChecker.

Quando crei un'istanza LicenseChecker, devi passare i seguenti parametri:

  • L'applicazione Context
  • Un riferimento all'implementazione di Policy da utilizzare per il controllo delle licenze. Nella nella maggior parte dei casi, utilizzerai l'implementazione Policy predefinita fornita da LVL, ServerManagedPolicy.
  • La variabile stringa che contiene la chiave pubblica dell'account publisher per licenze.

Se utilizzi ServerManagedPolicy, non dovrai accedere alla classe di modo che tu possa creare un'istanza nel costruttore LicenseChecker, come mostrato nell'esempio riportato di seguito. Tieni presente che devi passare un riferimento a un nuovo Istanza di offuscamento durante la creazione di ServerManagedPolicy.

L'esempio seguente mostra la creazione di un'istanza di LicenseChecker e LicenseCheckerCallback dal metodo onCreate() di un'attività .

Kotlin

class MainActivity : AppCompatActivity() {
    ...
    private lateinit var licenseCheckerCallback: LicenseCheckerCallback
    private lateinit var checker: LicenseChecker

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        // Construct the LicenseCheckerCallback. The library calls this when done.
        licenseCheckerCallback = MyLicenseCheckerCallback()

        // Construct the LicenseChecker with a Policy.
        checker = LicenseChecker(
                this,
                ServerManagedPolicy(this, AESObfuscator(SALT, packageName, deviceId)),
                BASE64_PUBLIC_KEY // Your public licensing key.
        )
        ...
    }
}

Java

public class MainActivity extends Activity {
    ...
    private LicenseCheckerCallback licenseCheckerCallback;
    private LicenseChecker checker;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Construct the LicenseCheckerCallback. The library calls this when done.
        licenseCheckerCallback = new MyLicenseCheckerCallback();

        // Construct the LicenseChecker with a Policy.
        checker = new LicenseChecker(
            this, new ServerManagedPolicy(this,
                new AESObfuscator(SALT, getPackageName(), deviceId)),
            BASE64_PUBLIC_KEY // Your public licensing key.
            );
        ...
    }
}

Tieni presente che LicenseChecker chiama i metodi LicenseCheckerCallback dall'interfaccia utente il thread solo se esiste una risposta a una licenza valida memorizzata nella cache localmente. Se del traffico, il controllo delle licenze viene inviato al server, i callback hanno sempre origine il thread in background, anche per gli errori di rete.

Chiama checkAccess() per avviare il controllo della licenza

Nell'Attività principale, aggiungi una chiamata al metodo checkAccess() del LicenseChecker istanza. Durante la chiamata, passa un riferimento LicenseCheckerCallback istanza come parametro. Se hai bisogno di gestire effetti speciali dell'interfaccia utente o gestione dello stato prima della chiamata, potrebbe esserti utile per chiamare checkAccess() da un metodo wrapper. Ad esempio, il valore LVL l'applicazione di esempio chiama checkAccess() da un Metodo wrapper doCheck():

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        // Call a wrapper method that initiates the license check
        doCheck()
        ...
    }
    ...
    private fun doCheck() {
        checkLicenseButton.isEnabled = false
        setProgressBarIndeterminateVisibility(true)
        statusText.setText(R.string.checking_license)
        checker.checkAccess(licenseCheckerCallback)
    }

Java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Call a wrapper method that initiates the license check
        doCheck();
        ...
    }
    ...
    private void doCheck() {
        checkLicenseButton.setEnabled(false);
        setProgressBarIndeterminateVisibility(true);
        statusText.setText(R.string.checking_license);
        checker.checkAccess(licenseCheckerCallback);
    }

Incorpora la chiave pubblica per le licenze

Per ogni applicazione, Google Play Services automaticamente genera una coppia di chiavi pubbliche/private RSA a 2048 bit che viene utilizzata licenze e fatturazione in-app. La coppia di chiavi è associata in modo univoco un'applicazione. Sebbene sia associata all'applicazione, la coppia di chiavi non corrisponde alla chiave che utilizzi per firmare le tue applicazioni (o che la utilizzi).

Google Play Console espone la chiave pubblica per la licenza a qualsiasi sviluppatore ha eseguito l'accesso a Play Console, ma conserva la chiave privata nascosti a tutti gli utenti in un luogo sicuro. Quando un'applicazione richiede il controllo delle licenze per un'applicazione pubblicata nel tuo account, il server di licenze firma la risposta della licenza utilizzando la chiave privata della coppia di chiavi dell'applicazione. Quando l'LVL riceve la risposta, utilizza la chiave pubblica fornita dalla per verificare la firma della risposta relativa alla licenza.

Per aggiungere licenze a un'applicazione, devi ottenere il chiave pubblica per la licenza e copiarla nella tua richiesta. Ecco come trovare chiave pubblica della tua applicazione per la licenza:

  1. Vai a Google Play Console ed esegui l'accesso. Assicurati di aver eseguito l'accesso all'account da cui stai utilizzando l'applicazione. licenze pubblicate (o verranno pubblicate).
  2. Nella pagina dei dettagli dell'applicazione, individua la sezione Servizi e API e fai clic sul link.
  3. Nella sezione Servizi e API, individua Licenze e Fatturazione in-app. La tua chiave pubblica per la licenza viene fornita Il tuo codice di licenza per questa applicazione.

Per aggiungere la chiave pubblica alla tua applicazione, è sufficiente copiare e incollare la stringa della chiave dal campo all'applicazione come valore della variabile String BASE64_PUBLIC_KEY. Quando effettui la copia, assicurati di avere selezionata l'intera stringa di chiave, senza omettere alcun carattere.

Ecco un esempio tratto dall'applicazione di esempio LVL:

Kotlin

private const val BASE64_PUBLIC_KEY = "MIIBIjANBgkqhkiG ... " //truncated for this example
class LicensingActivity : AppCompatActivity() {
    ...
}

Java

public class MainActivity extends Activity {
    private static final String BASE64_PUBLIC_KEY = "MIIBIjANBgkqhkiG ... "; //truncated for this example
    ...
}

Chiama il metodo onDestroy() di LicenseChecker per chiudere le connessioni IPC

Infine, per consentire la pulizia di LVL prima dell'applicazione Context modifiche, aggiungi una chiamata all'app LicenseChecker onDestroy() metodo della tua Attività Implementazione di onDestroy(). La chiamata fa sì che LicenseChecker per chiudere correttamente qualsiasi connessione IPC aperta a Google Play ilicensingService dell'applicazione e rimuove tutti i riferimenti locali al servizio e gestore.

Impossibile chiamare il metodo onDestroy() di LicenseChecker possono causare problemi durante il ciclo di vita della tua applicazione. Ad esempio, se l'utente cambia l'orientamento dello schermo mentre è attivo un controllo della licenza, l'applicazione Eliminazione di Context completata. Se la tua applicazione non chiudi correttamente la connessione IPC di LicenseChecker, l'applicazione avrà un arresto anomalo quando viene ricevuta la risposta. In modo simile, se l'utente esce dall'applicazione mentre è in corso un controllo della licenza, l'applicazione avrà un arresto anomalo quando di risposta, a meno che non abbia correttamente chiamato il Metodo onDestroy() di LicenseChecker per disconnettersi dal servizio.

Ecco un esempio dall'applicazione di esempio inclusa nella LVL, in cui mChecker è l'istanza LicenseChecker:

Kotlin

    override fun onDestroy() {
        super.onDestroy()
        checker.onDestroy()
        ...
    }

Java

    @Override
    protected void onDestroy() {
        super.onDestroy();
        checker.onDestroy();
        ...
    }

Se stai estendendo o modificando LicenseChecker, potrebbe essere necessario chiamare anche metodo finishCheck() di LicenseChecker, per ripulire eventuali IPC aperti e connessioni a Internet.

Implementazione di un DeviceLimiter

In alcuni casi, potresti voler limitare il numero di Policy dispositivi a cui è consentito utilizzare una singola licenza. Questo impedisce a un utente dalla migrazione di un'applicazione con licenza su più dispositivi all'utilizzo su tali dispositivi con lo stesso ID account. Inoltre, impedirebbe che utente da "condivisione" fornendo i dati dell'account associati alla licenza di altri individui, che potrebbero poi accedervi sui propri dispositivi e accedere alla licenza dell'applicazione.

L'LVL supporta le licenze per dispositivo fornendo DeviceLimiter, che dichiara un singolo metodo, allowDeviceAccess(). Quando un LicenseValidator gestisce una risposta dal server di licenze, chiama allowDeviceAccess(), trasmettendo una Stringa dell'ID utente estratta dalla risposta.

Se non vuoi supportare le limitazioni del dispositivo, non dovrai fare nulla obbligatorio: il corso LicenseChecker utilizza automaticamente un'istanza chiamata NullDeviceLimiter. Come suggerisce il nome, NullDeviceLimiter è una modalità "no-op" il cui metodo allowDeviceAccess() restituisce semplicemente una risposta LICENSED per tutti gli utenti e i dispositivi.

Attenzione:l'assegnazione di licenze per dispositivo non è consigliata per la maggior parte delle applicazioni perché:

  • Devi fornire un server di backend per gestire utenti e dispositivi mappatura e
  • Potrebbe inavvertitamente comportare la negazione dell'accesso a un un'applicazione che ha legittimamente acquistato su un altro dispositivo.

Offuscamento del codice

Per garantire la sicurezza della tua applicazione, in particolare per un account a pagamento che utilizza le licenze e/o le protezioni e i vincoli personalizzati, per offuscare il codice dell'applicazione. Offuscamento corretto rende più difficile per un utente malintenzionato decompilare il database dell'applicazione in bytecode, modificarlo, ad esempio rimuovendo il controllo delle licenze. e quindi ricompilarlo.

Sono disponibili diversi programmi di offuscamento per le applicazioni Android, tra cui ProGuard, che offre anche di ottimizzazione del codice. L'utilizzo di ProGuard o di un programma simile per offuscare il tuo codice è vivamente consigliato per tutte le applicazioni che utilizzano Licenze Google Play.

Pubblicazione di un'applicazione concessa in licenza

Al termine del test dell'implementazione della licenza, pubblicare l'applicazione su Google Play. Segui la normale procedura per preparare, firmare e pubblicare la richiesta.

Dove trovare assistenza

Se hai domande o riscontri problemi durante l'implementazione o il deployment pubblica nelle tue applicazioni, utilizza le risorse di assistenza elencate nella riportata di seguito. Indirizzando le query al forum corretto, puoi ottenere l'assistenza necessaria più rapidamente.

Tabella 2. Risorse di assistenza per gli sviluppatori per il servizio di licenze di Google Play.

Tipo di assistenza Risorsa Gamma di argomenti
Problemi di sviluppo e verifica Google Gruppi: android-developers Download e integrazione LVL, progetti libreria, Policy domande, idee per l'esperienza utente, gestione delle risposte, Obfuscator, IPC, test configurazione dell'ambiente
Stack Overflow: http://stackoverflow.com/questions/gtag/android
Problemi relativi ad account, pubblicazione e deployment Google Play Forum di assistenza Account publisher, coppia di chiavi di licenza, account di prova, server risposte dei test, deployment e risultati dell'applicazione
Mercato Domande frequenti sull'assistenza per le licenze
Issue Tracker LVL Licenze di mercato strumento di monitoraggio dei problemi a livello di progetto Report su problemi e bug relativi specificamente alle classi del codice sorgente LVL e le implementazioni dell'interfaccia

Per informazioni generali su come pubblicare post nei gruppi sopra elencati, consulta la sezione Risorse della community nella pagina Risorse di assistenza per gli sviluppatori.

Risorse aggiuntive

L'applicazione di esempio inclusa nella LVL fornisce un esempio completo di come avviare un controllo della licenza e gestire il risultato, nel MainActivity corso.