Dodawanie do aplikacji weryfikacji licencji po stronie klienta

Ostrzeżenie: gdy aplikacja przeprowadza proces weryfikacji licencji po stronie klienta, potencjalnym hakerom łatwiej jest zmodyfikować lub usunąć zasady powiązane z tym procesem.

Dlatego zdecydowanie zachęcamy do wykonywanie po stronie serwera weryfikacji licencji.

Po skonfigurowaniu konta wydawcy i środowiska programistycznego (zobacz Konfigurowanie licencjonowania) możesz dodać weryfikację licencji z biblioteką weryfikacji licencji (LVL).

Dodanie weryfikacji licencji w LVL obejmuje te zadania:

  1. Dodawanie uprawnień dotyczących licencjonowania do pliku manifestu aplikacji.
  2. Wdrażanie zasad – możesz wybrać jedną z pełnych implementacji dostępnych w LVL lub utworzyć własną.
  3. Wdrożenie zaciemniającego, jeśli Policy zapisze którykolwiek z nich w pamięci podręcznej. danych odpowiedzi licencji.
  4. Dodawanie kodu w celu sprawdzenia licencji w głównej aplikacji aplikacji Aktywność.
  5. Implementowanie ograniczenia liczby urządzeń (opcjonalne i niezalecane w przypadku: dla większości aplikacji).

Poniżej znajdziesz opis tych zadań. Gdy skończysz korzystać z musisz być w stanie skompilować aplikację i można rozpocząć testowanie, zgodnie z opisem w sekcji Konfigurowanie testu Środowisko.

Omówienie pełnego zestawu plików źródłowych w LVL znajdziesz w artykule Podsumowanie klas LVL i interfejsy.

Dodawanie uprawnienia dotyczącego licencji

Aby użyć aplikacji Google Play do wysłania sprawdzenia licencji do serwer, aplikacja musi żądać odpowiedniego uprawnienia com.android.vending.CHECK_LICENSE Jeśli Twoja aplikacja nie zadeklaruje uprawnień dotyczących licencji, ale próbuje rozpocząć sprawdzanie licencji, LVL zgłasza wyjątek bezpieczeństwa.

Aby poprosić o uprawnienia licencyjne w aplikacji, zadeklaruj <uses-permission> jako element podrzędny elementu <manifest> w ten sposób:

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

Oto jak przykładowa aplikacja LVL zadeklaruje to uprawnienie:

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

Uwaga: obecnie nie można zadeklarować, CHECK_LICENSE w pliku manifestu projektu biblioteki LVL, bo narzędzia SDK nie łączą go z plikami manifestu zależnych aplikacji. Zamiast tego musisz zadeklarować to uprawnienie w każdym plik manifestu aplikacji.

Wdrażanie zasad

Usługa licencjonowania Google Play nie określa tego, czy użytkownik z daną licencją powinien otrzymać dostęp do Twojej aplikacji. Odpowiedzialność spoczywa na implementacji Policy, którą dostarczysz. w Twojej aplikacji.

Policy to interfejs deklarowany przez LVL, który służy do przechowywania reguły zezwalania na dostęp użytkownika lub go blokowania w zależności od wyniku weryfikacji licencji. Aby korzystać z LVL, aplikacja musi zawierać po wdrożeniu zmiennej Policy.

Interfejs Policy deklaruje 2 metody: allowAccess() oraz processServerResponse(), które są wywoływane przez LicenseChecker podczas przetwarzania odpowiedzi z serwera licencji. Deklaruje też wyliczenie o nazwie LicenseResponse, które określa odpowiedź dotyczącą licencji wartość przekazana w wywołaniach funkcji processServerResponse().

  • processServerResponse() umożliwia wstępne przetworzenie nieprzetworzonej odpowiedzi danych otrzymanych z serwera licencjonowania przed podjęciem decyzji o przyznaniu dostęp.

    Typowa implementacja spowoduje wyodrębnienie niektórych lub wszystkich pól z licencji i przechowują dane lokalnie w magazynie trwałym, np. przez SharedPreferences pamięci masowej, aby zapewnić, że dane będą dostępne w ramach wywołań aplikacji i cykli zasilania urządzenia. Przykład: Policy zachowa sygnaturę czasową ostatniego pomyślnego sprawdzenia licencji, wartość liczbę ponownych prób, okres ważności licencji i podobne informacje w pamięci trwałej, zamiast resetowania wartości za każdym razem, gdy aplikacja który został już wprowadzony.

    W przypadku przechowywania danych odpowiedzi lokalnie obiekt Policy musi zapewniać, zaciemniony (patrz Implementowanie zaciemnionego kodu, poniżej).

  • allowAccess() określa, czy przyznać użytkownikowi dostęp do: aplikacji, na podstawie wszelkich dostępnych danych odpowiedzi licencyjnych (z serwera licencjonowania lub pamięci podręcznej) bądź inne informacje dotyczące aplikacji. Dla: np. implementacja allowAccess() może wziąć pod uwagę dodatkowych kryteriów, takich jak wykorzystanie lub inne dane pobierane z z serwera backendu. We wszystkich przypadkach implementacja allowAccess() powinien zwracać wartość true tylko wtedy, gdy użytkownik ma licencję na używanie aplikacji, zgodnie z ustawieniami serwera licencjonowania, a jeśli występuje przejściowy problem, problem z siecią lub systemem, który uniemożliwia ukończenie sprawdzania licencji. W takich przypadków implementacja może utrzymać liczbę ponownych odpowiedzi tymczasowo zezwolić na dostęp do momentu zakończenia następnego sprawdzania licencji.

