Clientseitige Lizenzüberprüfung zu Ihrer Anwendung hinzufügen

Warnung : Wenn Ihre Anwendung die Lizenzüberprüfung auf Clientseite ausführt, ist es für potenzielle Angreifer einfacher, die mit dem Überprüfungsprozess verbundene Logik zu ändern oder zu entfernen.

Aus diesem Grund empfehlen wir dir dringend, stattdessen eine serverseitige Lizenzüberprüfung durchzuführen.

Nachdem du ein Publisher-Konto und eine Entwicklungsumgebung eingerichtet hast (siehe Lizenzierung einrichten), kannst du deiner App eine Lizenzüberprüfung mithilfe der License Verification Library (LVL) hinzufügen.

Das Hinzufügen der Lizenzüberprüfung mit der LVL umfasst folgende Aufgaben:

  1. Fügen Sie die Lizenzierungsberechtigung zum Manifest Ihrer App hinzu.
  2. Richtlinie implementieren: Sie können eine der vollständigen in der LVL bereitgestellten Implementierungen auswählen oder Ihre eigene erstellen.
  3. Implementieren Sie einen Obfuscator, wenn Ihr Policy Lizenzantwortdaten im Cache speichert.
  4. In der Hauptaktivität Ihrer Anwendung Code hinzufügen, um die Lizenz zu prüfen.
  5. DeviceLimiter implementieren (optional und für die meisten Anwendungen nicht empfohlen)

In den folgenden Abschnitten werden diese Aufgaben beschrieben. Wenn die Integration abgeschlossen ist, sollten Sie in der Lage sein, Ihre Anwendung erfolgreich zu kompilieren und mit den Tests zu beginnen, wie unter Testumgebung einrichten beschrieben.

Eine Übersicht über alle Quelldateien, die in der LVL enthalten sind, finden Sie in der Zusammenfassung der LVL-Klassen und -Schnittstellen.

Lizenzierungsberechtigung hinzufügen

Damit über die Google Play App eine Lizenzprüfung an den Server gesendet werden kann, muss die App die entsprechende Berechtigung anfordern: com.android.vending.CHECK_LICENSE. Wenn Ihre Anwendung die Lizenzberechtigung nicht deklariert, aber versucht, eine Lizenzprüfung zu initiieren, gibt die LVL eine Sicherheitsausnahme aus.

Deklarieren Sie ein <uses-permission>-Element als untergeordnetes Element von <manifest>, um die Lizenzberechtigung in Ihrer Anwendung anzufordern:

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

So deklariert die LVL-Beispielanwendung die Berechtigung beispielsweise:

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

Hinweis:Derzeit können Sie die Berechtigung CHECK_LICENSE nicht im Manifest des LVL-Bibliotheksprojekts deklarieren, da die SDK-Tools sie nicht mit den Manifesten abhängiger Anwendungen zusammenführen. Stattdessen müssen Sie die Berechtigung im Manifest jeder abhängigen Anwendung deklarieren.

Richtlinie implementieren

Der Google Play-Lizenzierungsservice bestimmt nicht selbst, ob einem bestimmten Nutzer mit einer bestimmten Lizenz Zugriff auf deine App gewährt werden soll. Diese Verantwortung bleibt vielmehr einer Policy-Implementierung überlassen, die Sie in Ihrer Anwendung angeben.

Die Richtlinie ist eine von der LVL deklarierte Schnittstelle, die die Logik Ihrer Anwendung für das Zulassen oder Ablehnen des Nutzerzugriffs auf Grundlage des Ergebnisses einer Lizenzprüfung enthält. Damit Sie die LVL verwenden können, muss Ihre Anwendung eine Implementierung von Policy bereitstellen.

Die Schnittstelle Policy deklariert zwei Methoden, allowAccess() und processServerResponse(). Diese werden von einer LicenseChecker-Instanz aufgerufen, wenn eine Antwort vom Lizenzserver verarbeitet wird. Außerdem wird eine Aufzählung mit dem Namen LicenseResponse deklariert, mit der der Lizenzantwortwert angegeben wird, der in Aufrufen an processServerResponse() übergeben wird.

  • Mit processServerResponse() können Sie die vom Lizenzierungsserver empfangenen Antwortrohdaten vorverarbeiten, bevor Sie entscheiden, ob Sie Zugriff gewähren möchten.

    In einer typischen Implementierung werden einige oder alle Felder aus der Lizenzantwort extrahiert und die Daten lokal in einem nichtflüchtigen Speicher gespeichert, z. B. in SharedPreferences. So ist sichergestellt, dass die Daten über Anwendungsaufrufe und Einschaltzyklen des Geräts zugänglich sind. Ein Policy speichert beispielsweise den Zeitstempel der letzten erfolgreichen Lizenzprüfung, die Anzahl der Wiederholungen, den Gültigkeitszeitraum der Lizenz und ähnliche Informationen in einem nichtflüchtigen Speicher, anstatt die Werte bei jedem Start der Anwendung zurückzusetzen.

    Wenn Antwortdaten lokal gespeichert werden, muss der Policy dafür sorgen, dass die Daten verschleiert sind (siehe Obfuscator implementieren unten).

  • allowAccess() bestimmt anhand von verfügbaren Lizenzantwortdaten (vom Lizenzierungsserver oder aus dem Cache) oder anderen anwendungsspezifischen Informationen, ob dem Nutzer Zugriff auf Ihre Anwendung gewährt wird. Ihre Implementierung von allowAccess() könnte beispielsweise zusätzliche Kriterien berücksichtigen, wie etwa Nutzung oder andere von einem Back-End-Server abgerufene Daten. In jedem Fall sollte bei einer Implementierung von allowAccess() nur true zurückgegeben werden, wenn der Nutzer laut Lizenzierungsserver für die Verwendung der Anwendung lizenziert ist, oder wenn ein vorübergehendes Netzwerk- oder Systemproblem vorliegt, das die Lizenzprüfung verhindert. In solchen Fällen kann Ihre Implementierung die Anzahl der Wiederholungsantworten beibehalten und vorläufig Zugriff gewähren, bis die nächste Lizenzprüfung abgeschlossen ist.

