Klasy i interfejsy LVL
Tabela 1 zawiera listę wszystkich plików źródłowych w bibliotece weryfikacji licencji (LVL), która jest dostępna w pakiecie Android SDK. Wszystkie pliki wchodzą w skład pakietu com.android.vending.licensing
.
Kategoria | Nazwa | Opis |
---|---|---|
Sprawdzanie licencji i wynik | Narzędzie LicenseChecker | Klasa, którą tworzysz (lub podklasę), aby rozpocząć sprawdzanie licencji. |
Wywołanie zwrotne sprawdzania licencji | Interfejs, który stosujesz do obsługi wyniku sprawdzania licencji. | |
Zasady | Zasady | Interfejs, który stosujesz do określania, czy zezwolić na dostęp do aplikacji na podstawie odpowiedzi licencji. |
Zasada zarządzania serwerem | Domyślna implementacja Policy . Wykorzystuje ustawienia udostępnione przez serwer licencjonowania do zarządzania lokalnym przechowywaniem danych licencji, ich ważność i ponawianiem prób. |
|
Ścisła zasada | Alternatywna implementacja Policy . Wymusza licencjonowanie tylko na podstawie bezpośredniej odpowiedzi licencji z serwera. Brak buforowania i ponawiania żądań. |
|
Zaciemnianie danych (opcjonalne) |
Zaciemnianie | Interfejs, który musisz wdrożyć, jeśli używasz Policy (np. ServerManagedPolicy), który przechowuje w pamięci podręcznej dane odpowiedzi licencji w pamięci trwałej.
Stosuje algorytm zaciemniania do kodowania i dekodowania danych zapisywanych lub odczytywanych. |
Moduł AESObfuscator | Domyślna implementacja maskowania, która do zaciemniania i usuwania zaciemnienia danych wykorzystuje algorytm AES szyfrowania/odszyfrowywania. | |
Ograniczenie dotyczące urządzeń (opcjonalne) |
DeviceLimiter | Interfejs, który musisz wdrożyć, aby ograniczyć korzystanie z aplikacji do konkretnego urządzenia. Wywołano z elementu LicenseValidator. Wdrożenie funkcji DeviceLimiter nie jest zalecane w przypadku większości aplikacji, ponieważ wymaga serwera backendu i może spowodować utratę dostępu do licencjonowanych aplikacji, jeśli nie zostały starannie zaprojektowane. |
Ogranicznik urządzenia o wartości null | Domyślna implementacja ograniczenia parametru DeviceLimiter, która nie jest obsługiwana (umożliwia dostęp do wszystkich urządzeń). | |
Podstawowa biblioteka, integracja nie jest wymagana | Dane odpowiedzi | Klasa, która zawiera pola odpowiedzi licencji. |
Element LicenseValidator | Klasa, która odszyfrowuje i weryfikuje odpowiedź otrzymaną z serwera licencji. | |
Wyjątek walidacji | Klasa, która wskazuje błędy występujące podczas weryfikacji integralności danych zarządzanych przez zaciemniacz. | |
Selektor preferencji | Klasa narzędzia, która zapisuje/czyta zaciemnione dane w magazynie SharedPreferences systemu. |
|
ILicensingService | Jednokierunkowy interfejs IPC, przez który do klienta Google Play jest przekazywane żądanie sprawdzania licencji. | |
ILicenseResultListener | Jednokierunkowa implementacja wywołania zwrotnego IPC, w ramach której aplikacja otrzymuje asynchroniczną odpowiedź z serwera licencjonowania. |
Odpowiedź serwera
Tabela 2 zawiera listę wszystkich pól odpowiedzi licencji zwróconych przez serwer licencjonowania.
Pole | Opis |
---|---|
responseCode |
Kod odpowiedzi zwrócony przez serwer licencjonowania. Kody odpowiedzi znajdziesz w sekcji Kody odpowiedzi serwera. |
signedData |
Konkatenacja ciągu znaków zawierająca dane zwrócone przez serwer licencjonowania w następujący sposób: responseCode|nonce|packageName|versionCode|userId|timestamp:extras .
|
signature |
Podpis klucza signedData za pomocą klucza specyficznego dla aplikacji.
|
Kody odpowiedzi serwera
Tabela 3 zawiera wszystkie kody odpowiedzi licencji obsługiwane przez serwer licencjonowania. Ogólnie aplikacja powinna obsługiwać wszystkie te kody odpowiedzi. Domyślnie klasa LicenseValidator w LVL zapewnia obsługę wszystkich kodów odpowiedzi.
Kod odpowiedzi | Reprezentacja liczby całkowitej | Opis | Podpisano? | Dodatkowe treści | Komentarze |
---|---|---|---|---|---|
LICENSED |
0 |
Użytkownik otrzyma licencję na aplikację. Użytkownik kupił aplikację lub ma uprawnienia do pobrania i zainstalowania jej wersji alfa lub beta. | Tak | VT , GT GR |
Zezwalaj na dostęp zgodnie z ograniczeniami Policy . |
LICENSED_OLD_KEY |
2 |
Użytkownik ma licencję na aplikację, ale dostępna jest zaktualizowana wersja aplikacji podpisana innym kluczem. | Tak | VT , GT , GR , UT |
Opcjonalnie zezwól na dostęp zgodnie z ograniczeniami Policy .
Może wskazywać, że para kluczy używana przez zainstalowaną wersję aplikacji jest nieprawidłowa lub została zhakowana. Aplikacja może zezwolić na dostęp w razie potrzeby lub poinformować użytkownika o możliwości uaktualnienia i ograniczyć dalsze korzystanie z aplikacji do czasu uaktualnienia. |
NOT_LICENSED |
1 |
Użytkownik nie ma licencji na tę aplikację. | Nie | Nie zezwalaj na dostęp. | |
ERROR_CONTACTING_SERVER |
257 |
Błąd lokalny – aplikacja Google Play nie mogła nawiązać połączenia z serwerem licencjonowania, prawdopodobnie z powodu problemów z dostępnością sieci. | Nie | Ponów próbę sprawdzenia licencji zgodnie z limitem ponownych prób (Policy ). |
|
ERROR_SERVER_FAILURE |
4 |
Błąd serwera – serwer nie mógł wczytać pary kluczy aplikacji na potrzeby licencjonowania. | Nie | Ponów próbę sprawdzenia licencji zgodnie z limitem ponownych prób (Policy ).
|
|
ERROR_INVALID_PACKAGE_NAME |
258 |
Błąd lokalny – aplikacja zażądała sprawdzenia licencji pakietu, który nie jest zainstalowany na urządzeniu. | Nie | Nie próbuj ponownie sprawdzić licencji.
Zwykle przyczyną jest błąd deweloperski. |
|
ERROR_NON_MATCHING_UID |
259 |
Błąd lokalny – aplikacja zażądała sprawdzenia licencji pakietu, którego identyfikator UID (pakiet, para identyfikatora użytkownika) nie jest zgodny z identyfikatorem aplikacji, która wysłała żądanie. | Nie | Nie próbuj ponownie sprawdzić licencji.
Zwykle przyczyną jest błąd deweloperski. |
|
ERROR_NOT_MARKET_MANAGED |
3 |
Błąd serwera – aplikacja (nazwa pakietu) nie została rozpoznana przez Google Play. | Nie | Nie próbuj ponownie sprawdzić licencji.
Może wskazywać, że aplikacja nie została opublikowana w Google Play lub wystąpił błąd w implementacji licencjonowania. |
Uwaga: zgodnie z opisem w sekcji Konfigurowanie środowiska testowego kod odpowiedzi można ręcznie zastąpić w Konsoli Google Play dla dewelopera aplikacji i wszystkich zarejestrowanych użytkowników testowych.
Uwaga: wcześniej można było testować aplikację, przesyłając nieopublikowaną wersję roboczą. Ta funkcja nie jest już obsługiwana. Musisz ją opublikować w kanale dystrybucji alfa lub beta. Więcej informacji znajdziesz w artykule Wersje robocze aplikacji nie są już obsługiwane.
Dodatki do funkcji odpowiedzi serwera
Aby pomóc aplikacji w zarządzaniu dostępem do aplikacji w okresie zwrotu środków za aplikację oraz podać inne informacje, serwer licencjonowania umieszcza w odpowiedziach licencji kilka rodzajów informacji. W szczególności usługa podaje zalecane wartości okresu ważności licencji aplikacji, okresu prolongaty ponawiania próby, maksymalnej dozwolonej liczbie ponownych prób i innych ustawień. Jeśli Twoja aplikacja korzysta z plików rozszerzeń APK, odpowiedź zawiera też nazwy plików, rozmiary i adresy URL. Serwer dołącza te ustawienia w postaci par klucz-wartość w polu „extras” odpowiedzi licencji.
Każda implementacja Policy
może wyodrębnić ustawienia dodatków z odpowiedzi licencji i użyć ich w razie potrzeby. Domyślna implementacja Policy
na poziomie LVL (ServerManagedPolicy
) służy jako działająca implementacja i pokazuje, jak uzyskiwać, przechowywać i używać ustawień.
Dodatek | Opis |
---|---|
VT |
Sygnatura czasowa ważności licencji. Określa datę i godzinę wygaśnięcia aktualnej (w pamięci podręcznej) odpowiedzi dotyczącej licencji i należy ją ponownie sprawdzić na serwerze licencjonowania. Zapoznaj się z sekcją Okres ważności licencji poniżej. |
GT |
Sygnatura czasowa okresu prolongaty. Określa koniec okresu, w którym zasada może zezwalać na dostęp do aplikacji, mimo że stan odpowiedzi to RETRY . Wartość jest zarządzana przez serwer, ale typowa wartość to 5 lub więcej dni. Zapoznaj się z sekcją poniżej na temat okresu ponawiania i maksymalnej liczby ponownych prób. |
GR |
Maksymalna liczba ponownych prób. Określa, na ile następujących po sobie kontroli licencji RETRY ma zezwalać Policy , zanim odmówisz użytkownikowi dostępu do aplikacji.
Wartość jest zarządzana przez serwer, ale typowa to „10” lub większa. Zapoznaj się z sekcją poniżej na temat okresu ponawiania i maksymalnej liczby ponownych prób. |
UT |
Sygnatura czasowa aktualizacji. Określa dzień i godzinę przesłania i opublikowania najnowszej aktualizacji aplikacji. Serwer zwraca te dodatkowe odpowiedzi tylko w przypadku odpowiedzi |
FILE_URL1 lub FILE_URL2 |
Adres URL pliku rozszerzenia (1 oznacza plik główny, 2 – plik poprawki). Służy do pobierania pliku przez HTTP. |
FILE_NAME1 lub FILE_NAME2 |
Nazwa pliku rozszerzenia (1 oznacza plik główny, 2 to plik poprawki). Musisz użyć tej nazwy podczas zapisywania pliku na urządzeniu. |
FILE_SIZE1 lub FILE_SIZE2 |
Rozmiar pliku w bajtach (1 oznacza plik główny, 2 – plik poprawki). Użyj tej opcji, aby pomóc w pobieraniu danych i przed pobraniem upewnić się, że w pamięci współdzielonej urządzenia jest dość miejsca. |
Okres ważności licencji
Serwer licencji Google Play ustawia okres ważności licencji dla wszystkich pobranych aplikacji. Okres określa przedział czasu, w którym stan licencji aplikacji powinien być uważany za niezmienny i buforowany przez Policy
licencjonowania w aplikacji. Serwer licencjonowania uwzględnia okres ważności w odpowiedzi na wszystkie kontrole licencji i dodaje do odpowiedzi sygnaturę czasową zakończenia ważności (jako dodatkowy element pod kluczem VT
). Policy
może wyodrębnić wartość klucza VT i użyć jej, aby warunkowo zezwolić na dostęp do aplikacji bez ponownego sprawdzania licencji, dopóki nie wygaśnie okres ważności.
Ważność licencji sygnalizuje licencję Policy
, gdy musi ponownie sprawdzić jej stan na serwerze licencji. Nie służy on do sugerowania, czy aplikacja jest rzeczywiście licencjonowana do użytku. Oznacza to, że gdy okres ważności licencji na aplikację wygaśnie, nie oznacza to, że aplikacja nie jest już licencjonowana. Wskazuje jedynie, że Policy
musi ponownie sprawdzić stan licencji na serwerze. Dlatego, o ile okres ważności licencji nie upłynął, Policy
może lokalnie zapisywać początkowy stan licencji w pamięci podręcznej i zwracać stan licencji zapisanej w pamięci podręcznej, zamiast wysyłać do serwera nowe sprawdzanie licencji.
Serwer licencji zarządza okresem ważności, aby pomóc aplikacji we właściwym egzekwowaniu licencjonowania w okresie zwrotu kosztów w przypadku płatnych aplikacji oferowanych przez Google Play. który określa okres ważności w zależności od tego, czy aplikacja została zakupiona, a jeśli tak, to jak dawno temu. Serwer ustawia ten okres ważności:
- W przypadku płatnej aplikacji serwer ustawia początkowy okres ważności licencji, tak aby odpowiedź była ważna tak długo, jak aplikacja podlega zwrotowi. Licencjonowany
Policy
w aplikacji może buforować wynik wstępnego sprawdzenia licencji i nie musi robić tego ponownie, dopóki nie wygaśnie okres jej ważności. - Gdy aplikacja nie podlega już zwrotowi, serwer ustawia dłuższy okres ważności, który zwykle jest liczbą dni.
- W przypadku bezpłatnej aplikacji serwer ustawia okres ważności na bardzo wysoką wartość (
long.MAX_VALUE
). Dzięki temu, jeśliPolicy
zapisze sygnaturę czasową ważności lokalnie w pamięci podręcznej, w przyszłości nie będzie trzeba ponownie sprawdzać stanu licencji aplikacji.
Implementacja ServerManagedPolicy
używa wyodrębnionej sygnatury czasowej (mValidityTimestamp
) jako głównego warunku przy określaniu, czy należy ponownie sprawdzić stan licencji na serwerze, zanim zezwolisz użytkownikowi na dostęp do aplikacji.
Okres i maksymalna liczba ponownych prób
W niektórych przypadkach warunki systemu lub sieci mogą uniemożliwić sprawdzenie licencji aplikacji z serwera licencyjnego albo spowodować, że odpowiedź serwera nie dotrze do aplikacji klienckiej Google Play. Na przykład użytkownik może uruchomić aplikację, gdy sieć komórkowa lub połączenie transmisji danych nie są dostępne (np. w samolocie) albo gdy połączenie sieciowe jest niestabilne lub sygnał sieci komórkowej jest słaby.
Gdy problemy z siecią uniemożliwiają sprawdzanie licencji lub przerywają sprawdzanie licencji, klient Google Play powiadamia aplikację, zwracając kod odpowiedzi RETRY
do metody processServerResponse()
w Policy
. W przypadku problemów systemowych, np. gdy aplikacja nie może powiązać się z implementacją ILicensingService
w Google Play, sama biblioteka LicenseChecker
wywołuje metodę zasad processServerResponse()
z kodem odpowiedzi RETRY
.
Ogólnie kod odpowiedzi RETRY
jest sygnałem dla aplikacji, że wystąpił błąd, który uniemożliwia ukończenie sprawdzania licencji.
Serwer Google Play pomaga aplikacji zarządzać licencjonowaniem w przypadku błędów przez ustawienie „okresu prolongaty” i zalecanej maksymalnej liczby ponownych prób. Serwer uwzględnia te wartości we wszystkich odpowiedziach dotyczących sprawdzania licencji i dołącza je jako dodatki pod kluczami GT
i GR
.
Aplikacja Policy
może wyodrębnić dodatki GT
i GR
oraz użyć ich do warunkowego zezwolenia na dostęp do aplikacji w ten sposób:
- Jeśli sprawdzanie licencji skutkuje odpowiedzią
RETRY
,Policy
powinno buforować kod odpowiedziRETRY
i zwiększać liczbę odpowiedzi (RETRY
). Policy
powinien umożliwiać użytkownikowi dostęp do aplikacji, pod warunkiem że okres prolongaty ponawiania jest nadal aktywny lub nie została osiągnięta maksymalna liczba ponownych prób.
ServerManagedPolicy
używa podanych przez serwer wartości GT
i GR
, jak opisano powyżej. Przykład poniżej pokazuje warunkową obsługę odpowiedzi na ponawianie w metodzie allow()
. Liczba odpowiedzi typu RETRY
jest zachowywana w metodzie processServerResponse()
, a nie wyświetlana.
Kotlin
fun allowAccess(): Boolean { val ts = System.currentTimeMillis() return when(lastResponse) { LICENSED -> { // Check if the LICENSED response occurred within the validity timeout. ts <= validityTimestamp // Cached LICENSED response is still valid. } RETRY -> { ts < lastResponseTime + MILLIS_PER_MINUTE && // Only allow access if we are within the retry period // or we haven't used up our max retries. (ts <= retryUntil || retryCount <= maxRetries) } else -> false } }
Java
public boolean allowAccess() { long ts = System.currentTimeMillis(); if (lastResponse == LicenseResponse.LICENSED) { // Check if the LICENSED response occurred within the validity timeout. if (ts <= validityTimestamp) { // Cached LICENSED response is still valid. return true; } } else if (lastResponse == LicenseResponse.RETRY && ts < lastResponseTime + MILLIS_PER_MINUTE) { // Only allow access if we are within the retry period // or we haven't used up our max retries. return (ts <= retryUntil || retryCount <= maxRetries); } return false; }