Aby uprościć proces dodawania licencji do wniosku oraz ilustracja przedstawiająca zaprojektowanie elementu Policy, dwóch pełnych implementacji Policy, których możesz używać bez modyfikacji lub dostosuj do swoich potrzeb:

  • ServerManagedPolicy, elastyczny Policy który korzysta z ustawień dostarczonych przez serwer i odpowiedzi w pamięci podręcznej do zarządzania dostępem w różnych warunkach sieci
  • StrictPolicy, który nie buforuje żadnej odpowiedzi. danych i umożliwia dostęp tylko wtedy, gdy serwer zwraca licencjonowaną .

W większości aplikacji zastosowanie zasad zarządzania serwerem zalecane. ServerManagedPolicy to domyślna zasada LVL, która jest zintegrowana z przykładową aplikację LVL.

Wytyczne dotyczące zasad niestandardowych

Przy wdrażaniu licencji możesz zastosować jedną z pełnych zasad w LVL (ServerManagedPolicy lub StrictPolicy) albo możesz utworzyć niestandardowe zasady. W przypadku każdego typu zasad niestandardowych jest kilka ważnych które warto zrozumieć i uwzględnić w implementacji.

Serwer licencjonowania stosuje ogólne limity żądań, aby chronić się przed nadużywaniem zasobów, które mogą doprowadzić do ataku typu DoS. Jeśli aplikacja przekracza lub limit żądań, serwer licencjonowania zwraca odpowiedź 503, która zwraca przekazywane do aplikacji jako ogólny błąd serwera. Oznacza to, że odpowiedź dotycząca licencji będzie dostępna dla użytkownika do momentu zresetowania limitu, co mogą wpływać na użytkownika przez czas nieokreślony.

Jeśli projektujesz zasady niestandardowe, zalecamy, aby Policy:

  1. Zapisuje w pamięci podręcznej (i odpowiednio zaciemnia) ostatnią pomyślną odpowiedź dotyczącą licencji w lokalnej pamięci trwałej.
  2. Zwraca odpowiedź z pamięci podręcznej w przypadku wszystkich kontroli licencji, dopóki odpowiedź z pamięci podręcznej jest prawidłowa i nie wysyła żądania do serwera licencjonowania. Ustawianie poprawności odpowiedzi zgodnie z zasadą VT dostarczonej przez serwer jest zdecydowanie zalecane. Zobacz Dodatki do odpowiedzi serwera .
  3. Wykorzystuje rosnący wykładniczo okres do ponowienia, jeśli ponowienie próby powoduje wyświetlenie wyniku . Pamiętaj, że klient Google Play automatycznie ponawia próbę więc w większości przypadków Policy nie ma potrzeby, aby je ponawiać.
  4. Zapewnia „okres prolongaty” która pozwala użytkownikom przez ograniczony czas lub w określonej liczbie zastosowań, podczas sprawdzania licencji podjęto próbę ponowienia próby. Okres prolongaty jest korzystny dla użytkownika, ponieważ zezwala na dostęp do następnego okresu można pomyślnie przejść weryfikację licencji, co jest korzystne dla Ciebie, umieszczając stały limit na dostęp do Twojej aplikacji, gdy nie ma ważnej odpowiedzi na pytanie o licencję i dostępności informacji.

Zaprojektowanie urządzenia Policy zgodnie z powyższymi wskazówkami jest bardzo ważne. ponieważ zapewnia użytkownikom najlepsze wrażenia, a jednocześnie efektywną kontrolę nad aplikacją nawet w przypadku błędów.

Pamiętaj, że każdy Policy może używać ustawień skonfigurowanych przez serwer licencjonowania, aby ułatwiają zarządzanie weryfikacją i buforowaniem, okres prolongaty ponawiania prób i nie tylko. Wyodrębnianie ustawienia po stronie serwera są proste, a korzystanie z nich zalecane. Zapoznaj się z implementacją ServerManagedPolicy, aby dowiedzieć się, jak wyodrębniania i używania dodatków. Lista ustawień serwera oraz informacje o jak ich używać, patrz Odpowiedź serwera Dodatki.

Zasada zarządzania serwerem

Ocena LVL obejmuje pełną i zalecaną implementację interfejsu Policy o nazwie ServerManagedPolicy. Implementacja jest zintegrowana z Klasy LVL i służy jako domyślny obiekt Policy w bibliotece.

ServerManagedPolicy (zarządzane zasady) zapewniają pełną obsługę licencji i ponawianie próby odpowiedzi. Wszystkie dane odpowiedzi są zapisywane lokalnie w pamięci podręcznej SharedPreferences, ukrywając go za pomocą funkcji implementacji Obfuscator w aplikacji. Dzięki temu odpowiedź licencji są bezpieczne i pozostają bez zmian po każdym cyklach zasilania urządzenia. Zasada zarządzania serwerem zapewnia konkretne implementacje metod interfejsu, processServerResponse() i allowAccess(), a także obejmuje zestaw dodatkowych metod i typów zarządzania licencją odpowiedzi.