Die LVL umfasst zwei vollständige Policy-Implementierungen, die Sie ohne Änderung oder Anpassung an Ihre Anforderungen verwenden können, um das Hinzufügen der Lizenzierung zu Ihrer Anwendung zu vereinfachen und zu zeigen, wie eine Policy entworfen werden sollte:

  • ServerManagedPolicy, eine flexible Policy, die vom Server bereitgestellte Einstellungen und im Cache gespeicherte Antworten verwendet, um den Zugriff über verschiedene Netzwerkbedingungen hinweg zu verwalten, und
  • StrictPolicy, der keine Antwortdaten im Cache speichert und nur dann Zugriff gewährt, wenn der Server eine lizenzierte Antwort zurückgibt.

Für die meisten Anwendungen wird die Verwendung von ServerManagedPolicy empfohlen. ServerManagedPolicy ist der LVL-Standardwert und ist in die LVL-Beispielanwendung integriert.

Richtlinien für benutzerdefinierte Richtlinien

Bei der Implementierung der Lizenzierung können Sie eine der vollständigen Richtlinien aus der LVL (ServerManagedPolicy oder StrictPolicy) verwenden oder eine benutzerdefinierte Richtlinie erstellen. Bei jeder Art von benutzerdefinierten Richtlinien gibt es einige wichtige Punkte, die bei der Implementierung zu verstehen und zu berücksichtigen sind.

Der Lizenzierungsserver wendet allgemeine Anfragelimits an, um eine übermäßige Nutzung von Ressourcen zu vermeiden, die zu einem Denial-of-Service führen könnte. Wenn eine Anwendung das Anfragelimit überschreitet, gibt der Lizenzierungsserver eine 503-Antwort zurück, die als allgemeiner Serverfehler an die Anwendung übergeben wird. Das bedeutet, dass dem Nutzer keine Lizenzantwort zur Verfügung steht, bis das Limit zurückgesetzt wird, was für einen unbestimmten Zeitraum gelten kann.

Wenn du eine benutzerdefinierte Richtlinie entwickelst, empfehlen wir Policy:

  1. speichert die letzte erfolgreiche Lizenzantwort im Cache (und verschleiert ordnungsgemäß) im lokalen nichtflüchtigen Speicher.
  2. Gibt die im Cache gespeicherte Antwort für alle Lizenzprüfungen zurück, solange die im Cache gespeicherte Antwort gültig ist, anstatt eine Anfrage an den Lizenzierungsserver zu senden. Es wird dringend empfohlen, die Antwortgültigkeit gemäß dem vom Server bereitgestellten VT-Extra festzulegen. Weitere Informationen finden Sie unter Server Response Extras.
  3. Wenn eine Wiederholung von Anfragen zu Fehlern führt, wird ein exponentieller Backoff-Zeitraum verwendet. Hinweis: Der Google Play-Client wiederholt fehlgeschlagene Anfragen automatisch. In den meisten Fällen ist es also nicht nötig, dass Policy die Anfragen wiederholen.
  4. Es wird ein Kulanzzeitraum gewährt, in dem der Nutzer für einen begrenzten Zeitraum oder eine bestimmte Anzahl von Verwendungen auf Ihre Anwendung zugreifen kann, während eine Lizenzprüfung wiederholt wird. Der Kulanzzeitraum bietet Nutzern den Vorteil, bis die nächste Lizenzprüfung erfolgreich abgeschlossen werden kann. Außerdem wird der Zugriff auf Ihre Anwendung eingeschränkt, wenn keine gültige Lizenzantwort verfügbar ist.

Es ist von entscheidender Bedeutung, die Policy gemäß den oben aufgeführten Richtlinien zu entwerfen, da sie Nutzern die bestmögliche Erfahrung bietet und Ihnen selbst bei Fehlerbedingungen effektive Kontrolle über Ihre Anwendung gibt.

Beachten Sie, dass jeder Policy die vom Lizenzierungsserver bereitgestellten Einstellungen verwenden kann, um die Gültigkeit und das Caching zu verwalten, den Kulanzzeitraum zu wiederholen und vieles mehr. Das Extrahieren der vom Server bereitgestellten Einstellungen ist einfach und es wird dringend empfohlen, sie zu verwenden. In der ServerManagedPolicy-Implementierung finden Sie ein Beispiel für das Extrahieren und Verwenden der Extras. Eine Liste der Servereinstellungen und Informationen zu ihrer Verwendung finden Sie unter Server Response Extras.

ServerManagedPolicy

Die LVL enthält eine vollständige und empfohlene Implementierung der Policy-Schnittstelle namens ServerManagedPolicy. Die Implementierung ist in die LVL-Klassen eingebunden und dient als Standard-Policy in der Bibliothek.

ServerManagedPolicy bietet alle Verwaltungsfunktionen für Lizenz- und Wiederholungsantworten. Alle Antwortdaten werden lokal in einer SharedPreferences-Datei zwischengespeichert und mit der Obfuscator-Implementierung der Anwendung verschleiert. Dadurch wird sichergestellt, dass die Lizenzantwortdaten sicher sind und auch nach dem Ein-/Ausschalten des Geräts erhalten bleiben. ServerManagedPolicy bietet konkrete Implementierungen der Schnittstellenmethoden processServerResponse() und allowAccess() und umfasst eine Reihe von unterstützenden Methoden und Typen zur Verwaltung von Lizenzantworten.