Co ważne, kluczową funkcją usługi ServerManagedPolicy jest użycie udostępnianych przez serwer ustawień jako podstawy zarządzania licencjami w z określonego okresu zwrotu środków i przy różnych warunkach sieci i błędów. Gdy aplikacja kontaktuje się z serwerem Google Play w celu sprawdzenia licencji, Serwer dołącza kilka ustawień jako pary klucz-wartość w polu Dodatki określonych typów odpowiedzi licencji. Na przykład serwer podaje zalecane wartości dla atrybutu okres ważności licencji aplikacji, okres prolongaty ponawiania próby i maksymalna dozwolona liczba liczbę ponownych prób. ServerManagedPolicy wyodrębnia wartości z pliku odpowiedź licencji w jej metodzie processServerResponse() i kontroli je w metodzie allowAccess(). Aby uzyskać listę wartości dostarczonych przez serwer, ustawień używanych przez ServerManagedPolicy, patrz odpowiedź serwera Dodatki.

Dla wygody, najlepszej wydajności i zalet korzystania z ustawień licencji z serwera Google Play, przy użyciu ServerManagedPolicy jako zalecamy licencjonowanie Policy.

Jeśli masz wątpliwości co do bezpieczeństwa danych odpowiedzi dotyczących licencji, przechowywane lokalnie w: SharedPreferences, możesz użyć silniejszego zaciemniania kodu lub zaprojektuj bardziej rygorystyczny algorytm Policy, w którym nie są przechowywane dane licencji. POZIOM zawiera przykład takiego elementu Policy – więcej informacji znajdziesz na stronie StrictPolicy.

Aby użyć ServerManagedPolicy, po prostu zaimportuj ją do aktywności, utwórz i przekazać odniesienie do instancji podczas tworzenia LicenseChecker Patrz sekcja Przeprowadzanie narzędzia do sprawdzania licencji LicenseCheckerCallback, aby dowiedzieć się więcej.

Rygorystyczne zasady

LVL obejmuje alternatywną pełną implementację interfejsu Policy StrictPolicy. Implementacja StrictPolicy zapewnia bardziej restrykcyjne zasady niż ServerManagedPolicy, ponieważ nie pozwala ona użytkownikowi na dostęp do aplikacji, o ile odpowiedź licencji nie zostanie odebrana z serwera czasu dostępu, który wskazuje, że użytkownik ma licencję.

Podstawową cechą StrictPolicy jest to, że nie przechowuje ona żadnych lokalnie, w magazynie trwałym. Żadne dane nie są przechowywane, żądania ponawiania nie są śledzone, a odpowiedzi z pamięci podręcznej nie mogą służyć do realizacji kontrole licencji. Policy zezwala na dostęp tylko wtedy, gdy:

  • odpowiedź dotycząca licencji zostanie odebrana z serwera licencjonowania.
  • Odpowiedź dotycząca licencji wskazuje, że użytkownik ma licencję na dostęp do aplikacji.

Użycie zasady StrictPolicy jest odpowiednie, jeśli głównym celem jest zapewnienie, we wszystkich możliwych przypadkach żaden użytkownik nie będzie mógł uzyskać dostępu do aplikacji, chyba że potwierdza, że ma on licencję w chwili używania. Dodatkowo Zasada zapewnia nieco większe bezpieczeństwo niż ServerManagedPolicy, ponieważ dane nie są przechowywane lokalnie w pamięci podręcznej, więc szkodliwy użytkownik nie ma możliwości z danymi w pamięci podręcznej i uzyskać dostęp do aplikacji.

Jednocześnie Policy stanowi wyzwanie dla zwykłych użytkowników, ponieważ co oznacza, że aplikacja nie będzie dostępna, gdy nie będzie dostępna sieć. (sieci komórkowe lub Wi-Fi). Kolejnym efektem ubocznym jest będzie wysyłać do serwera więcej żądań sprawdzenia licencji, ponieważ odpowiedź z pamięci podręcznej jest niemożliwa.

Zasadniczo ta zasada stanowi kompromis w pewnym stopniu wygody użytkowników dla absolutnego bezpieczeństwa i kontroli dostępu. Dobrze zastanów się nad kompromisem przed użyciem tego elementu (Policy).

Aby użyć StrictPolicy, po prostu zaimportuj ją do aktywności, utwórz instancję i przekazać odniesienie do niego podczas tworzenia LicenseChecker. Zobacz Instancje LicenseChecker i LicenseCheckerCallback .

Typowa implementacja Policy musi zapisać dane odpowiedzi licencji na: aplikacji do pamięci trwałej, tak aby była dostępna wywołań aplikacji i cykli zasilania urządzenia. Na przykład Policy będzie zachowaj sygnaturę czasową ostatniego pomyślnego sprawdzenia licencji, liczbę ponownych prób, okresu ważności licencji i podobne informacje w trwałym magazynie, zamiast resetowania wartości przy każdym uruchomieniu aplikacji. domyślna wartość Policy w LVL, ServerManagedPolicy, przechowuje odpowiedź licencji w instancji SharedPreferences, aby zapewnić, są trwałe.

Ponieważ Policy będzie wykorzystywać zapisane dane odpowiedzi licencji do określenia, czy zezwala na dostęp aplikacji lub go nie zezwala, musi zagwarantować, że przechowywane dane są bezpieczne i nie mogą być ponownie wykorzystywane ani modyfikowane przez roota w urządzenia. W szczególności Policy musi zawsze zaciemniać dane przed ich zapisaniem. używając klucza, który jest unikalny dla aplikacji i urządzenia. Zaciemnianie kodu za pomocą który jest kluczowy zarówno dla aplikacji, jak i urządzenia. zapobiega udostępnianiu zaciemnionych danych między aplikacjami urządzenia.