Ein wichtiges Merkmal von ServerManagedPolicy ist die Verwendung von vom Server bereitgestellten Einstellungen als Grundlage für die Lizenzverwaltung während des Erstattungszeitraums einer Anwendung und durch unterschiedliche Netzwerk- und Fehlerbedingungen. Wenn eine App den Google Play-Server für eine Lizenzprüfung kontaktiert, hängt der Server bei bestimmten Lizenzantworttypen im Feld „Extras“ mehrere Einstellungen als Schlüssel/Wert-Paare an. Der Server stellt beispielsweise empfohlene Werte für den Gültigkeitszeitraum der Lizenz, den Kulanzzeitraum für Wiederholungen und die maximal zulässige Anzahl von Wiederholungen bereit. ServerManagedPolicy extrahiert die Werte aus der Lizenzantwort in der Methode processServerResponse() und prüft sie in der Methode allowAccess(). Eine Liste der vom Server bereitgestellten Einstellungen, die von ServerManagedPolicy verwendet werden, finden Sie unter Server Response Extras.

Um die beste Leistung zu erzielen und die Vorteile der Lizenzeinstellungen des Google Play-Servers zu nutzen, empfehlen wir dringend die Verwendung von ServerManagedPolicy als Lizenzierungs-Policy.

Wenn Sie Bedenken bezüglich der Sicherheit von Lizenzantwortdaten haben, die lokal in SharedPreferences gespeichert sind, können Sie einen stärkeren Verschleierungsalgorithmus verwenden oder eine striktere Policy entwerfen, bei der keine Lizenzdaten gespeichert werden. Die LVL enthält ein Beispiel für eine solche Policy. Weitere Informationen finden Sie unter StrictPolicy.

Wenn Sie ServerManagedPolicy verwenden möchten, importieren Sie es einfach in Ihre Aktivität, erstellen Sie eine Instanz und übergeben Sie beim Erstellen der LicenseChecker einen Verweis auf die Instanz. Weitere Informationen finden Sie unter Instantiate LicenseChecker und LicenseCheckerCallback.

StrengePolicy

Die LVL enthält eine alternative vollständige Implementierung der Policy-Schnittstelle namens StrictPolicy. Die StrictPolicy-Implementierung bietet eine restriktivere Richtlinie als ServerManagedPolicy, da der Nutzer nur dann auf die Anwendung zugreifen kann, wenn zum Zeitpunkt des Zugriffs eine Lizenzantwort vom Server eingeht, die darauf hinweist, dass der Nutzer lizenziert ist.

Die Hauptfunktion von StrictPolicy besteht darin, dass keine Lizenzantwortdaten lokal in einem nichtflüchtigen Speicher gespeichert werden. Da keine Daten gespeichert sind, werden Wiederholungsanfragen nicht verfolgt und im Cache gespeicherte Antworten können nicht zur Ausführung von Lizenzprüfungen verwendet werden. Die Policy erlaubt den Zugriff nur unter folgenden Bedingungen:

  • Die Lizenzantwort wird vom Lizenzierungsserver empfangen.
  • Die Lizenzantwort zeigt an, dass der Nutzer eine Lizenz für den Zugriff auf die Anwendung hat.

Die Verwendung von StrictPolicy ist geeignet, wenn Sie in erster Linie dafür sorgen möchten, dass in jedem Fall kein Nutzer auf die Anwendung zugreifen darf, es sei denn, bei der Verwendung wurde bestätigt, dass er über eine Lizenz verfügt. Außerdem bietet die Richtlinie etwas mehr Sicherheit als ServerManagedPolicy – da keine Daten lokal im Cache gespeichert werden, kann ein böswilliger Nutzer die im Cache gespeicherten Daten nicht manipulieren und Zugriff auf die Anwendung erlangen.

Gleichzeitig stellt diese Policy eine Herausforderung für normale Nutzer dar, da sie nicht auf die App zugreifen können, wenn keine Netzwerkverbindung (Mobilfunk- oder WLAN-Verbindung) verfügbar ist. Ein weiterer Nebeneffekt ist, dass Ihre Anwendung mehr Lizenzüberprüfungsanfragen an den Server sendet, da die Verwendung einer im Cache gespeicherten Antwort nicht möglich ist.

Insgesamt stellt diese Richtlinie einen Kompromiss zwischen Nutzerkomfort und absoluter Sicherheit und Kontrolle über den Zugriff dar. Beachten Sie die Vor- und Nachteile sorgfältig, bevor Sie diesen Policy verwenden.

Wenn Sie StrictPolicy verwenden möchten, importieren Sie ihn einfach in Ihre Activity-Klasse, erstellen Sie eine Instanz und übergeben Sie beim Erstellen der LicenseChecker einen Verweis darauf. Weitere Informationen finden Sie unter LicenseChecker und LicenseCheckerCallback instanziieren.

Eine typische Policy-Implementierung muss die Lizenzantwortdaten für eine Anwendung in einem nichtflüchtigen Speicher speichern, damit sie über Anwendungsaufrufe und Geräte-Einschaltzyklen zugänglich sind. Ein Policy speichert beispielsweise den Zeitstempel der letzten erfolgreichen Lizenzprüfung, die Anzahl der Wiederholungen, den Gültigkeitszeitraum der Lizenz und ähnliche Informationen in einem nichtflüchtigen Speicher, anstatt die Werte bei jedem Start der Anwendung zurückzusetzen. Der in der LVL enthaltene Standard-Policy (ServerManagedPolicy) speichert Lizenzantwortdaten in einer SharedPreferences-Instanz, damit die Daten dauerhaft sind.

Da das Policy gespeicherte Lizenzantwortdaten verwendet, um zu bestimmen, ob der Zugriff auf die App zugelassen oder blockiert wird, muss es dafür sorgen, dass alle gespeicherten Daten sicher sind und von einem Root-Nutzer auf einem Gerät nicht wiederverwendet oder geändert werden können. Insbesondere muss der Policy die Daten vor dem Speichern immer verschleiern, indem ein Schlüssel verwendet wird, der für die Anwendung und das Gerät eindeutig ist. Die Verschleierung mit einem anwendungs- und gerätespezifischen Schlüssel ist wichtig, da dies verhindert, dass die verschleierten Daten zwischen Anwendungen und Geräten geteilt werden.