LVL pomaga aplikacji przechowywać dane odpowiedzi licencji w pliku w bezpieczny i trwały sposób. Najpierw udostępnia Obfuscator interfejsu, który pozwala aplikacji dostarczać algorytm zaciemniania kodu jej wyboru zapisanych danych. Na tej podstawie LVL oferuje klasę pomocniczą, PreferenceObfuscator, który obsługuje większość zadań związanych z wywoływaniem klasy Obfuscator aplikacji i odczytywanie i zapisywanie zaciemnionych danych w SharedPreferences instancję.

LVL zapewnia pełną implementację Obfuscator o nazwie AESObfuscator, który używa szyfrowania AES do zaciemniania danych. Dostępne opcje używaj AESObfuscator w swojej aplikacji bez modyfikacji lub aby dostosować ją do swoich potrzeb. Jeśli używasz Policy (np. ServerManagedPolicy), który buforuje dane odpowiedzi licencji przy użyciu AESObfuscator jako jako podstawę wdrożenia Obfuscator. Więcej informacji znajdziesz w następnej sekcji.

AESObfuscator

Ocena LVL obejmuje pełną i zalecaną implementację interfejsu Obfuscator interfejsu AESObfuscator. Implementacja jest zintegrowana z Przykładowa aplikacja LVL służąca jako domyślna Obfuscator w bibliotece.

AESObfuscator zapewnia bezpieczne zaciemnianie danych za pomocą AES do szyfrować i odszyfrowywać dane w miarę ich zapisywania lub odczytywania. Obfuscator rozpoczyna szyfrowanie za pomocą 3 podanych pól danych przez aplikację:

  1. Sól – tablica losowych bajtów, które mają być używane do każdego (usunięcia) zaciemnienia kodu.
  2. Ciąg identyfikatora aplikacji, zwykle nazwa pakietu aplikacji.
  3. Ciąg identyfikatora urządzenia pobrany na podstawie jak największej liczby źródeł związanych z określonym urządzeniem aby była jak najbardziej unikalna.

Aby używać AESObfuscator, najpierw zaimportuj go do aktywności. Deklarowanie prywatnego charakteru statyczna tablica końcowa do przechowywania bajtów zaburzających i inicjowania ich losowo na 20 wygenerowanych bajtów.

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

Następnie zadeklaruj zmienną do przechowywania identyfikatora urządzenia i generowania wartości dla: w dowolny sposób. Na przykład przykładowa aplikacja uwzględniona w LVL wysyła zapytanie do ustawień systemowych android.Settings.Secure.ANDROID_ID, która jest unikalna dla każdego urządzenia.

Pamiętaj, że w zależności od używanych interfejsów API aplikacja może wymagać zażądać dodatkowych uprawnień w celu uzyskania informacji o urządzeniu. Aby na przykład wysłać zapytanie do funkcji TelephonyManager w celu uzyskania numeru IMEI urządzenia ani powiązanych danych, aplikacja będzie musiała również android.permission.READ_PHONE_STATE w pliku manifestu.

Zanim poprosisz o nowe uprawnienia wyłączne w celu pozyskania dotyczące konkretnego urządzenia na potrzeby Obfuscator, rozważ Jak to może wpłynąć na Twoją aplikację lub jej filtrowanie w Google Play? (ponieważ niektóre uprawnienia mogą powodować, że narzędzia do kompilacji SDK powiązany <uses-feature>).

Na koniec utwórz instancję AESObfuscator, przekazując ciąg zaburzający, identyfikatora aplikacji i urządzenia. Możesz utworzyć instancję bezpośrednio podczas tworzenia Policy i LicenseChecker. Na przykład:

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

Pełny przykład znajdziesz w sekcji MainActivity w przykładowej aplikacji LVL.

Sprawdzanie licencji z działania

Gdy zaimplementujesz interfejs Policy służący do zarządzania dostępem do aplikacji, następnym krokiem jest dodanie do aplikacji sprawdzania licencji, co spowoduje uruchomienie zapytania do serwera licencjonowania i w razie potrzeby zarządza dostępem do aplikacji na podstawie odpowiedź dotyczącą licencji. Cała praca związana z dodawaniem sprawdzania licencji i obsługą odpowiedź jest wykonywana w głównym pliku źródłowym Activity.

Aby dodać sprawdzanie licencji i obsługiwać odpowiedź, musisz:

  1. Dodawanie importów
  2. Wdrożenie LicenseCheckerCallback jako prywatnej klasy wewnętrznej
  3. Utwórz moduł obsługi do publikowania z interfejsu LicenseCheckerCallback w wątku interfejsu użytkownika
  4. Instancje LicenseChecker i LicenseCheckerCallback
  5. Wywołaj funkcję checkAccess(), aby zainicjować sprawdzanie licencji
  6. Umieszczanie klucza publicznego na potrzeby licencjonowania
  7. Wywołaj metodę onDestroy() narzędzia LicenseChecker, aby zamknąć połączenia IPC.

Poniżej znajdziesz opis tych zadań.

Omówienie sprawdzania licencji i reagowania na nie