Die LVL unterstützt die Anwendung dabei, ihre Lizenzantwortdaten sicher und dauerhaft zu speichern. Erstens stellt er eine Obfuscator-Schnittstelle bereit, über die Ihre Anwendung den Verschleierungsalgorithmus ihrer Wahl für gespeicherte Daten bereitstellen kann. Darauf aufbauend stellt die LVL die Hilfsklasse PreferredObfuscator bereit, die den Großteil der Arbeit beim Aufrufen der Klasse Obfuscator der Anwendung und dem Lesen und Schreiben der verschleierten Daten in einer SharedPreferences-Instanz übernimmt.

Die LVL bietet eine vollständige Obfuscator-Implementierung namens AESObfuscator, die die AES-Verschlüsselung zur Verschleierung von Daten verwendet. Sie können AESObfuscator unverändert in Ihrer Anwendung verwenden oder ihn an Ihre Anforderungen anpassen. Wenn Sie eine Policy (z. B. ServerManagedPolicy) verwenden, die Lizenzantwortdaten im Cache speichert, wird die Verwendung von AESObfuscator als Grundlage für Ihre Obfuscator-Implementierung dringend empfohlen. Weitere Informationen finden Sie im nächsten Abschnitt.

AESObfuscator

Die LVL enthält eine vollständige und empfohlene Implementierung der Obfuscator-Schnittstelle namens AESObfuscator. Die Implementierung ist in die LVL-Beispielanwendung eingebunden und dient in der Bibliothek als Standard-Obfuscator.

AESObfuscator bietet eine sichere Verschleierung von Daten mithilfe von AES, um die Daten zu verschlüsseln und zu entschlüsseln, wenn sie in den Speicher geschrieben oder aus diesem gelesen werden. Das Obfuscator leitet die Verschlüsselung mit drei von der Anwendung bereitgestellten Datenfeldern weiter:

  1. Salt – ein Array von zufälligen Byte, die für jede (Un-)Verschleierung verwendet werden.
  2. Ein Anwendungs-ID-String, in der Regel der Paketname der Anwendung.
  3. Ein Geräte-ID-String, der aus möglichst vielen gerätespezifischen Quellen abgeleitet wird, damit er so eindeutig ist wie möglich.

Wenn du AESObfuscator verwenden möchtest, importiere ihn zuerst in deine Aktivität. Deklarieren Sie ein privates statisches endgültiges Array, das die Salt-Byte enthält, und initialisieren Sie es mit 20 zufällig generierten Byte.

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

Deklarieren Sie als Nächstes eine Variable, die eine Geräte-ID enthält, und generieren Sie je nach Bedarf einen Wert dafür. Beispielsweise fragt die in der LVL enthaltene Beispielanwendung die Systemeinstellungen für die android.Settings.Secure.ANDROID_ID ab, die für jedes Gerät eindeutig ist.

Beachten Sie, dass Ihre Anwendung je nach den von Ihnen verwendeten APIs möglicherweise zusätzliche Berechtigungen anfordern muss, um gerätespezifische Informationen zu erhalten. Um beispielsweise die TelephonyManager abzufragen, um die IMEI des Geräts oder zugehörige Daten zu erhalten, muss die App auch die Berechtigung android.permission.READ_PHONE_STATE im Manifest anfordern.

Bevor Sie neue Berechtigungen anfordern, die einzigen Zweck sind, um gerätespezifische Daten zur Verwendung in Ihrer Obfuscator abzurufen, sollten Sie sich überlegen, welche Auswirkungen dies auf Ihre App oder deren Filter bei Google Play haben kann. Einige Berechtigungen können dazu führen, dass die SDK-Build-Tools die verknüpfte <uses-feature> hinzufügen.

Erstellen Sie schließlich eine Instanz von AESObfuscator und übergeben Sie den Salt, die Anwendungs-ID und die Geräte-ID. Sie können die Instanz direkt beim Erstellen von Policy und LicenseChecker erstellen. Beispiele:

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.
        );
    ...

Ein vollständiges Beispiel finden Sie unter MainActivity in der LVL-Beispielanwendung.

Lizenz aus einer Aktivität prüfen

Nachdem Sie eine Policy zur Verwaltung des Zugriffs auf Ihre Anwendung implementiert haben, fügen Sie Ihrer Anwendung im nächsten Schritt eine Lizenzprüfung hinzu. Dadurch wird bei Bedarf eine Abfrage an den Lizenzierungsserver gestartet und der Zugriff auf die Anwendung basierend auf der Lizenzantwort verwaltet. Das Hinzufügen der Lizenzprüfung und die Verarbeitung der Antwort erfolgen in der Activity-Hauptquelldatei.

Um die Lizenzprüfung hinzuzufügen und die Antwort zu verarbeiten, müssen Sie Folgendes tun:

  1. Importe hinzufügen
  2. Implementieren Sie LicenseCheckerCallback als private innere Klasse.
  3. Erstellen Sie einen Handler für das Posten von LicenseCheckerCallback im UI-Thread.
  4. Instanziate LicenseChecker und LicenseCheckerCallback
  5. Rufen Sie „checkAccess()“ auf, um die Lizenzprüfung zu starten.
  6. Öffentlichen Schlüssel zur Lizenzierung einbetten
  7. Rufen Sie die onDestroy()-Methode Ihres LicenseCheckers auf, um IPC-Verbindungen zu schließen.

In den folgenden Abschnitten werden diese Aufgaben beschrieben.

Lizenzprüfung und ‐antwort – Übersicht

In den meisten Fällen sollten Sie die Lizenzprüfung in der onCreate()-Methode dem Haupt-Activity Ihrer Anwendung hinzufügen. Dadurch wird sichergestellt, dass die Lizenzprüfung sofort aufgerufen wird, wenn der Nutzer Ihre Anwendung direkt startet. In einigen Fällen können Sie Lizenzprüfungen auch an anderen Standorten hinzufügen. Wenn Ihre Anwendung beispielsweise mehrere Aktivitätskomponenten enthält, die andere Anwendungen mit Intent starten können, können Sie diesen Aktivitäten Lizenzprüfungen hinzufügen.