W większości przypadków należy dodać sprawdzanie licencji do głównego Activity w metodzie onCreate(). Ten pozwala zagwarantować, że przy bezpośrednim uruchomieniu aplikacji przez użytkownika zostanie wywołana natychmiast. W niektórych przypadkach możesz dodać kontrole licencji w innych lokalizacji firmy. Jeśli na przykład aplikacja zawiera wiele aktywności komponenty, które inne aplikacje mogą uruchamiać przez Intent, możesz dodać kontrole licencji do tych działań.

Sprawdzanie licencji składa się z 2 głównych działań:

  • Wywołanie metody inicjowania sprawdzania licencji. W LVL jest to wywołanie metody checkAccess() obiektu LicenseChecker, tworzyć.
  • Wywołanie zwrotne, które zwraca wynik sprawdzania licencji. W LVL implementowanego przez Ciebie interfejsu LicenseCheckerCallback. interfejs deklaruje 2 metody: allow() oraz dontAllow(), które są wywoływane przez bibliotekę na podstawie argumentu w wyniku sprawdzania licencji. Implementujesz te dwie metody z dowolną logiką aby zezwolić użytkownikowi na dostęp do aplikacji lub go zablokować. Pamiętaj, że te metody nie określają, czy zezwolić na dostęp – za implementację Policy spoczywa na Tobie odpowiedzialność. raczej po prostu podają zachowania aplikacji i określają, jak zezwolić na zablokować dostęp (i obsługiwać błędy aplikacji).

    Metody allow() i dontAllow() podają „przyczynę” za odpowiedź, która może być jedną z wartości Policy, LICENSED, NOT_LICENSED, czy RETRY. Zwróć szczególną uwagę na przypadki, w których metoda odbiera odpowiedź RETRY dla zapytania dontAllow() i udostępnia użytkownikowi „Spróbuj ponownie” (Może się tak zdarzyć, gdy usługa była niedostępna w okresie użytkownika.

Rysunek 1. Omówienie co zwykle przy sprawdzaniu licencji.

Na diagramie powyżej widać, jak odbywa się typowa weryfikacja licencji:

  1. Kod w głównej aktywności aplikacji tworzy instancję LicenseCheckerCallback i LicenseChecker obiektów. Podczas tworzenia obiektu LicenseChecker kod przekazuje Context, implementacja Policy, której należy użyć, oraz klucz publiczny konta wydawcy do licencjonowania jako parametry.
  2. Następnie kod wywołuje metodę checkAccess() w LicenseChecker obiekt. Implementacja metody wywołuje Policy, aby określić, czy prawidłowa odpowiedź dotycząca licencji znajduje się w pamięci podręcznej lokalnie, SharedPreferences
    • Jeśli tak, implementacja checkAccess() wywołuje allow()
    • W przeciwnym razie LicenseChecker wysyła żądanie sprawdzenia licencji. do serwera licencjonowania.

    Uwaga: serwer licencjonowania zawsze zwraca LICENSED podczas sprawdzania licencji wersji roboczej aplikacji.

  3. Po otrzymaniu odpowiedzi LicenseChecker tworzy obiekt LicenseValidator, który weryfikuje dane podpisanej licencji i wyodrębnia pola odpowiedzi, a następnie przekazuje je do Policy do dalszej oceny.
    • Jeśli licencja jest ważna, Policy zapisuje odpowiedź w pamięci podręcznej w SharedPreferences i powiadamia walidatora, który wywołuje metodę allow() na obiekcie LicenseCheckerCallback.
    • Jeśli licencja jest nieważna, Policy powiadamia walidatora, który wywołuje metodę metodę dontAllow() w tabeli LicenseCheckerCallback.
  4. W przypadku możliwego do naprawienia błędu lokalnego lub serwera, np. gdy sieć nie można wysłać żądania, LicenseChecker przekazuje odpowiedź RETRY do metody processServerResponse() obiektu Policy.

    Ponadto metody wywołania zwrotnego allow() i dontAllow() otrzymują błąd reason argument. Przyczyna zastosowania metody allow() to zwykle Policy.LICENSED lub Policy.RETRY, a przyczyna dontAllow() to zwykle Policy.NOT_LICENSED lub Policy.RETRY. Te wartości odpowiedzi są przydatne, bo pokazują, odpowiednią odpowiedź dla użytkownika, na przykład „Ponów próbę”. gdy dontAllow() odpowiada przy użyciu elementu Policy.RETRY. Przyczyną może być to, że usługa niedostępna.

  5. W przypadku błędu aplikacji, np. gdy aplikacja próbuje sprawdź licencję na nieprawidłową nazwę pakietu, LicenseChecker zwraca błąd odpowiedź na żądanie applicationError() usługi LicenseCheckerCallback .

Pamiętaj, że oprócz zainicjowania sprawdzenia licencji i obsługi które zostały opisane w poniższych sekcjach, aplikacja musi również aby udostępnić wdrożenie zasad, a jeśli Policy przechowuje dane odpowiedzi (takie jak ServerManagedPolicy) jako implementacja Obfuscator.

Dodaj importy

Najpierw otwórz plik zajęć w głównym działaniu aplikacji i zaimportuj LicenseChecker i LicenseCheckerCallback z pakietu 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;

Jeśli używasz domyślnej implementacji Policy udostępnionej w LVL, ServerManagedPolicy, zaimportuj ją wraz z AESObfuscator. Jeśli jesteś za pomocą niestandardowych Policy lub Obfuscator, zaimportuj je.

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;

Wdrożenie LicenseCheckerCallback jako prywatnej klasy wewnętrznej

LicenseCheckerCallback to interfejs udostępniany przez LVL w wyniku sprawdzania licencji. Aby zapewnić obsługę licencjonowania z użyciem LVL, musisz: zaimplementuj LicenseCheckerCallback i oraz metody zezwalania na dostęp do aplikacji lub jej blokowania.

Wynikiem sprawdzenia licencji jest zawsze wywołanie jednego z LicenseCheckerCallback metod, utworzonych na podstawie weryfikacji odpowiedzi ładunek, kod odpowiedzi serwera i wszelkie dodatkowe przez Policy. Aplikacja może implementować te metody w dowolny potrzebny sposób. W więc metody powinny być proste, ograniczając się do zarządzania interfejsem użytkownika stanu i dostępu do aplikacji. Jeśli chcesz dodać dalsze przetwarzanie licencji odpowiedzi, na przykład przez skontaktowanie się z serwerem backendu lub zastosowanie niestandardowych ograniczeń, spróbuj użyć kodu w Policy, zamiast w metodach LicenseCheckerCallback.

W większości przypadków należy zadeklarować implementację LicenseCheckerCallback jako klasa prywatna w głównej aplikacji Zajęcia.

Zaimplementuj metody allow() i dontAllow() jako niezbędną. Na początek można skorzystać z prostych sposobów obsługi wyników w interfejsie takie jak wyświetlenie wyniku licencji w oknie. Dzięki temu uzyskasz która działa szybciej i może pomóc w debugowaniu. Później, po możesz określić żądane przez Ciebie zachowania, możesz dodać bardziej złożoną obsługę.

Niektóre sugestie dotyczące postępowania z nielicencjonowanymi odpowiedziami w dontAllow(), w tym:

  • Wyświetl komunikat „Spróbuj ponownie”. okno, w tym przycisk do rozpoczynania sprawdzanie nowej licencji, czy dostarczony reason to Policy.RETRY.
  • Wyświetlaj tekst „Kup tę aplikację”. wraz z przyciskiem precyzyjny link do strony z informacjami o aplikacji w Google Play, na której użytkownik może kupić tę aplikację. Więcej informacji na temat konfigurowania przeczytaj artykuł Tworzenie linków do Twoich produktów.
  • Wyświetli powiadomienie Toast informujące, że funkcje aplikacji są ograniczone, ponieważ nie jest objęta licencją.

Poniższy przykład pokazuje, jak przykładowa aplikacja LVL implementuje LicenseCheckerCallback, przy użyciu metod, które wyświetlają sprawdzenie licencji, .

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

Dodatkowo należy zaimplementować applicationError() którą LVL wywołuje, aby umożliwić aplikacji obsługę błędów, które nie są można spróbować ponownie. Listę takich błędów znajdziesz w sekcji Serwer Kody odpowiedzi w dokumentacji dotyczącej licencji. Możesz zastosować przy użyciu tej metody. W większości przypadków powinna rejestrować kod błędu i wywoływać funkcję dontAllow().

Utwórz moduł obsługi publikowania z poziomu LicenseCheckerCallback do wątku UI

Podczas sprawdzania licencji LVL przekazuje żądanie do Google Play. która obsługuje komunikację z serwerem licencji. POZIOM przekazuje żądanie przez asynchroniczny IPC (za pomocą Binder), więc faktyczne przetwarzanie i komunikacja sieciowa nie odbywają się w wątku. zarządzane przez Twoją aplikację. Gdy aplikacja Google Play odbiera wynik, wywołuje metodę wywołania zwrotnego przez IPC, która z kolei są wykonywane w puli wątków IPC w procesie aplikacji.

Klasa LicenseChecker zarządza komunikacją IPC aplikacji z aplikacji Google Play, m.in. wywołania, które wysyła żądanie, wywołanie zwrotne, które otrzyma odpowiedź. LicenseChecker śledzi także licencję otwartą i zarządza ich limitami czasu.

Aby poprawnie obsługiwał czas oczekiwania i przetwarzał przychodzące odpowiedzi bez wpływu na wątek UI aplikacji, funkcja LicenseChecker tworzy wątku w tle podczas tworzenia wystąpienia. W wątku przetwarza w całości wyniki sprawdzania licencji, czy wynik to odpowiedź otrzymana z serwera; lub błąd przekroczenia limitu czasu. Po zakończeniu weryfikacji LVL wywołuje LicenseCheckerCallback metod z wątku w tle.

Dla Twojej aplikacji oznacza to, że:

  1. W wielu przypadkach Twoje metody LicenseCheckerCallback będą wywoływane z w wątku w tle.
  2. Te metody nie będą w stanie zaktualizować stanu ani wywołać żadnego przetwarzania w wątku UI, chyba że utworzysz w wątku interfejsu moduł obsługi i otrzymasz wywołanie zwrotne. do modułu obsługi.

Jeśli chcesz, aby metody LicenseCheckerCallback aktualizowały wątek UI, utwórz instancję Handler w głównym działaniu onCreate(), jak pokazano poniżej. W tym przykładzie kod LVL przykładowej aplikacji Metody LicenseCheckerCallback (patrz wyżej) wywołują metodę displayResult() do zaktualizuj wątek UI za pomocą 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();
    }