Eine Lizenzprüfung besteht aus zwei Hauptaktionen:

  • Ein Aufruf einer Methode zum Initiieren der Lizenzprüfung – in der LVL ist dies ein Aufruf der Methode checkAccess() eines LicenseChecker-Objekts, das Sie erstellen.
  • Ein Callback, der das Ergebnis der Lizenzprüfung zurückgibt. In der LVL ist dies eine LicenseCheckerCallback-Schnittstelle, die Sie implementieren. In der Benutzeroberfläche werden die beiden Methoden allow() und dontAllow() deklariert, die von der Bibliothek basierend auf dem Ergebnis der Lizenzprüfung aufgerufen werden. Sie implementieren diese beiden Methoden mit einer beliebigen Logik, um dem Nutzer den Zugriff auf Ihre Anwendung zu ermöglichen oder zu verbieten. Diese Methoden haben keinen Einfluss darauf, ob der Zugriff gewährt wird. Diese Entscheidung liegt in der Verantwortung Ihrer Policy-Implementierung. Diese Methoden bieten lediglich das Anwendungsverhalten, wie der Zugriff zugelassen bzw. nicht zugelassen und Anwendungsfehler behoben werden können.

    Die Methoden allow() und dontAllow() geben einen Grund für die Antwort an. Dies kann einer der Werte Policy sein: LICENSED, NOT_LICENSED oder RETRY. Sie sollten insbesondere den Fall behandeln, in dem die Methode die RETRY-Antwort für dontAllow() empfängt, und dem Nutzer eine Schaltfläche zum Wiederholen bereitstellen. Dies kann passieren, wenn der Dienst während der Anfrage nicht verfügbar war.

Abbildung 1: Übersicht über eine typische Interaktion zur Lizenzüberprüfung.

Das Diagramm oben zeigt, wie eine typische Lizenzüberprüfung durchgeführt wird:

  1. Code in der Hauptaktivität der Anwendung instanziiert LicenseCheckerCallback- und LicenseChecker-Objekte. Beim Erstellen von LicenseChecker werden mit dem Code Context, eine Policy-Implementierung, die verwendet werden soll, und der öffentliche Schlüssel des Publisher-Kontos zur Lizenzierung als Parameter übergeben.
  2. Mit dem Code wird dann die Methode checkAccess() für das LicenseChecker-Objekt aufgerufen. Bei der Methodenimplementierung wird Policy aufgerufen, um zu ermitteln, ob eine gültige Lizenzantwort lokal in SharedPreferences im Cache gespeichert ist.
    • In diesem Fall ruft die checkAccess()-Implementierung allow() auf.
    • Andernfalls initiiert LicenseChecker eine Lizenzüberprüfungsanfrage, die an den Lizenzierungsserver gesendet wird.

    Hinweis:Der Lizenzierungsserver gibt immer LICENSED zurück, wenn Sie eine Lizenzprüfung in einem Anwendungsentwurf durchführen.

  3. Wenn eine Antwort eingeht, erstellt LicenseChecker einen LicenseValidator, der die signierten Lizenzdaten überprüft, die Felder der Antwort extrahiert und sie dann zur weiteren Auswertung an Ihre Policy übergibt.
    • Wenn die Lizenz gültig ist, speichert der Policy die Antwort in SharedPreferences im Cache und benachrichtigt den Validator, der dann die Methode allow() für das LicenseCheckerCallback-Objekt aufruft.
    • Wenn die Lizenz ungültig ist, benachrichtigt Policy die Validierung, die die Methode dontAllow() für LicenseCheckerCallback aufruft.
  4. Bei einem behebbaren lokalen oder Serverfehler, z. B. wenn das Netzwerk nicht zum Senden der Anfrage verfügbar ist, übergibt LicenseChecker eine RETRY-Antwort an die Methode processServerResponse() des Policy-Objekts.

    Außerdem empfangen die Callback-Methoden allow() und dontAllow() das Argument reason. Der Grund für die allow()-Methode ist normalerweise Policy.LICENSED oder Policy.RETRY und der dontAllow()-Grund ist normalerweise Policy.NOT_LICENSED oder Policy.RETRY. Diese Antwortwerte sind nützlich, damit Sie dem Nutzer eine geeignete Antwort anzeigen können. Beispielsweise können Sie die Schaltfläche „Wiederholen“ verwenden, wenn dontAllow() mit Policy.RETRY antwortet. Das könnte daran liegen, dass der Dienst nicht verfügbar war.

  5. Bei einem Anwendungsfehler, z. B. wenn die Anwendung versucht, die Lizenz eines ungültigen Paketnamens zu prüfen, übergibt LicenseChecker eine Fehlerantwort an die Methode applicationError() von LicenseCheckerCallback.

Hinweis: Zusätzlich zum Initiieren der Lizenzprüfung und Verarbeiten des Ergebnisses, wie in den folgenden Abschnitten beschrieben, muss deine Anwendung auch eine Richtlinienimplementierung und eine Obfuscator-Implementierung bereitstellen, wenn Policy Antwortdaten speichert (z. B. ServerManagedPolicy).

Importe hinzufügen

Öffnen Sie zuerst die Klassendatei der Hauptaktivität der Anwendung und importieren Sie LicenseChecker und LicenseCheckerCallback aus dem LVL-Paket.

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;

Wenn Sie die Policy-Standardimplementierung verwenden, die in der LVL bereitgestellt wird, ServerManagedPolicy, importieren Sie sie ebenfalls zusammen mit dem AESObfuscator. Wenn Sie einen benutzerdefinierten Policy oder Obfuscator verwenden, importieren Sie diese stattdessen.

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;

LicenseCheckerCallback als private innere Klasse implementieren

LicenseCheckerCallback ist eine Schnittstelle, die von der LVL zur Verarbeitung des Ergebnisses einer Lizenzprüfung bereitgestellt wird. Wenn Sie die Lizenzierung mithilfe der LVL unterstützen möchten, müssen Sie LicenseCheckerCallback und die zugehörigen Methoden implementieren, um den Zugriff auf die Anwendung zu erlauben oder zu verbieten.

Das Ergebnis einer Lizenzprüfung ist immer ein Aufruf einer der LicenseCheckerCallback-Methoden, der auf der Validierung der Antwortnutzlast, dem Serverantwortcode selbst und der zusätzlichen Verarbeitung durch deine Policy erfolgt. Ihre Anwendung kann die Methoden auf beliebige Weise implementieren. Im Allgemeinen ist es am besten, die Methoden einfach zu halten und auf die Verwaltung des UI-Status und des Anwendungszugriffs zu beschränken. Wenn Sie eine weitere Verarbeitung von Lizenzantworten hinzufügen möchten, z. B. indem Sie einen Back-End-Server kontaktieren oder benutzerdefinierte Einschränkungen anwenden, sollten Sie diesen Code in Ihre Policy einbinden, anstatt ihn in die LicenseCheckerCallback-Methoden einzufügen.

In den meisten Fällen sollten Sie die Implementierung von LicenseCheckerCallback als private Klasse innerhalb der Hauptaktivitätsklasse Ihrer Anwendung deklarieren.

Implementieren Sie die Methoden allow() und dontAllow() nach Bedarf. Für den Anfang können Sie einfache Verhaltensweisen zur Ergebnisverarbeitung in den Methoden anwenden, z. B. das Lizenzergebnis in einem Dialogfeld anzeigen. So können Sie Ihre Anwendung schneller ausführen und die Fehlerbehebung erleichtern. Später, nachdem Sie genau das gewünschte Verhalten festgelegt haben, können Sie eine komplexere Handhabung hinzufügen.

Hier einige Vorschläge für den Umgang mit nicht lizenzierten Antworten in dontAllow():

  • Dem Nutzer das Dialogfeld „Noch einmal versuchen“ mit einer Schaltfläche zum Starten einer neuen Lizenzprüfung anzeigen, wenn das bereitgestellte reason Policy.RETRY ist.
  • Das Dialogfeld „Diese App kaufen“ mit einer Schaltfläche aufrufen, über die der Nutzer zur Detailseite der App bei Google Play gelangt, über die er die App kaufen kann. Weitere Informationen zum Einrichten solcher Verknüpfungen finden Sie unter Verknüpfungen mit Ihren Produkten.
  • Es wird eine Toast-Benachrichtigung angezeigt, die darauf hinweist, dass die Funktionen der Anwendung eingeschränkt sind, da sie nicht lizenziert ist.

Das folgende Beispiel zeigt, wie die LVL-Beispielanwendung LicenseCheckerCallback implementiert, wobei Methoden zum Anzeigen der Lizenzprüfungsergebnisse in einem Dialogfeld angezeigt werden.

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

Außerdem sollten Sie die Methode applicationError() implementieren, die von der LVL aufgerufen wird, damit Ihre Anwendung Fehler verarbeiten kann, die nicht wiederholt werden können. Eine Liste solcher Fehler finden Sie in der Lizenzierungsreferenz unter Serverantwortcodes. Die Methode lässt sich auf beliebige Weise implementieren. In den meisten Fällen sollte die Methode den Fehlercode protokollieren und dontAllow() aufrufen.

Handler zum Posten von LicenseCheckerCallback im UI-Thread erstellen

Während einer Lizenzprüfung leitet die LVL die Anfrage an die Google Play-Anwendung weiter, die die Kommunikation mit dem Lizenzierungsserver übernimmt. Die LVL leitet die Anfrage über einen asynchronen IPC (mit Binder) weiter, sodass die tatsächliche Verarbeitung und Netzwerkkommunikation nicht in einem Thread stattfindet, der von Ihrer Anwendung verwaltet wird. Wenn die Google Play-Anwendung das Ergebnis erhält, ruft sie auf ähnliche Weise eine Callback-Methode über IPC auf, die wiederum in einem IPC-Thread-Pool im Prozess Ihrer Anwendung ausgeführt wird.

Die Klasse LicenseChecker verwaltet die IPC-Kommunikation Ihrer Anwendung mit der Google Play-App, einschließlich des Aufrufs, der die Anfrage sendet, und dem Callback, der die Antwort empfängt. LicenseChecker verfolgt außerdem offene Lizenzanfragen und verwaltet Zeitlimits.

Damit Zeitüberschreitungen richtig verarbeitet und eingehende Antworten verarbeitet werden können, ohne den UI-Thread der Anwendung zu beeinträchtigen, erstellt LicenseChecker bei der Instanziierung einen Hintergrundthread. Im Thread werden die Ergebnisse der Lizenzprüfung vollständig verarbeitet, unabhängig davon, ob es sich um eine vom Server empfangene Antwort oder um einen Zeitüberschreitungsfehler handelt. Am Ende der Verarbeitung ruft die LVL Ihre LicenseCheckerCallback-Methoden aus dem Hintergrundthread auf.

Für Ihre Anwendung bedeutet dies Folgendes:

  1. Die LicenseCheckerCallback-Methoden werden in vielen Fällen aus einem Hintergrundthread aufgerufen.
  2. Diese Methoden können den Status nicht aktualisieren und keine Verarbeitungen im UI-Thread aufrufen, es sei denn, Sie erstellen einen Handler im UI-Thread und lassen Ihre Callback-Methoden an den Handler senden.

Wenn Sie möchten, dass Ihre LicenseCheckerCallback-Methoden den UI-Thread aktualisieren, instanziieren Sie ein Handler in der onCreate()-Methode der Hauptaktivität, wie unten dargestellt. In diesem Beispiel rufen die LicenseCheckerCallback-Methoden der LVL-Beispielanwendung (siehe oben) displayResult() auf, um den UI-Thread über die Methode post() des Handlers zu aktualisieren.

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

Anschließend können Sie in Ihren LicenseCheckerCallback-Methoden Handler-Methoden verwenden, um Runnable- oder Message-Objekte an den Handler zu senden. So sendet die in der LVL enthaltene Beispielanwendung ein „Runnable“ an einen Handler im UI-Thread, um den Lizenzstatus anzuzeigen.

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

LicenseChecker und LicenseCheckerCallback instanziieren