Następnie w metodach LicenseCheckerCallback możesz używać metod modułu obsługi, aby po przesłaniu obiektów Runnable lub Message do modułu obsługi. Przykład aplikacja uwzględniona w LVL przesyła element wykonywalny do modułu obsługi w wątku UI aby wyświetlić stan licencji.

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

Tworzenie instancji LicenseChecker i LicenseCheckerCallback

W sekcji Aktywność onCreate(), Tworzenie prywatnych instancji LicenseCheckerCallback i LicenseChecker. Musisz utwórz najpierw instancję LicenseCheckerCallback, ponieważ trzeba przekazać odwołanie do tej instancji przy wywołaniu konstruktora dla LicenseChecker.

Podczas tworzenia instancji LicenseChecker musisz przekazać te parametry:

  • Aplikacja Context
  • Odwołanie do implementacji Policy, która ma być używana do sprawdzania licencji. W w większości przypadków należy użyć domyślnej implementacji Policy udostępnionej przez LVL, ServerManagedPolicy.
  • Zmienna String zawierająca klucz publiczny Twojego konta wydawcy dla licencji.

Jeśli korzystasz z ServerManagedPolicy, nie potrzebujesz dostępu do klasy bezpośrednio, co pozwala utworzyć jej instancję w konstruktorze LicenseChecker, jak widać w przykładzie poniżej. Pamiętaj, że musisz przekazać odwołanie do nowego elementu Instancja zaciemniania kodu podczas tworzenia instancji ServerManagedPolicy.