Erstellen Sie in der Methode onCreate() der Hauptaktivität private Instanzen von LicenseCheckerCallback und LicenseChecker. Sie müssen zuerst LicenseCheckerCallback instanziieren, da Sie einen Verweis auf diese Instanz übergeben müssen, wenn Sie den Konstruktor für LicenseChecker aufrufen.

Wenn Sie LicenseChecker instanziieren, müssen Sie die folgenden Parameter übergeben:

  • Die Anwendung Context
  • Ein Verweis zur Policy-Implementierung, die für die Lizenzprüfung verwendet werden soll. In den meisten Fällen sollten Sie die Policy-Standardimplementierung verwenden, die von der LVL (ServerManagedPolicy) bereitgestellt wird.
  • Die Stringvariable, die den öffentlichen Schlüssel deines Publisher-Kontos zur Lizenzierung enthält.

Wenn Sie ServerManagedPolicy verwenden, müssen Sie nicht direkt auf die Klasse zugreifen. Sie können sie also im LicenseChecker-Konstruktor instanziieren, wie im folgenden Beispiel gezeigt. Beim Erstellen von ServerManagedPolicy muss ein Verweis auf eine neue Obfuscator-Instanz übergeben werden.

Das folgende Beispiel zeigt die Instanziierung von LicenseChecker und LicenseCheckerCallback aus der onCreate()-Methode einer Activity-Klasse.

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

Beachten Sie, dass LicenseChecker die LicenseCheckerCallback-Methoden aus dem UI-Thread nur dann aufruft, wenn eine gültige Lizenzantwort lokal im Cache gespeichert ist. Wenn die Lizenzprüfung an den Server gesendet wird, stammen die Callbacks immer aus dem Hintergrundthread, auch bei Netzwerkfehlern.

checkAccess() aufrufen, um die Lizenzprüfung zu starten

Fügen Sie in Ihrer Hauptaktivität einen Aufruf der Methode checkAccess() der Instanz LicenseChecker hinzu. Übergeben Sie dabei einen Verweis auf die LicenseCheckerCallback-Instanz als Parameter. Wenn Sie vor dem Aufruf spezielle UI-Effekte oder die Statusverwaltung anpassen müssen, kann es sinnvoll sein, checkAccess() über eine Wrapper-Methode aufzurufen. Die LVL-Beispielanwendung ruft beispielsweise checkAccess() über eine doCheck()-Wrapper-Methode auf:

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

Öffentlichen Schlüssel zur Lizenzierung einbetten

Der Google Play-Dienst generiert für jede App automatisch ein 2048-Bit-RSA-Paar aus öffentlichem und privatem Schlüssel, das für die Lizenzierung und In-App-Abrechnung verwendet wird. Das Schlüsselpaar ist der Anwendung eindeutig zugeordnet. Obwohl das Schlüsselpaar der Anwendung zugeordnet ist, ist es nicht mit dem Schlüssel identisch, mit dem Sie Ihre Anwendungen signieren (oder von ihm abgeleitet).

Die Google Play Console stellt den öffentlichen Schlüssel zur Lizenzierung für alle Entwickler bereit, die in der Play Console angemeldet sind. Der private Schlüssel wird jedoch an einem sicheren Ort vor allen Nutzern verborgen. Wenn eine Anwendung eine Lizenzprüfung für eine in Ihrem Konto veröffentlichte Anwendung anfordert, signiert der Lizenzierungsserver die Lizenzantwort mit dem privaten Schlüssel des Schlüsselpaars Ihrer Anwendung. Wenn die LVL die Antwort erhält, verwendet sie den von der Anwendung bereitgestellten öffentlichen Schlüssel, um die Signatur der Lizenzantwort zu prüfen.

Wenn Sie einer Anwendung eine Lizenzierung hinzufügen möchten, müssen Sie den öffentlichen Schlüssel Ihrer Anwendung für die Lizenzierung abrufen und in Ihre Anwendung kopieren. So finden Sie den öffentlichen Schlüssel Ihrer Anwendung für die Lizenzierung:

  1. Rufen Sie die Google Play Console auf und melden Sie sich an. Melden Sie sich in dem Konto an, über das die von Ihnen lizenzierte Anwendung veröffentlicht (oder veröffentlicht) wird.
  2. Suchen Sie auf der Seite mit den Anwendungsdetails den Link Dienste & APIs und klicken Sie darauf.
  3. Gehen Sie auf der Seite Dienste & APIs zum Abschnitt Lizenzierung & In-App-Abrechnung. Den öffentlichen Schlüssel für die Lizenzierung erhalten Sie im Feld Ihr Lizenzschlüssel für diese Anwendung.

Wenn Sie den öffentlichen Schlüssel zu Ihrer Anwendung hinzufügen möchten, kopieren Sie einfach den Schlüsselstring aus dem Feld und fügen Sie ihn als Wert der Stringvariablen BASE64_PUBLIC_KEY in Ihre Anwendung ein. Achten Sie beim Kopieren darauf, dass Sie den gesamten Schlüsselstring ausgewählt haben, ohne Zeichen auszulassen.

Hier ist ein Beispiel aus der LVL-Beispielanwendung:

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

Rufen Sie die onDestroy()-Methode Ihres LicenseCheckers auf, um IPC-Verbindungen zu schließen.

Damit die LVL bereinigt werden kann, bevor sich Context der Anwendung ändert, füge einen Aufruf der Methode onDestroy() der LicenseChecker aus der onDestroy()-Implementierung deiner Aktivität hinzu. Durch den Aufruf schließt LicenseChecker jede offene IPC-Verbindung zum ILicensingService der Google Play-Anwendung ordnungsgemäß. Außerdem werden alle lokalen Verweise auf den Dienst und den Handler entfernt.