Przykład poniżej pokazuje utworzenie instancji LicenseChecker oraz LicenseCheckerCallback z metody onCreate() aktywności zajęcia.

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

Pamiętaj, że funkcja LicenseChecker wywołuje z interfejsu metody LicenseCheckerCallback. do wątku tylko wtedy, gdy poprawna odpowiedź dotycząca licencji znajduje się w pamięci podręcznej. Jeśli informacje o sprawdzaniu licencji są wysyłane do serwera, wywołania zwrotne zawsze pochodzą z adresu w tle, nawet w przypadku błędów sieci.

Wywołaj funkcję checkAccess(), aby rozpocząć sprawdzanie licencji

W głównej aktywności dodaj wywołanie do metody checkAccess() funkcji LicenseChecker instancję. Podczas rozmowy przekaż odniesienie do swojego wystąpienie LicenseCheckerCallback jako parametr. Jeśli chcesz zareagować efekty specjalne lub zarządzanie stanem przed rozmową, może Ci się przydać aby wywołać checkAccess() z metody kodu. Na przykład parametr LVL przykładowa aplikacja wywołuje metodę checkAccess() z Metoda opakowań 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);
    }

Umieszczanie klucza publicznego na potrzeby licencjonowania

W przypadku każdej aplikacji Usługa Google Play automatycznie generuje 2048-bitową parę kluczy RSA (publiczny/prywatny), która jest używana i rozliczenia w aplikacji. Para kluczy jest jednoznacznie powiązana z aplikacji. Chociaż są powiązane z aplikacją, para kluczy jest inny niż klucz, którego używasz do podpisywania aplikacji (lub pochodnego od niego).

Konsola Google Play ujawnia klucz publiczny do licencjonowania zalogowany do Konsoli Play, ale zachowuje klucz prywatny ukryte przed wszystkimi użytkownikami w bezpiecznej lokalizacji. Gdy aplikacja poprosi o sprawdzanie licencji na aplikację opublikowaną na Twoim koncie, serwer licencjonowania podpisuje odpowiedź licencji przy użyciu klucza prywatnego pary kluczy aplikacji. Gdy LVL otrzyma odpowiedź, używa klucza publicznego dostarczonego przez aplikacji do zweryfikowania podpisu odpowiedzi licencji.

Aby dodać licencję do aplikacji, musisz uzyskać: klucz publiczny do licencjonowania i skopiuj go do aplikacji. Oto jak znaleźć: klucz publiczny aplikacji do licencjonowania:

  1. Otwórz Konsolę Google Play i zaloguj się. Pamiętaj, aby zalogować się na konto, z którego aplikacja została stworzona licencji zostanie opublikowane (lub zostanie opublikowane).
  2. Na stronie z informacjami o aplikacji znajdź sekcję Usługi i Interfejsy API i kliknij go.
  3. W sekcji Usługi i API, znajdź Licencjonowanie Rozliczenia w aplikacji. Twój klucz publiczny dla jest udzielana w Twój klucz licencyjny tej aplikacji.

Aby dodać klucz publiczny do aplikacji, po prostu skopiuj i wklej ten klucz z pola do aplikacji jako wartość zmiennej String, BASE64_PUBLIC_KEY Przy kopiowaniu upewnij się, że masz zaznaczono cały ciąg klucza, nie pomijając żadnych znaków.

Oto przykład z przykładowej aplikacji 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
    ...
}

Wywoływanie metody onDestroy() używanego narzędzia LicenseChecker zamykanie połączeń IPC

Pozwól LVL oczyścić się przed zgłoszeniem Context – zmiany, dodaj wywołanie do: LicenseChecker Metoda onDestroy() z modułu aktywności onDestroy(). Wywołanie powoduje, że LicenseChecker, aby prawidłowo zamknąć otwarte połączenie IPC z Google Play. ILicensingService aplikacji i usunie wszelkie lokalne odwołania do tej usługi. i moduł obsługi.