Wenn die Methode onDestroy() von LicenseChecker nicht aufgerufen wird, kann das über den gesamten Lebenszyklus Ihrer Anwendung hinweg zu Problemen führen. Wenn der Nutzer beispielsweise die Bildschirmausrichtung ändert, während eine Lizenzprüfung aktiv ist, wird die Anwendung Context gelöscht. Wenn Ihre Anwendung die IPC-Verbindung des LicenseChecker nicht ordnungsgemäß schließt, stürzt sie beim Empfang der Antwort ab. Ebenso stürzt die Anwendung beim Empfang der Antwort ab, wenn der Nutzer die Anwendung während einer Lizenzprüfung schließt. Dies gilt nicht, wenn die Verbindung zum Dienst von LicenseChecker nicht ordnungsgemäß aufgerufen wurde.onDestroy()

Hier sehen Sie ein Beispiel aus der Beispielanwendung, die in der LVL enthalten ist, wobei mChecker die Instanz LicenseChecker ist:

Kotlin

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

Java

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

Wenn Sie LicenseChecker erweitern oder ändern, müssen Sie möglicherweise auch die Methode finishCheck() von LicenseChecker aufrufen, um offene IPC-Verbindungen zu bereinigen.

DeviceLimiter implementieren

In einigen Fällen kann es sinnvoll sein, die Anzahl der tatsächlichen Geräte, die eine einzelne Lizenz verwenden dürfen, durch Policy zu begrenzen. Dadurch wird verhindert, dass ein Nutzer eine lizenzierte App auf mehrere Geräte verschiebt und die App auf diesen Geräten unter derselben Konto-ID verwendet. Außerdem wird dadurch verhindert, dass ein Nutzer die Anwendung "freigibt", indem er die mit der Lizenz verknüpften Kontoinformationen an andere Personen weitergibt, die sich dann auf ihren Geräten in diesem Konto anmelden und auf die Lizenz für die Anwendung zugreifen können.

Die LVL unterstützt die Lizenzierung pro Gerät, indem eine DeviceLimiter-Schnittstelle bereitgestellt wird, die eine einzelne Methode, allowDeviceAccess(), deklariert. Wenn ein LicenseValidator eine Antwort vom Lizenzierungsserver verarbeitet, ruft er allowDeviceAccess() auf und übergibt einen Nutzer-ID-String, der aus der Antwort extrahiert wurde.

Wenn Sie keine Geräteeinschränkung unterstützen möchten, müssen Sie nichts weiter tun. Die Klasse LicenseChecker verwendet automatisch eine Standardimplementierung namens NullDeviceLimiter. Wie der Name schon sagt, ist NullDeviceLimiter eine No-Op-Klasse, deren allowDeviceAccess()-Methode einfach eine LICENSED-Antwort für alle Nutzer und Geräte zurückgibt.

Achtung:Die Lizenzierung pro Gerät wird für die meisten Apps nicht empfohlen. Das hat folgende Gründe:

  • Sie müssen einen Backend-Server bereitstellen, um die Zuordnung von Nutzern und Geräten zu verwalten.
  • Dies könnte versehentlich dazu führen, dass einem Nutzer der Zugriff auf eine Anwendung verweigert wird, die er rechtmäßig auf einem anderen Gerät erworben hat.

Code verschleiern

Zum Schutz Ihrer Anwendung, insbesondere bei kostenpflichtigen Anwendungen, die Lizenzierung und/oder benutzerdefinierte Einschränkungen und Schutzmaßnahmen verwendet, ist es sehr wichtig, dass Ihr Anwendungscode verschleiert wird. Eine ordnungsgemäße Verschleierung des Codes erschwert es für böswillige Nutzer, den Bytecode der Anwendung zu dekompilieren, zu verändern, z. B. durch das Entfernen der Lizenzprüfung, und anschließend neu zu kompilieren.

Für Android-Anwendungen stehen verschiedene Verschleierungsprogramme zur Verfügung, darunter ProGuard, das auch Funktionen zur Codeoptimierung bietet. Die Verwendung von ProGuard oder eines ähnlichen Programms zur Verschleierung Ihres Codes wird für alle Apps mit Google Play-Lizenzierung dringend empfohlen.

Lizenzierte Apps veröffentlichen

Wenn du mit dem Testen deiner Lizenzimplementierung fertig bist, kannst du die App bei Google Play veröffentlichen. Folgen Sie den üblichen Schritten zum Vorbereiten, Signieren und Veröffentlichen der Anwendung.

Support

Wenn Sie Fragen haben oder Probleme bei der Implementierung oder Bereitstellung von Veröffentlichungen in Ihren Anwendungen auftreten, nutzen Sie bitte die Supportressourcen, die in der folgenden Tabelle aufgeführt sind. Wenn Sie Ihre Fragen an das richtige Forum weiterleiten, erhalten Sie schneller die gewünschte Unterstützung.

Tabelle 2 Supportressourcen für Entwickler für den Google Play-Lizenzierungsservice.

Supporttyp Ressource Themenspektrum
Entwicklungs- und Testprobleme Google Groups: android-developers LVL-Download und -Integration, Bibliotheksprojekte, Policy Fragen, Ideen zur Nutzererfahrung, Verarbeitung der Antworten, Obfuscator, IPC, Einrichtung der Testumgebung
Stack Overflow: http://stackoverflow.com/questions/tagged/android
Probleme mit Konten, Veröffentlichung und Bereitstellung Google Play-Hilfeforum Publisher-Konten, Lizenzierungsschlüsselpaar, Testkonten, Server- und Testantworten, Bereitstellung der Anwendung und Ergebnisse
FAQs zum Support für Marktlizenzen
LVL-Problemverfolgung Problemverfolgung für die Marktlizenzierung Fehler- und Problemberichte speziell im Zusammenhang mit den LVL-Quellcodeklassen und Schnittstellenimplementierungen

Allgemeine Informationen zum Posten in den oben aufgeführten Gruppen finden Sie auf der Seite mit Supportressourcen für Entwickler im Abschnitt Community-Ressourcen.

Weitere Ressourcen

Die in der LVL enthaltene Beispielanwendung enthält ein vollständiges Beispiel dafür, wie eine Lizenzprüfung initiiert und das Ergebnis in der Klasse MainActivity verarbeitet wird.