Nie udało się wywołać metody onDestroy() metody LicenseChecker może powodować problemy w trakcie cyklu życia aplikacji. Na przykład, jeśli plik użytkownik zmieni orientację ekranu, gdy jest aktywne sprawdzanie licencji, Element Context został zniszczony. Jeśli Twoja aplikacja nie poprawnie zamknij połączenie IPC LicenseChecker, aplikacja ulegnie awarii po otrzymaniu odpowiedzi. Podobnie, jeśli użytkownik zamknie aplikację a w trakcie sprawdzania licencji aplikacja ulegnie awarii, gdy otrzymano odpowiedź, chyba że poprawnie wywołała Metoda onDestroy() przeglądarki LicenseChecker do odłączenia od usługi.

Oto przykład z przykładowej aplikacji uwzględnionej w LVL, gdzie mChecker to instancja LicenseChecker:

Kotlin

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

Java

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

Jeśli rozszerzasz lub modyfikujesz numer LicenseChecker, konieczne może być również wywołanie metody finishCheck() interfejsu LicenseChecker, aby wyczyścić otwarte IPC. połączeń.

Stosowanie ograniczenia liczby urządzeń

W niektórych przypadkach Policy może ograniczać liczbę rzeczywistych które mogą korzystać z 1 licencji. Uniemożliwiłoby to użytkownikowi przeniesienia licencjonowanej aplikacji na wiele urządzeń aplikacji na tych urządzeniach z tym samym identyfikatorem konta. Zapobiegłoby to również użytkownik z „udostępniania” przez podanie informacji o koncie, związane z licencją innych osób, które mogą się do niej zalogować konta na swoich urządzeniach i uzyskać dostęp do licencji na aplikację.

LVL wspiera licencjonowanie dla poszczególnych urządzeń, udostępniając DeviceLimiter, który deklaruje jedną metodę, allowDeviceAccess() Gdy zasób LicenseValidator obsługuje odpowiedź z serwera licencjonowania wywołuje funkcję allowDeviceAccess(), przekazując w ten sposób identyfikator użytkownika wyodrębniony z odpowiedzi.

Jeśli nie chcesz stosować ograniczeń dotyczących urządzeń, żadna praca nie jest wymagane – klasa LicenseChecker automatycznie używa wartości domyślnej implementacji o nazwie NullDeviceLimiter. Jak sama nazwa wskazuje, NullDeviceLimiter nie jest operacją klasa, której metoda allowDeviceAccess() zwraca po prostu odpowiedź LICENSED dla wszystkich użytkowników i urządzeń.

Uwaga: licencjonowanie na poziomie urządzenia nie jest zalecane w przypadku dla większości aplikacji, ponieważ:

  • Wymaga udostępnienia serwera backendu do zarządzania użytkownikami i urządzeniami mapowanie,
  • Odebranie użytkownikowi dostępu do które w uprawniony sposób kupiły na innym urządzeniu.

Zaciemnianie kodu

Aby zapewnić bezpieczeństwo aplikacji, zwłaszcza w przypadku płatnej aplikacji korzystającej z licencjonowania lub niestandardowych ograniczeń i zabezpieczeń, ważne jest, aby zaciemniać kod aplikacji. Prawidłowo zaciemnianie kodu utrudnia złośliwemu użytkownikowi dekompilację kodu bajtowego, modyfikować go, np. usuwając weryfikację licencji – i skompilować go na nowo.

Dostępnych jest kilka programów do zaciemniania kodu dla aplikacji na Androida, w tym ProGuard, która oferuje również funkcje optymalizacji kodu. użycie ProGuard lub podobnego programu do zaciemniania kodu. Twój kod jest zdecydowanie zalecany dla wszystkich aplikacji, które korzystają z usług Google Zagraj w Licencjonowanie.

Publikowanie licencjonowanej aplikacji

Po zakończeniu testowania implementacji licencji możesz opublikować aplikację w Google Play. Wykonaj zwykłe czynności, aby przygotować, podpisać, a następnie opublikować aplikację.

Gdzie uzyskać pomoc

W przypadku pytań lub problemów przy wdrażaniu podczas publikowania w aplikacjach, skorzystaj z zasobów pomocy wymienionych w tabeli poniżej. Kierując swoje pytania na właściwe forum, uzyskasz uzyskać pomoc w krótszym czasie.

Tabela 2. Zasoby pomocy dla programistów do Usługi licencjonowania w Google Play.

Typ pomocy Zasób Zakres tematów
Problemy podczas programowania i testowania Grupy dyskusyjne Google: android-developers Pobieranie i integracja LVL, projekty biblioteczne, Policy pytania, pomysły na wrażenia użytkownika, obsługa odpowiedzi, Obfuscator, IPC, test konfiguracja środowiska
Stack Overflow: http://stackoverflow.com/questions/tagged/android
Problemy z kontami, publikowaniem i wdrażaniem Google Play. Forum pomocy Konta wydawcy, para kluczy licencyjnych, konta testowe, serwer odpowiedzi, odpowiedzi testowe, wdrażanie aplikacji i wyniki
Rynek Pomoc dotycząca licencji – najczęstsze pytania
Tracker problemów LVL Licencjonowanie rynkowe narzędzie do rejestrowania problemów w projekcie Zgłoszenia błędów i problemów związane konkretnie z klasami kodu źródłowego LVL i implementacjach interfejsu

Ogólne informacje o publikowaniu w grupach wymienionych powyżej znajdziesz w sekcji Zasoby społeczności. na stronie Zasoby pomocy dla programistów.

Dodatkowe materiały

Przykładowa aplikacja dołączona do LVL zawiera pełny przykład tego, aby rozpocząć sprawdzanie licencji i obsługować wynik, MainActivity zajęcia.