Pliki rozszerzeń APK

Google Play wymaga, aby skompresowany plik APK pobierany przez użytkowników miał rozmiar nie większy niż 100 MB. W większości aplikacji wystarcza wystarczająco dużo miejsca na kod i zasoby. Niektóre aplikacje potrzebują jednak więcej miejsca na obrazy w wysokiej jakości, pliki multimedialne lub inne duże zasoby. Wcześniej, jeśli rozmiar skompresowanego pliku do pobrania aplikacji przekraczał 100 MB, trzeba było hostować i pobierać dodatkowych zasobów, gdy użytkownik uruchomi aplikację. Hosting i wyświetlanie dodatkowych plików może jest kosztowne, a wygoda użytkownika jest często niższa od idealnej. Aby ułatwić Ci ten proces i wygodniejsze dla użytkowników Google Play umożliwia dołączenie dwóch dużych plików rozszerzeń, uzupełniają pakiet APK.

Google Play przechowuje pliki rozszerzeń aplikacji i udostępnia je na urządzeniu pod adresem nie ponosisz żadnych kosztów. Pliki rozszerzeń są zapisywane w pamięci współdzielonej urządzenia (czyli karta SD lub partycja podłączana przez USB; zwany także „zewnętrznym” pamięci masowej), do której aplikacja ma dostęp . Na większości urządzeń Google Play pobiera pliki rozszerzające w tym samym czasie. pobiera plik APK, dzięki czemu aplikacja ma wszystko, czego potrzebuje, gdy użytkownik ją otworzy za pierwszym razem. W niektórych przypadkach aplikacja musi jednak pobrać pliki z Google Play. po uruchomieniu aplikacji.

Jeśli nie chcesz używać plików rozszerzających, a rozmiar skompresowanego pliku do pobrania aplikacji jest większy niż 100 MB, prześlij aplikację za pomocą aplikacji na Androida Pakiety, które umożliwiają pobranie skompresowanego pliku o wielkości do 200 MB. Ponadto, ponieważ użycie pakietów aplikacji opóźnia generowanie plików APK i podpisywanie ich w Google Play, użytkownicy pobierają zoptymalizowane pliki APK, tylko kod i zasoby, których potrzebują do uruchomienia aplikacji. Nie musisz budować, podpisywać zarządzać wieloma pakietami APK lub plikami rozszerzeń, dzięki czemu użytkownicy będą mogli pobierać mniejsze i lepiej zoptymalizowane pliki do pobrania.

Omówienie

Przy każdym przesyłaniu pliku APK w Konsoli Google Play możesz: dodaj jeden lub dwa pliki rozszerzające do pliku APK. Każdy plik może mieć maksymalnie 2 GB i może być w dowolnym formacie ale zalecamy korzystanie z skompresowanego pliku, by zmniejszyć przepustowość pobierania podczas pobierania. Każdy plik rozszerzeń pełni inną rolę:

  • Główny plik rozszerzenia to główny plik rozszerzenia z dodatkowymi zasobami wymaganymi przez aplikację.
  • Plik rozszerzenia poprawki jest opcjonalny i służy do wprowadzania niewielkich aktualizacji głównym pliku rozszerzenia.

Można ich używać w dowolny sposób, jednak zalecamy, by główny plik plik rozszerzenia dostarcza zasoby główne i powinien być rzadko aktualizowany, jeśli w ogóle jest aktualizowany; rozszerzenie z poprawką powinien być mniejszy i pełnić rolę „operatora poprawek” oraz być aktualizowany przy każdym głównym lub w razie potrzeby.

Jednak nawet wtedy, gdy aktualizacja aplikacji wymaga tylko nowego pliku rozszerzenia poprawki, nadal musisz prześlij nowy plik APK ze zaktualizowanym plikiem versionCode w pliku manifestu. (Parametr Konsola Play nie umożliwia przesłania pliku rozszerzenia do istniejącego pakietu APK).

Uwaga: plik rozszerzenia poprawki pod względem semantycznym jest taki sam jak plik głównego pliku rozszerzenia – z każdego pliku możesz korzystać w dowolny sposób.

Format nazwy pliku

Przesyłany plik rozszerzenia może mieć dowolny wybrany format (ZIP, PDF, MP4 itp.). Możesz też użyj narzędzia JOBB, aby hermetyzować i szyfrować zbiór, plików zasobów i kolejnych poprawek dla tego zbioru. Niezależnie od typu pliku usługa Google Play traktuje je jako nieprzejrzyste binarne bloby i zmienia ich nazwy zgodnie z tym schematem:

[main|patch].<expansion-version>.<package-name>.obb

Schemat ten składa się z 3 elementów:

main lub patch
Określa, czy plik jest głównym plikiem rozszerzenia, czy plikiem rozszerzenia z poprawką. Istnieje możliwość tylko jeden plik główny i jeden plik poprawki dla każdego pakietu APK.
<expansion-version>
Liczba całkowita zgodna z kodem wersji pliku APK z rozwinięciem pierwszy powiązany (pasuje do android:versionCode ).

„Pierwszy” jest wyróżniona, ponieważ chociaż Konsola Play umożliwia ponowne użycie przesłanego pliku rozszerzenia z nowym pakietem APK, nazwa pliku nie ulegnie zmianie – zachowuje wersję zastosowaną do pliku w chwili jego przesłania po raz pierwszy.

<package-name>
Nazwa pakietu aplikacji w stylu Java.

Załóżmy, że wersja pakietu APK to 314159, a nazwa Twojego pakietu to com.example.app. Jeśli po przesłaniu głównego pliku rozszerzenia jego nazwa zostanie zmieniona na:

main.314159.com.example.app.obb

Lokalizacja pamięci

Gdy Google Play pobiera pliki rozszerzeń na urządzenie, zapisuje je w folderze lokalizację pamięci współdzielonej. Aby zapewnić prawidłowe działanie, nie wolno usuwać, przenosić ani zmieniać nazw plików rozszerzeń. w przypadku, gdy aplikacja musi pobrać aplikację z Google Play. musisz zapisać pliki dokładnie w tej samej lokalizacji.

Metoda getObbDir() zwraca określoną lokalizację plików rozszerzeń w takiej postaci:

<shared-storage>/Android/obb/<package-name>/

W tym katalogu nie mogą znajdować się więcej niż 2 pliki rozszerzeń dla każdej aplikacji. Jeden to główny plik rozszerzenia, a drugi to plik rozszerzenia poprawki (w razie potrzeby). Poprzedni są zastępowane, gdy zaktualizujesz aplikację za pomocą nowych plików rozszerzeń. Od Androida 4.4 (poziom interfejsu API 19) aplikacje mogą odczytywać pliki rozszerzeń OBB bez pamięci zewnętrznej uprawnienia. Jednak niektóre implementacje Androida 6.0 (poziom interfejsu API 23) i nowszych nadal wymagają więc musisz zadeklarować READ_EXTERNAL_STORAGE w manifeście aplikacji i spytaj o nie na stronie środowiska wykonawczego w taki sposób:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

W przypadku Androida w wersji 6 lub nowszej musisz poprosić o uprawnienia do korzystania z pamięci zewnętrznej w czasie działania aplikacji. Niektóre implementacje Androida nie wymagają jednak uprawnień do odczytu plików OBB. ten fragment kodu pokazuje, jak sprawdzić dostęp do odczytu, zanim poprosisz o pamięć zewnętrzną uprawnienie:

Kotlin

val obb = File(obb_filename)
var open_failed = false

try {
    BufferedReader(FileReader(obb)).also { br ->
        ReadObbFile(br)
    }
} catch (e: IOException) {
    open_failed = true
}

if (open_failed) {
    // request READ_EXTERNAL_STORAGE permission before reading OBB file
    ReadObbFileWithPermission()
}

Java

File obb = new File(obb_filename);
 boolean open_failed = false;

 try {
     BufferedReader br = new BufferedReader(new FileReader(obb));
     open_failed = false;
     ReadObbFile(br);
 } catch (IOException e) {
     open_failed = true;
 }

 if (open_failed) {
     // request READ_EXTERNAL_STORAGE permission before reading OBB file
     ReadObbFileWithPermission();
 }

Jeśli musisz rozpakować zawartość plików rozszerzeń, nie usuwaj OBBw kolejnych plikach rozszerzeń i nie zapisuj danych bez pakietu w tym samym katalogu. Zapisz rozpakowane pliki w katalogu określona przez getExternalFilesDir(). Pamiętaj jednak: jeśli to możliwe, najlepiej używać formatu pliku rozszerzającego, który umożliwia odczyt bezpośrednio pliku bez konieczności rozpakowywania danych. Udostępniliśmy na przykład bibliotekę projekt o nazwie biblioteka ZIP rozszerzenia APK, która bezpośrednio odczytuje Twoje dane. z pliku ZIP.

Uwaga: w przeciwieństwie do plików APK wszystkie pliki są zapisywane w pamięci współdzielonej może odczytać użytkownik i inne aplikacje.

Wskazówka: jeśli spakujesz pliki multimedialne do pliku ZIP, możesz użyć tej funkcji odtwarzania plików z elementami sterującymi przesunięciem i długością (np. MediaPlayer.setDataSource() i SoundPool.load()) bez parametru musisz rozpakować plik ZIP. Aby to zadziałało, nie należy wykonywać dodatkowej kompresji na plików multimedialnych podczas tworzenia pakietów ZIP. Na przykład w narzędziu zip użyj opcji -n, by określić sufiksy plików, które nie powinny skompresowane:
zip -n .mp4;.ogg main_expansion media_files

Proces pobierania

W większości przypadków Google Play pobiera i zapisuje pliki rozszerzeń w tym samym czasie pobierze pakiet APK na urządzenie. Jednak w niektórych przypadkach Google Play nie można pobrać plików rozszerzeń lub użytkownik mógł usunąć wcześniej pobrane rozszerzenie . Aby móc poradzić sobie w tych sytuacjach, aplikacja musi mieć możliwość pobierania plików po rozpoczęciu głównej aktywności, przy użyciu adresu URL udostępnionego przez Google Play.

Ogólny proces pobierania wygląda tak:

  1. Użytkownik decyduje się zainstalować Twoją aplikację z Google Play.
  2. Jeśli Google Play może pobrać pliki rozszerzeń (w przypadku większości urządzenia), pobiera je razem z plikiem APK.

    Jeśli Google Play nie może pobrać plików rozszerzeń, Tylko plik APK.

  3. Gdy użytkownik uruchomi aplikację, musi ona sprawdzić, czy pliki rozszerzeń są już zapisane na urządzeniu.
    1. Jeśli tak, aplikacja jest gotowa.
    2. Jeśli nie, aplikacja musi pobrać pliki rozszerzające z Google Play przez HTTP. Twoja aplikacja musi wysłać żądanie do klienta Google Play przy użyciu usługi licencjonowania aplikacji Google Play, która podaje w odpowiedzi nazwę, rozmiar pliku i adres URL każdego pliku rozszerzenia. Dzięki tym informacjom pobierz pliki i zapisz je w odpowiedniej lokalizacji pamięci.

Uwaga: konieczne jest podanie kodu niezbędnego do pobierz je z Google Play, jeśli nie znajdują się one jeszcze w na urządzeniu po uruchomieniu aplikacji. Jak wspominaliśmy w sekcji o pobieraniu plików rozszerzeń, udostępniliśmy bibliotekę, która pozwala znacznie upraszcza ten proces i umożliwia pobieranie plików z usługi przy kod od Ciebie.

Lista kontrolna programowania

Oto podsumowanie czynności, które musisz wykonać, by używać plików rozszerzeń ze aplikacja:

  1. Najpierw sprawdź, czy rozmiar skompresowanego pliku do pobrania Twojej aplikacji musi być większy niż 100 MB. Ilość miejsca jest ważna, dlatego całkowity rozmiar pobieranego pliku powinien być jak najmniejszy. Jeśli Twoja aplikacja wykorzystuje więcej niż 100 MB w celu przesłania wielu wersji zasobów graficznych na różne ekrany gęstości, rozważ opublikowanie wielu plików APK, w których każdy zawiera wyłącznie zasoby wymagane przez ekrany, na które jest kierowany. Aby uzyskać najlepsze wyniki, opublikuj w Google Play, prześlij pakiet Android App Bundle, który obejmuje cały skompilowany kod i zasoby aplikacji, ale opóźnia wygenerowanie i podpisanie plików APK przez Google Graj.
  2. Określ, które zasoby aplikacji należy oddzielić od pliku APK, i umieść je w pakiecie który ma być używany jako główny plik rozszerzający.

    Zazwyczaj przy aktualizacjach do głównego pliku rozszerzenia. Jeśli jednak zasoby przekraczają limit 2 GB dla głównego rozszerzenia, możesz użyć pliku poprawki dla pozostałych zasobów.

  3. Opracuj aplikację w taki sposób, aby wykorzystywała zasoby z plików rozszerzeń w lokalizacja pamięci współdzielonej urządzenia.

    Pamiętaj, że nie możesz usuwać i przenosić plików rozszerzeń ani zmieniać ich nazw.

    Jeśli aplikacja nie wymaga konkretnego formatu, zalecamy tworzenie plików ZIP z plików rozszerzeń, a następnie odczytaj je za pomocą pliku APK Expansion Zip Biblioteka.

  4. Dodaj logikę do głównej aktywności w aplikacji, która sprawdza, czy pliki rozszerzeń są na urządzeniu po uruchomieniu. Jeśli plików nie ma na urządzeniu, użyj usługi licencjonowania aplikacji w Google Play, aby poprosić o adresy URL. a następnie pobierz i zapisz je.

    Aby znacznie zmniejszyć ilość kodu, musisz pisać i zapewnić użytkownikom dobre wrażenia. w trakcie pobierania zalecamy skorzystanie z Programu do pobrania Biblioteka, aby wdrożyć sposób pobierania.

    Jeśli zamiast korzystać z biblioteki tworzysz własną usługę pobierania, pamiętaj, że nie mogą zmieniać nazw plików rozszerzeń i muszą je zapisać w prawidłowym lokalizacji miejsca na dane.

Gdy skończysz tworzenie aplikacji, postępuj zgodnie z instrukcjami z przewodnika Testowanie Twoje pliki rozszerzeń.

Reguły i ograniczenia

Dodanie plików rozszerzeń APK to funkcja dostępna podczas przesyłania aplikacji za pomocą Konsola Play. Gdy przesyłasz aplikację po raz pierwszy lub aktualizujesz korzystających z plików rozszerzeń, musisz pamiętać o tych regułach i ograniczeniach:

  1. Każdy plik rozszerzający nie może być większy niż 2 GB.
  2. Aby pobrać pliki rozszerzeń z Google Play, użytkownik musi mieć pozyskali aplikację z Google Play. Google Play nie będzie podaj adresy URL plików rozszerzeń, jeśli aplikacja została zainstalowana w inny sposób.
  3. Podczas pobierania z aplikacji adres URL powiązany z kontem Google Play określony dla każdego pliku jest unikalny dla każdego pobieranego pliku, a każdy z nich wygasa wkrótce po do Twojej aplikacji.
  4. Gdy zaktualizujesz aplikację o nowy plik APK lub prześlesz wiele plików APK dla tego samego pliku APK aplikacji, możesz wybrać pliki rozszerzeń przesłane do poprzedniego pliku APK. nazwa pliku rozszerzenia nie zmienia się – zachowuje wersję otrzymaną przez plik APK, z którym plik był pierwotnie powiązany.
  5. Jeśli używasz plików rozszerzeń w połączeniu z wieloma pakietami APK, musisz przesyłać oddzielne pliki APK dla różnych urządzeń, dla każdego urządzenia, aby zapewnić unikalny versionCode i zadeklaruj różne filtry dla: każdego pliku APK.
  6. Nie możesz przeprowadzić aktualizacji aplikacji, zmieniając pliki rozszerzeń – musisz przesłać nowy plik APK, aby zaktualizować aplikację. Jeśli zmiany dotyczą tylko dotyczące zasobów w plikach rozszerzeń, możesz zaktualizować pakiet APK, zmieniając ikonę versionCode (oraz (być może również versionName).

  7. Nie zapisuj innych danych na koncie obb/ Katalog. Jeśli musisz rozpakować niektóre dane, zapisz je w lokalizacji podanej w zasadzie getExternalFilesDir().
  8. Nie usuwaj pliku rozszerzenia .obb ani nie zmieniaj jego nazwy (chyba że przeprowadzanie aktualizacji). Jeśli to zrobisz, Google Play (lub sama aplikacja) będzie wielokrotnie działać pobierz plik rozszerzenia.
  9. Przy ręcznym aktualizowaniu pliku rozszerzenia musisz usunąć poprzedni plik rozszerzenia.

Pobieranie plików rozszerzeń

W większości przypadków Google Play pobiera i zapisuje pliki rozszerzeń na urządzeniu w tym samym podczas instalacji lub aktualizacji pliku APK. Dzięki temu pliki rozszerzeń są dostępne, gdy przy pierwszym uruchomieniu aplikacji. Jednak w niektórych przypadkach aplikacja musi pobrać plików rozszerzających, żądając ich z adresu URL podanego w odpowiedzi w usłudze licencjonowania aplikacji w Google Play.

Podstawowa logika pobierania plików rozszerzeń jest następująca:

  1. Po uruchomieniu aplikacji odszukaj pliki rozszerzeń w lokalizacji pamięci współdzielonej (w Android/obb/<package-name>/).
    1. Jeśli są tam pliki rozszerzeń, nie musisz nic więcej robić i możesz korzystać z aplikacji.
    2. Jeśli plików rozszerzeń nie ma na liście:
      1. Prześlij prośbę przy użyciu licencjonowania aplikacji Google Play, aby uzyskać nazw, rozmiarów i adresów URL plików rozszerzeń aplikacji.
      2. Użyj adresów URL dostarczonych przez Google Play, by pobrać pliki rozszerzeń i zapisać plików rozszerzeń. Musisz zapisać pliki w lokalizacji pamięci współdzielonej (Android/obb/<package-name>/) i użyj dokładnie podanej nazwy pliku odpowiedź Google Play.

        Uwaga: adres URL podany w Google Play na potrzeby Przy każdym pobieraniu jest on unikalny, a każdy z nich wygasa wkrótce po udostępnieniu do aplikacji.

Jeśli aplikacja jest bezpłatna (a nie płatna), prawdopodobnie nie korzystasz z usługi licencjonowania aplikacji. Jest to przede wszystkim stworzone z myślą o egzekwowaniu zasad zasadami licencjonowania aplikacji i upewnić się, że użytkownik ma prawo korzystają z aplikacji (osoba słusznie zapłaciła za nią w Google Play). Aby ułatwić plików rozszerzających, usługa licencjonowania została zwiększona, aby zapewnić do aplikacji z adresem URL hostowanych plików rozszerzeń aplikacji w Google Play. Dlatego nawet jeśli Twoja aplikacja jest bezpłatna dla użytkowników, musisz dodać do niej atrybut Biblioteka weryfikacji licencji (LVL) pozwalająca używać plików rozszerzeń APK. Jeśli Twoja aplikacja jest bezpłatna, nie trzeba wymuszać weryfikacji licencji. Wystarczy w celu zwrócenia adresów URL plików rozszerzeń.

Uwaga: bez względu na to, czy aplikacja jest bezpłatna, Google Play zwraca adresy URL plików rozszerzenia tylko wtedy, gdy użytkownik pozyskał Twoją aplikację z Google Play.

Oprócz kodu LVL potrzebujesz zestawu kodu do pobierania plików rozszerzeń przez połączenie HTTP i zapisuje je w odpowiedniej lokalizacji w pamięci współdzielonej urządzenia. Podczas wdrażania tej procedury w aplikacji musisz uwzględnić kilka problemów rozważanie zakupu:

  • Na urządzeniu może być za mało miejsca na pliki rozszerzeń, dlatego sprawdź, przed rozpoczęciem pobierania i ostrzegać użytkownika, jeśli nie ma wystarczającej ilości miejsca.
  • Pliki powinny być pobierane w usłudze w tle, aby uniknąć zablokowania użytkownika interakcji i pozwalają użytkownikowi opuścić aplikację w trakcie pobierania.
  • Podczas przesyłania żądania i pobierania mogą wystąpić różne błędy z gracją.
  • Połączenie sieciowe może ulec zmianie podczas pobierania i należy radzić sobie z nimi. jeśli pobieranie zostanie przerwane, w miarę możliwości wznów je.
  • Podczas pobierania w tle należy przesłać powiadomienie, że: wskazuje postęp pobierania, powiadamia użytkownika o jego zakończeniu i przenosi z powrotem do Twojej aplikacji.

Aby ułatwić Ci pracę, stworzyliśmy Bibliotekę do pobierania, które wysyła do usługi licencjonowania adresy URL plików rozszerzeń, pobiera pliki rozszerzające wykonuje wszystkie zadania wymienione powyżej, a nawet umożliwia wstrzymanie i wznowienie pobierz. Po dodaniu do aplikacji biblioteki narzędzia Downloader i kilku punktów zaczepienia kodu niemal wszystkie jest już zakodowany. W związku z tym, aby zapewnić jak najlepszą jakość użytkowników przy minimalnym wysiłku, zalecamy korzystanie z biblioteki narzędzia do pobierania pobierz pliki rozszerzeń. W poniższych sekcjach znajdziesz informacje o tym, jak zintegrować do aplikacji.

Jeśli wolisz opracować własne rozwiązanie do pobierania plików rozszerzeń za pomocą narzędzia Google URL-i Google Play, musisz przestrzegać dokumentacji dotyczącej licencjonowania, która umożliwia wykonanie żądania licencji, a potem pobieranie nazw plików rozszerzeń. rozmiarów reklam i adresów URL z dodatków do odpowiedzi. Do licencjonowania należy używać klasy APKExpansionPolicy (dostępnej w bibliotece weryfikacji licencji) który przechwytuje nazwy, rozmiary i adresy URL plików rozszerzeń z usługi licencjonowania.

Informacje o bibliotece narzędzia do pobierania

Aby używać w aplikacji plików rozszerzeń APK i zapewnić użytkownikom najlepsze wrażenia, zalecamy użycie biblioteki Downloader, która jest dostępna w Pakiet biblioteki rozszerzeń plików APK w Google Play. Ta biblioteka pobiera pliki rozszerzeń w usługa w tle, wyświetla powiadomienie użytkownika ze stanem pobierania, obsługuje sieć utratę połączenia, wznowienie pobierania, gdy będzie to możliwe i inne.

Aby zaimplementować pobieranie plików rozszerzeń za pomocą biblioteki narzędzia do pobierania, wystarczy, że:

  • Rozszerza specjalną podklasę Service i podklasę BroadcastReceiver, które wymagają tylko kilku kilka wierszy kodu.
  • Dodaj do głównej aktywności funkcję logiczną, która sprawdza, czy pliki rozszerzeń zostało już pobrane, a w przeciwnym razie wywołuje proces pobierania i wyświetla UI postępu.
  • Zaimplementuj interfejs wywołania zwrotnego z kilkoma metodami w głównej aktywności, które otrzymuje aktualizacje na temat postępu pobierania.

W sekcjach poniżej wyjaśniamy, jak skonfigurować aplikację za pomocą biblioteki narzędzia do pobierania.

Przygotowanie do użycia biblioteki narzędzia do pobierania

Aby korzystać z biblioteki narzędzia do pobierania, musisz: pobierz dwa pakiety z SDK Manager i dodaj odpowiednie biblioteki do .

Najpierw otwórz Menedżera pakietów SDK na Androida. (Narzędzia > Menedżer SDK) oraz w sekcji Wygląd Zachowanie > Ustawienia systemu > SDK do Androida, wybierz kartę Narzędzia SDK, aby wybrać i pobrać:

  • Pakiet biblioteki licencjonowania Google Play
  • Pakiet biblioteki rozszerzeń plików APK w Google Play

Utwórz nowy moduł biblioteki na potrzeby biblioteki weryfikacji licencji i narzędzia do pobierania Biblioteka. Dla każdej biblioteki:

  1. Wybierz Plik > Nowe > Nowy moduł.
  2. W oknie Utwórz nowy moduł wybierz Biblioteka Androida, i kliknij Dalej.
  3. Podaj nazwę aplikacji lub biblioteki, na przykład „Biblioteka licencji Google Play”. i „Biblioteka pobierania Google Play”, wybierz Minimalny poziom pakietu SDK, a potem wybierz Zakończ.
  4. Wybierz Plik > Struktura projektu.
  5. Wybierz kartę Właściwości i otwórz Bibliotekę. Repozytorium – wpisz bibliotekę z katalogu <sdk>/extras/google/ (play_licensing/ w przypadku biblioteki weryfikacji licencji lub play_apk_expansion/downloader_library/ w przypadku biblioteki narzędzia do pobierania).
  6. Kliknij OK, aby utworzyć nowy moduł.

Uwaga: biblioteka narzędzia do pobierania zależy od licencji Biblioteka weryfikacji. Pamiętaj, aby dodać licencję z biblioteki Weryfikacja do właściwości projektu w bibliotece narzędzia do pobierania.

Możesz też z poziomu wiersza poleceń zaktualizować projekt, dodając do niego biblioteki:

  1. Przejdź do katalogu <sdk>/tools/.
  2. Wykonaj polecenie android update project, korzystając z opcji --library, aby dodać zarówno LVL i biblioteka narzędzia do pobierania w projekcie. Na przykład:
    android update project --path ~/Android/MyApp \
    --library ~/android_sdk/extras/google/market_licensing \
    --library ~/android_sdk/extras/google/market_apk_expansion/downloader_library
    

Po dodaniu biblioteki weryfikacji licencji i biblioteki narzędzia do pobierania do możesz szybko zintegrować możliwość pobierania plików rozszerzeń Google Play. wybrany format plików rozszerzeń i sposób ich odczytywania, z pamięci współdzielonej to oddzielny sposób, który musisz rozważyć, do potrzeb aplikacji.

Wskazówka: pakiet rozszerzenia APK zawiera próbkę aplikacja który pokazuje, jak korzystać w aplikacji z Biblioteki pobierania. W przykładzie użyto trzeciej biblioteki dostępne w pakiecie rozszerzeń APK o nazwie Biblioteka ZIP rozszerzenia APK. Jeśli planujesz plików ZIP w plikach ZIP, zalecamy również dodanie biblioteki ZIP rozszerzenia APK do do aplikacji. Więcej informacji znajdziesz w sekcji poniżej o używaniu biblioteki ZIP rozszerzenia APK.

Deklarowanie uprawnień użytkownika

Aby pobrać pliki rozszerzające, biblioteka pobierania Aplikacja wymaga kilku uprawnień, które należy zadeklarować w pliku manifestu aplikacji. Ta to:

<manifest ...>
    <!-- Required to access Google Play Licensing -->
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />

    <!-- Required to download files from Google Play -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- Required to keep CPU alive while downloading files
        (NOT to keep screen awake) -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <!-- Required to poll the state of the network connection
        and respond to changes -->
    <uses-permission
        android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!-- Required to check whether Wi-Fi is enabled -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <!-- Required to read and write the expansion files on shared storage -->
    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

Uwaga: domyślnie biblioteka pobierania wymaga interfejsu API poziomu 4, ale biblioteka ZIP rozszerzenia APK wymaga poziomu API 5.

Wdrażanie usługi pobierania

Aby można było pobierać treści w tle, Biblioteka pobierania udostępnia własnego podklasy Service o nazwie DownloaderService, którą należy rozszerzyć. W (oprócz pobierania plików rozszerzeń) DownloaderService:

  • Rejestruje obiekt BroadcastReceiver, który nasłuchuje zmian w połączenie sieciowe urządzenia (CONNECTIVITY_ACTION transmisji) w celu wstrzymania pobierania w razie potrzeby (np. z powodu utraty połączenia). wznów pobieranie, gdy będzie to możliwe (połączenie zostanie nabyte).
  • Planuje alarm o nazwie RTC_WAKEUP, który będzie próbował pobrać jeszcze raz w przypadku gdy usługa zostanie utracona.
  • Tworzy niestandardowy obiekt Notification, który wyświetla postęp pobierania oraz żadnych błędów ani zmian stanu.
  • Zezwala aplikacji na ręczne wstrzymywanie i wznawianie pobierania.
  • Sprawdza, czy pamięć współdzielona jest podłączona i dostępna oraz czy pliki jeszcze nie istnieją. i wystarczającą ilość miejsca, zanim pobierzesz pliki rozszerzeń. Następnie powiadamia użytkownika jeśli któreś z nich nie jest prawdziwe.

Wystarczy, że utworzysz w aplikacji klasę, która rozszerza klasę DownloaderService, i zastąp 3 metody, aby podać szczegółowe informacje o aplikacji:

getPublicKey()
Musi to zwracać ciąg znaków, który jest kluczem publicznym RSA wydawcy zakodowanym w standardzie Base64 na stronie profilu w Konsoli Play (patrz Konfigurowanie licencjonowania).
getSALT()
Musi to zwrócić tablicę losowych bajtów, do których używa licencji Policy utwórz Obfuscator. Sól gwarantuje, że zaciemniony kod SharedPreferences będzie unikalny i niemożliwy do znalezienia.
getAlarmReceiverClassName()
Musi to zwrócić nazwę klasy klasy BroadcastReceiver w do aplikacji, która powinna otrzymać alarm informujący o tym, że ponownie uruchomione (co może się zdarzyć, gdy usługa pobierania nieoczekiwanie się zatrzyma).

Oto pełna implementacja interfejsu DownloaderService:

Kotlin

// You must use the public key belonging to your publisher account
const val BASE64_PUBLIC_KEY = "YourLVLKey"
// You should also modify this salt
val SALT = byteArrayOf(
        1, 42, -12, -1, 54, 98, -100, -12, 43, 2,
        -8, -4, 9, 5, -106, -107, -33, 45, -1, 84
)

class SampleDownloaderService : DownloaderService() {

    override fun getPublicKey(): String = BASE64_PUBLIC_KEY

    override fun getSALT(): ByteArray = SALT

    override fun getAlarmReceiverClassName(): String = SampleAlarmReceiver::class.java.name
}

Java

public class SampleDownloaderService extends DownloaderService {
    // You must use the public key belonging to your publisher account
    public static final String BASE64_PUBLIC_KEY = "YourLVLKey";
    // You should also modify this salt
    public static final byte[] SALT = new byte[] { 1, 42, -12, -1, 54, 98,
            -100, -12, 43, 2, -8, -4, 9, 5, -106, -107, -33, 45, -1, 84
    };

    @Override
    public String getPublicKey() {
        return BASE64_PUBLIC_KEY;
    }

    @Override
    public byte[] getSALT() {
        return SALT;
    }

    @Override
    public String getAlarmReceiverClassName() {
        return SampleAlarmReceiver.class.getName();
    }
}

Uwaga: musisz zaktualizować wartość BASE64_PUBLIC_KEY. jako klucz publiczny należący do Twojego konta wydawcy. Klucz znajdziesz na stronie Konsola w informacjach o profilu. Jest to konieczne nawet podczas testowania pobrane pliki.

Pamiętaj, aby zadeklarować usługę w pliku manifestu:

<app ...>
    <service android:name=".SampleDownloaderService" />
    ...
</app>

Wdrażanie odbiornika alarmu

Aby monitorować postęp pobierania pliku i w razie potrzeby rozpocząć pobieranie od nowa, narzędzie DownloaderService planuje alarm o RTC_WAKEUP, który: dostarcza Intent do BroadcastReceiver w . Aby wywołać interfejs API, musisz zdefiniować BroadcastReceiver z biblioteki narzędzia do pobierania, która sprawdza stan pobierania i uruchamia się ponownie. w razie potrzeby.

Wystarczy, że zastąpisz metodę onReceive(), aby wywołać DownloaderClientMarshaller.startDownloadServiceIfRequired().

Na przykład:

Kotlin

class SampleAlarmReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        try {
            DownloaderClientMarshaller.startDownloadServiceIfRequired(
                    context,
                    intent,
                    SampleDownloaderService::class.java
            )
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
    }
}

Java

public class SampleAlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            DownloaderClientMarshaller.startDownloadServiceIfRequired(context,
                intent, SampleDownloaderService.class);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Zwróć uwagę, że jest to klasa, dla której musisz zwrócić nazwę w metodzie getAlarmReceiverClassName() Twojej usługi (zobacz poprzednią sekcję).

Pamiętaj, aby zadeklarować odbiorcę w pliku manifestu:

<app ...>
    <receiver android:name=".SampleAlarmReceiver" />
    ...
</app>

Rozpoczynanie pobierania

Główna aktywność w aplikacji (uruchomiona przez ikonę programu uruchamiającego) to odpowiada za sprawdzenie, czy pliki rozszerzeń znajdują się już na urządzeniu i inicjowanie, pobieranie.

Aby rozpocząć pobieranie za pomocą biblioteki narzędzia do pobierania, musisz spełnić te wymagania: procedury:

  1. Sprawdź, czy pliki zostały pobrane.

    Biblioteka narzędzia do pobierania zawiera niektóre interfejsy API z klasy Helper do pomoc w tym procesie:

    • getExpansionAPKFileName(Context, c, boolean mainFile, int versionCode)
    • doesFileExist(Context c, String fileName, long fileSize)

    Na przykład przykładowa aplikacja udostępniona w pakiecie rozszerzenia Apk wywołuje tę metodę w metodzie onCreate() aktywności, aby sprawdzić, możesz sprawdzić, czy pliki rozszerzeń znajdują się już na urządzeniu:

    Kotlin

    fun expansionFilesDelivered(): Boolean {
        xAPKS.forEach { xf ->
            Helpers.getExpansionAPKFileName(this, xf.isBase, xf.fileVersion).also { fileName ->
                if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false))
                    return false
            }
        }
        return true
    }
    

    Java

    boolean expansionFilesDelivered() {
        for (XAPKFile xf : xAPKS) {
            String fileName = Helpers.getExpansionAPKFileName(this, xf.isBase,
                xf.fileVersion);
            if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false))
                return false;
        }
        return true;
    }
    

    W tym przypadku każdy obiekt XAPKFile zawiera numer wersji i rozmiar pliku znanego oraz wartość logiczną określającą, czy jest to główny plik rozszerzenia. (Zobacz przykład: klasy SampleDownloaderActivity aplikacji, aby uzyskać więcej informacji).

    Jeśli ta metoda zwraca wartość fałsz, aplikacja musi rozpocząć pobieranie.

  2. Rozpocznij pobieranie od wywołania metody statycznej DownloaderClientMarshaller.startDownloadServiceIfRequired(Context c, PendingIntent notificationClient, Class<?> serviceClass).

    Przyjmuje ona te parametry:

    • context: Context Twojej aplikacji.
    • notificationClient: PendingIntent do rozpoczęcia głównego działania. Jest on używany w Notification, w którym dyrektywa DownloaderService i wyświetla postęp pobierania. Gdy użytkownik wybierze powiadomienie, wywołuje PendingIntent podany przez Ciebie w tym miejscu i powinien otworzyć aktywność pokazuje postęp pobierania (zwykle jest to to samo działanie, które zaczęło pobieranie).
    • serviceClass: obiekt Class dla Twojej implementacji DownloaderService, wymagane do uruchomienia usługi i rozpoczęcia pobierania w razie potrzeby.

    Metoda zwraca liczbę całkowitą, która wskazuje, czy konieczne jest ich pobranie. Możliwe wartości to:

    • NO_DOWNLOAD_REQUIRED: zwracany, jeśli pliki istnieje albo trwa pobieranie.
    • LVL_CHECK_REQUIRED: zwracany, jeśli weryfikacja licencji jest wymagane do uzyskania adresów URL plików rozszerzających.
    • DOWNLOAD_REQUIRED: zwracany, jeśli adresy URL plików rozszerzających są już znane, ale nie zostały pobrane.

    Działanie funkcji LVL_CHECK_REQUIRED i DOWNLOAD_REQUIRED to zasadniczo jest taka sama i nie musisz się o nie martwić. W swojej głównej aktywności, która wywołuje startDownloadServiceIfRequired(), możesz po prostu sprawdzić, czy odpowiedź to NO_DOWNLOAD_REQUIRED. Jeśli odpowiedź to inna niż NO_DOWNLOAD_REQUIRED, Biblioteka narzędzia do pobierania rozpocznie pobieranie, dlatego musisz zaktualizować UI aktywności, wyświetlić postęp pobierania (patrz następny krok). Jeśli odpowiedź to NO_DOWNLOAD_REQUIRED, pliki są dostępne i aplikacja może się uruchomić.

    Na przykład:

    Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        // Check if expansion files are available before going any further
        if (!expansionFilesDelivered()) {
            val pendingIntent =
                    // Build an Intent to start this activity from the Notification
                    Intent(this, MainActivity::class.java).apply {
                        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
                    }.let { notifierIntent ->
                        PendingIntent.getActivity(
                                this,
                                0,
                                notifierIntent,
                                PendingIntent.FLAG_UPDATE_CURRENT
                        )
                    }
    
    
            // Start the download service (if required)
            val startResult: Int = DownloaderClientMarshaller.startDownloadServiceIfRequired(
                    this,
                    pendingIntent,
                    SampleDownloaderService::class.java
            )
            // If download has started, initialize this activity to show
            // download progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // This is where you do set up to display the download
                // progress (next step)
                ...
                return
            } // If the download wasn't necessary, fall through to start the app
        }
        startApp() // Expansion files are available, start the app
    }
    

    Java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // Check if expansion files are available before going any further
        if (!expansionFilesDelivered()) {
            // Build an Intent to start this activity from the Notification
            Intent notifierIntent = new Intent(this, MainActivity.getClass());
            notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                                    Intent.FLAG_ACTIVITY_CLEAR_TOP);
            ...
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                    notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    
            // Start the download service (if required)
            int startResult =
                DownloaderClientMarshaller.startDownloadServiceIfRequired(this,
                            pendingIntent, SampleDownloaderService.class);
            // If download has started, initialize this activity to show
            // download progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // This is where you do set up to display the download
                // progress (next step)
                ...
                return;
            } // If the download wasn't necessary, fall through to start the app
        }
        startApp(); // Expansion files are available, start the app
    }
    
  3. Gdy metoda startDownloadServiceIfRequired() zwraca dowolną inną wartość niż NO_DOWNLOAD_REQUIRED, utwórz instancję IStub przez Wywołuję DownloaderClientMarshaller.CreateStub(IDownloaderClient client, Class<?> downloaderService). IStub tworzy powiązanie między Twoją aktywnością a narzędziem do pobierania tak aby Twoja aktywność odbierała wywołania zwrotne dotyczące postępu pobierania.

    Aby utworzyć instancję IStub, wywołując metodę CreateStub(), musisz ją przekazać wdrożenie interfejsu IDownloaderClient i DownloaderService implementacji. W następnej sekcji o otrzymywaniu postępów pobierania interfejsu IDownloaderClient, który zwykle należy wdrożyć w klasie Activity, aby móc aktualizować interfejs aktywności po zmianie stanu pobierania.

    Zalecamy wywołanie metody CreateStub(), aby utworzyć wystąpienie IStub podczas metody onCreate() aktywności po startDownloadServiceIfRequired() rozpocznie pobieranie.

    Na przykład w poprzednim przykładowym kodzie dla funkcji onCreate() możesz odpowiedzieć na wynik startDownloadServiceIfRequired() w ten sposób:

    Kotlin

            // Start the download service (if required)
            val startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(
                    this@MainActivity,
                    pendingIntent,
                    SampleDownloaderService::class.java
            )
            // If download has started, initialize activity to show progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // Instantiate a member instance of IStub
                downloaderClientStub =
                        DownloaderClientMarshaller.CreateStub(this, SampleDownloaderService::class.java)
                // Inflate layout that shows download progress
                setContentView(R.layout.downloader_ui)
                return
            }
    

    Java

            // Start the download service (if required)
            int startResult =
                DownloaderClientMarshaller.startDownloadServiceIfRequired(this,
                            pendingIntent, SampleDownloaderService.class);
            // If download has started, initialize activity to show progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // Instantiate a member instance of IStub
                downloaderClientStub = DownloaderClientMarshaller.CreateStub(this,
                        SampleDownloaderService.class);
                // Inflate layout that shows download progress
                setContentView(R.layout.downloader_ui);
                return;
            }
    

    Po powrocie metody onCreate() aktywność odbiera połączenie z numerem onResume() – tam należy wtedy wywołaj connect() w IStub, przekazując przy tym wynik Context Twojej aplikacji. I na odwrót, wywołaj disconnect() w wywołaniu zwrotnym onStop() Twojej aktywności.

    Kotlin

    override fun onResume() {
        downloaderClientStub?.connect(this)
        super.onResume()
    }
    
    override fun onStop() {
        downloaderClientStub?.disconnect(this)
        super.onStop()
    }
    

    Java

    @Override
    protected void onResume() {
        if (null != downloaderClientStub) {
            downloaderClientStub.connect(this);
        }
        super.onResume();
    }
    
    @Override
    protected void onStop() {
        if (null != downloaderClientStub) {
            downloaderClientStub.disconnect(this);
        }
        super.onStop();
    }
    

    Wywołanie funkcji connect() w narzędziu IStub wiąże Twoją aktywność z instancją DownloaderService, dzięki czemu otrzymuje wywołania zwrotne dotyczące zmian w pobieranym pliku. za pomocą interfejsu IDownloaderClient.

Odbieram informacje o postępie pobierania

Aby otrzymywać informacje o postępie pobierania i korzystać z narzędzia DownloaderService, musisz wdrożyć interfejs IDownloaderClient biblioteki pobierania. Zwykle działanie rozpoczynające pobieranie powinno implementować ten interfejs, wyświetlać postęp pobierania i wysyłać żądania do usługi.

Wymagane metody interfejsu dla IDownloaderClient:

onServiceConnected(Messenger m)
Po utworzeniu wystąpienia IStub w swojej aktywności otrzymasz połączenie która przekazuje obiekt Messenger połączony z Twoją instancją z DownloaderService. Aby wysyłać żądania do usługi, na przykład wstrzymywać i wznawiać działanie pobierania, należy wywołać interfejs DownloaderServiceMarshaller.CreateProxy(), aby uzyskać dostęp do interfejsu IDownloaderService połączonego z usługą.

Zalecana implementacja wygląda tak:

Kotlin

private var remoteService: IDownloaderService? = null
...

override fun onServiceConnected(m: Messenger) {
    remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply {
        downloaderClientStub?.messenger?.also { messenger ->
            onClientUpdated(messenger)
        }
    }
}

Java

private IDownloaderService remoteService;
...

@Override
public void onServiceConnected(Messenger m) {
    remoteService = DownloaderServiceMarshaller.CreateProxy(m);
    remoteService.onClientUpdated(downloaderClientStub.getMessenger());
}

Po zainicjowaniu obiektu IDownloaderService możesz wysyłać polecenia do usługi pobierania, np. wstrzymania i wznowienia pobierania (requestPauseDownload() i requestContinueDownload()).

onDownloadStateChanged(int newState)
Usługa pobierania wywołuje to polecenie, gdy nastąpi zmiana stanu pobierania, na przykład rozpocznie się lub zakończy pobieranie.

Wartość newState będzie jedną z kilku możliwych wartości określonych w parametrze jedną ze stałych STATE_* klasy IDownloaderClient.

Aby przekazać użytkownikom przydatną wiadomość, możesz poprosić o odpowiedni ciąg znaków. dla każdego stanu, wywołując Helpers.getDownloaderStringResourceIDFromState(). Ten zwraca identyfikator zasobu jednego z ciągów połączonych z narzędziem do pobierania Biblioteka. Na przykład tekst „Pobieranie wstrzymane z powodu roamingu” odpowiada wartości STATE_PAUSED_ROAMING.

onDownloadProgress(DownloadProgressInfo progress)
Usługa pobierania wywołuje to, aby przesłać obiekt DownloadProgressInfo, który zawiera różne informacje o postępie pobierania, w tym szacowany czas do jego zakończenia, aktualna szybkość, ogólny postęp i suma, które pozwalają aktualizować UI postępu pobierania.

Wskazówka: przykłady tych wywołań zwrotnych, które aktualizują pobierane pliki interfejsu postępu, patrz SampleDownloaderActivity w przykładowej aplikacji z Pakiet rozszerzenia pliku APK.

Niektóre publiczne metody korzystania z interfejsu IDownloaderService, które mogą Ci się przydać:

requestPauseDownload()
Wstrzymuje pobieranie.
requestContinueDownload()
Wznawia wstrzymane pobieranie.
setDownloadFlags(int flags)
Określa typy sieci, w których użytkownik może pobierać pliki. bieżąca implementacja obsługuje 1 flagę, FLAGS_DOWNLOAD_OVER_CELLULAR, ale możesz dodać reszta. Domyślnie ta flaga nie jest włączona, więc aby pobrać, użytkownik musi mieć połączenie z Wi-Fi plików rozszerzeń. Możesz określić preferencje użytkownika, aby umożliwić pobieranie przez do sieci komórkowej. W takim przypadku możesz zadzwonić pod numer:

Kotlin

remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply {
    ...
    setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR)
}

Java

remoteService
    .setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR);

Przy użyciu APKExpansionPolicy

Jeśli zamiast korzystać z Google Play, wolisz stworzyć własną usługę pobierania biblioteki narzędzia do pobierania, nadal należy korzystać z biblioteki APKExpansionPolicy dostępnej w bibliotece weryfikacji licencji. Klasa APKExpansionPolicy jest prawie taka sama jak ServerManagedPolicy (dostępna w biblioteki weryfikacji licencji Google Play), ale obejmuje dodatkową obsługę rozszerzania pliku APK. w pliku.

Uwaga: jeśli używasz Biblioteki pobierania zgodnie z opisem w poprzedniej sekcji, Biblioteka wykonuje wszystkie działania z tagiem APKExpansionPolicy, więc nie musisz używać bezpośrednio na tych zajęciach.

Zajęcia te obejmują metody, które pomagają zdobyć niezbędne informacje o dostępnych opcjach pliki rozszerzeń:

  • getExpansionURLCount()
  • getExpansionURL(int index)
  • getExpansionFileName(int index)
  • getExpansionFileSize(int index)

Aby uzyskać więcej informacji o tym, jak korzystać z funkcji APKExpansionPolicy, gdy nie przy użyciu biblioteki narzędzia do pobierania, zapoznaj się z dokumentacją dotyczącą dodawania licencji do aplikacji, który wyjaśnia, jak wdrożyć taką zasadę dotyczącą licencji.

Odczytywanie pliku rozszerzenia

Po zapisaniu plików rozszerzeń APK na urządzeniu możesz sprawdzić sposób odczytywania plików zależy od typu użytego pliku. Jak wspomnieliśmy w omówieniu, funkcje pliki rozszerzające mogą być dowolnymi plikami ale są zmieniane przy użyciu określonego formatu nazwy pliku i są zapisywane <shared-storage>/Android/obb/<package-name>/.

Niezależnie od sposobu odczytywania plików, zawsze najpierw sprawdź, czy zewnętrzny dostępna jest pamięć masowa do odczytu. Możliwe, że użytkownik ma pamięć podręczną przez USB lub wyjął(a) kartę SD.

Uwaga: przy uruchamianiu aplikacji zawsze sprawdzaj, czy pamięć zewnętrzna jest dostępna i można ją odczytać, wywołując getExternalStorageState(). Zwraca jeden z kilku możliwych ciągów reprezentującą stan pamięci zewnętrznej. Aby był czytelny dla app, zwrócona wartość musi wynosić MEDIA_MOUNTED.

Pobieram nazwy plików

Zgodnie z opisem w omówieniu pliki rozszerzeń APK są zapisywane. w określonym formacie nazwy pliku:

[main|patch].<expansion-version>.<package-name>.obb

Aby uzyskać lokalizację i nazwy plików rozszerzeń, skorzystaj z funkcji getExternalStorageDirectory() i getPackageName() do utworzenia ścieżki do plików.

Oto metoda, której możesz użyć w aplikacji, aby uzyskać tablicę zawierającą pełną ścieżkę do obu plików rozszerzeń:

Kotlin

fun getAPKExpansionFiles(ctx: Context, mainVersion: Int, patchVersion: Int): Array<String> {
    val packageName = ctx.packageName
    val ret = mutableListOf<String>()
    if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
        // Build the full path to the app's expansion files
        val root = Environment.getExternalStorageDirectory()
        val expPath = File(root.toString() + EXP_PATH + packageName)

        // Check that expansion file path exists
        if (expPath.exists()) {
            if (mainVersion > 0) {
                val strMainPath = "$expPath${File.separator}main.$mainVersion.$packageName.obb"
                val main = File(strMainPath)
                if (main.isFile) {
                    ret += strMainPath
                }
            }
            if (patchVersion > 0) {
                val strPatchPath = "$expPath${File.separator}patch.$mainVersion.$packageName.obb"
                val main = File(strPatchPath)
                if (main.isFile) {
                    ret += strPatchPath
                }
            }
        }
    }
    return ret.toTypedArray()
}

Java

// The shared path to all app expansion files
private final static String EXP_PATH = "/Android/obb/";

static String[] getAPKExpansionFiles(Context ctx, int mainVersion,
      int patchVersion) {
    String packageName = ctx.getPackageName();
    Vector<String> ret = new Vector<String>();
    if (Environment.getExternalStorageState()
          .equals(Environment.MEDIA_MOUNTED)) {
        // Build the full path to the app's expansion files
        File root = Environment.getExternalStorageDirectory();
        File expPath = new File(root.toString() + EXP_PATH + packageName);

        // Check that expansion file path exists
        if (expPath.exists()) {
            if ( mainVersion > 0 ) {
                String strMainPath = expPath + File.separator + "main." +
                        mainVersion + "." + packageName + ".obb";
                File main = new File(strMainPath);
                if ( main.isFile() ) {
                        ret.add(strMainPath);
                }
            }
            if ( patchVersion > 0 ) {
                String strPatchPath = expPath + File.separator + "patch." +
                        mainVersion + "." + packageName + ".obb";
                File main = new File(strPatchPath);
                if ( main.isFile() ) {
                        ret.add(strPatchPath);
                }
            }
        }
    }
    String[] retArray = new String[ret.size()];
    ret.toArray(retArray);
    return retArray;
}

Możesz wywołać tę metodę, przekazując ją do aplikacji Context oraz wersję żądanego pliku rozszerzenia.

Numer wersji pliku rozszerzenia można określić na wiele sposobów. Prostym sposobem jest zapisz wersję w pliku SharedPreferences po rozpoczęciu pobierania, przez i wysyła zapytanie o nazwę pliku rozszerzenia za pomocą metody getExpansionFileName(int index) klasy APKExpansionPolicy. Kod wersji możesz uzyskać, odczytując plik SharedPreferences, gdy chcesz uzyskać dostęp do rozszerzenia .

Więcej informacji o odczytywaniu z pamięci współdzielonej znajdziesz w sekcji Magazyn danych. dokumentacji.

Używanie biblioteki ZIP rozszerzenia APK

Pakiet rozszerzenia Apk Google Market zawiera bibliotekę o nazwie APK Rozszerzona biblioteka Zip (dostępna w: <sdk>/extras/google/google_market_apk_expansion/zip_file/). To jest opcjonalna biblioteka, która ułatwia odczytywanie rozszerzenia zasięgu, gdy są zapisywane jako pliki ZIP. Korzystanie z tej biblioteki pozwala łatwo odczytywać zasoby z ZIP jako wirtualny system plików.

Biblioteka ZIP rozszerzeń APK zawiera te klasy i interfejsy API:

APKExpansionSupport
Udostępnia kilka metod dostępu do nazw plików rozszerzających i plików ZIP:
getAPKExpansionFiles()
Ta sama metoda jak powyżej, która zwraca pełną ścieżkę pliku do obu rozwinięcia .
getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion)
Zwraca wartość ZipResourceFile reprezentującą sumę zarówno pliku głównego, jak i . Oznacza to, że jeśli podasz zarówno mainVersion, jak i patchVersion, zwraca wartość ZipResourceFile, która zapewnia dostęp do odczytu funkcji wszystkie dane, z danymi z pliku poprawki scalonym nad plikiem głównym.
ZipResourceFile
Reprezentuje plik ZIP w pamięci współdzielonej i wykonuje całą pracę, aby udostępnić na podstawie plików ZIP. Możesz uzyskać instancję za pomocą APKExpansionSupport.getAPKExpansionZipFile() lub ZipResourceFile, przekazując ją w metodzie ścieżki do pliku rozszerzenia. Te zajęcia obejmują wiele przydatnych metod, ale zazwyczaj nie potrzebują dostępu do większości z nich. Kilka ważnych metod to:
getInputStream(String assetPath)
Udostępnia InputStream umożliwiający odczyt pliku w pliku ZIP. assetPath musi być ścieżką do żądanego pliku podaną w odniesieniu do katalogu głównego zawartości pliku ZIP.
getAssetFileDescriptor(String assetPath)
Udostępnia AssetFileDescriptor dla pliku w zakresie ZIP. assetPath musi być ścieżką do żądanego pliku podaną w odniesieniu do katalogu głównego zawartości pliku ZIP. Jest to przydatne w przypadku określonych interfejsów API Androida, które wymagają AssetFileDescriptor, na przykład niektórych interfejsów API MediaPlayer.
APEZProvider
Większość aplikacji nie musi używać tych zajęć. Ta klasa definiuje element ContentProvider, który grupuje dane z plików ZIP za pomocą treści Uri, aby umożliwić dostęp do plików określonym interfejsom API Androida, które oczekuje dostępu Uri do plików multimedialnych. Jest to przydatne, jeśli na przykład chcesz odtwórz film na urządzeniu VideoView.setVideoURI().

Pomijam kompresję ZIP z plikami multimedialnymi

Jeśli przechowujesz pliki multimedialne w plikach rozszerzeń, archiwum ZIP umożliwia używać wywołań funkcji odtwarzania multimediów na Androidzie z elementami sterującymi przesunięciem i długością (np. MediaPlayer.setDataSource(), SoundPool.load()). Aby nie działa, nie należy wykonywać dodatkowej kompresji plików multimedialnych podczas tworzenia pliku ZIP. przesyłek. Na przykład w narzędziu zip należy użyć narzędzia -n możesz określić sufiksy plików, które nie powinny być skompresowane:

zip -n .mp4;.ogg main_expansion media_files

Odczyt z pliku ZIP

Jeśli używasz biblioteki ZIP rozszerzenia APK, odczytanie pliku z pliku ZIP zwykle wymaga :

Kotlin

// Get a ZipResourceFile representing a merger of both the main and patch files
val expansionFile =
        APKExpansionSupport.getAPKExpansionZipFile(appContext, mainVersion, patchVersion)

// Get an input stream for a known file inside the expansion file ZIPs
expansionFile.getInputStream(pathToFileInsideZip).use {
    ...
}

Java

// Get a ZipResourceFile representing a merger of both the main and patch files
ZipResourceFile expansionFile =
    APKExpansionSupport.getAPKExpansionZipFile(appContext,
        mainVersion, patchVersion);

// Get an input stream for a known file inside the expansion file ZIPs
InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);

Powyższy kod umożliwia dostęp do każdego pliku istniejącego w głównym pliku rozszerzenia lub pliku rozszerzenia poprawki, odczytując scaloną mapę wszystkich plików z obu plików. Ty należy podać metodę getAPKExpansionFile(), czyli aplikację android.content.Context, a także numer wersji głównego pliku rozszerzenia i poprawki. .

Jeśli wolisz odczytać dane z konkretnego pliku rozszerzenia, możesz użyć konstruktora ZipResourceFile ze ścieżką do odpowiedniego pliku rozszerzenia:

Kotlin

// Get a ZipResourceFile representing a specific expansion file
val expansionFile = ZipResourceFile(filePathToMyZip)

// Get an input stream for a known file inside the expansion file ZIPs
expansionFile.getInputStream(pathToFileInsideZip).use {
    ...
}

Java

// Get a ZipResourceFile representing a specific expansion file
ZipResourceFile expansionFile = new ZipResourceFile(filePathToMyZip);

// Get an input stream for a known file inside the expansion file ZIPs
InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);

Więcej informacji o korzystaniu z tej biblioteki w przypadku plików rozszerzeń znajdziesz tutaj: klasy SampleDownloaderActivity w przykładowej aplikacji, która zawiera dodatkowy kod do sprawdzić pobrane pliki za pomocą CRC. Pamiętaj, że jeśli wykorzystasz tę próbkę jako podstawę Twojej implementacji wymaga zadeklarowania rozmiaru rozszerzenia w bajtach w tablicy xAPKS.

Testowanie plików rozszerzających

Zanim opublikujesz aplikację, warto przetestować 2 rzeczy: przeczytanie rozszerzeń i pobierania plików.

Testuję odczyty plików

Zanim prześlesz aplikację do Google Play, powinno przetestować możliwość odczytu plików z pamięci współdzielonej przez aplikację. Wszystko, co musisz zrobić to umieszczenie plików w odpowiedniej lokalizacji w pamięci współdzielonej urządzenia i uruchomienie aplikacja:

  1. Na urządzeniu utwórz w pamięci współdzielonej odpowiedni katalog, w którym Google Google Play zapisze Twoje pliki.

    Jeśli na przykład nazwa Twojego pakietu to com.example.android, musisz utworzyć katalogu Android/obb/com.example.android/ w pamięci współdzielonej. (Podłącz urządzenia testowego do komputera, aby podłączyć pamięć współdzieloną i ręcznie utworzyć ).

  2. Dodaj ręcznie do tego katalogu pliki rozszerzeń. Pamiętaj, aby zmienić ich nazwy na muszą być zgodne z formatem nazwy pliku, którego będzie używać Google Play.

    Na przykład bez względu na typ pliku główny plik rozszerzenia aplikacji com.example.android powinien mieć format main.0300110.com.example.android.obb. Kod wersji może mieć dowolną wartość. Pamiętaj:

    • Główny plik rozszerzający zaczyna się zawsze od main, a plik poprawki – od patch
    • Nazwa pakietu zawsze odpowiada nazwie pliku APK, do którego jest dołączony plik. Google Play.
  3. Po zapisaniu plików rozszerzenia na urządzeniu możesz zainstalować i uruchomić aplikację przetestować pliki rozszerzające.

Oto kilka przypomnień o obsłudze plików rozszerzeń:

  • Nie usuwaj plików rozszerzeń .obb ani nie zmieniaj ich nazw (nawet po rozpakowaniu dane w innej lokalizacji). Spowoduje to, że Google Play (lub sama aplikacja) pobrać plik rozszerzający.
  • Nie zapisuj innych danych na koncie obb/ Katalog. Jeśli musisz rozpakować niektóre dane, zapisz je w lokalizacji podanej w zasadzie getExternalFilesDir().

Testuję pobieranie plików

Ponieważ aplikacja po raz pierwszy musi czasami ręcznie pobrać pliki rozszerzeń warto przetestować ten proces, by mieć pewność, że aplikacja prawidłowo pod kątem adresów URL, pobierz pliki i zapisz je na urządzeniu.

Aby sprawdzić wdrożenie procedury pobierania ręcznego w aplikacji: możesz opublikować na ścieżce testu wewnętrznego, by był dostępny tylko autoryzowanych testerów. Jeśli wszystko działa zgodnie z oczekiwaniami, aplikacja powinna pobieranie plików rozszerzeń rozpocznie się natychmiast po rozpoczęciu głównej aktywności.

Uwaga: wcześniej można było testować aplikację przez przesłanie nieopublikowanej wersji roboczej, wersji. Ta funkcja nie jest już dostępna obsługiwane. Zamiast tego musisz ją opublikować na ścieżce testów wewnętrznych, zamkniętych lub otwartych. śledzić. Więcej informacji: Wersje robocze aplikacji nie Dłużej obsługiwane.

Aktualizowanie aplikacji

Jedną z największych zalet korzystania z plików rozszerzeń w Google Play jest możliwość zaktualizować aplikację bez ponownego pobierania wszystkich oryginalnych zasobów. Ponieważ Google Play pozwala dostarczyć dwa pliki rozszerzające z każdym pakietem APK, drugi może służyć jako „poprawka” który zawiera aktualizacje i nowe zasoby. Pozwoli to uniknąć musisz ponownie pobrać główny plik rozszerzenia, bo może to być duży i kosztowny dla użytkowników.

Plik rozszerzenia poprawki jest technicznie taki sam jak główny plik rozszerzenia, ale żaden z nich system Android lub Google Play instaluje poprawki między rozszerzeniem głównym i poprawką. . Kod aplikacji musi samodzielnie instalować wszystkie niezbędne poprawki.

Jeśli używasz plików ZIP jako plików rozszerzających, plik APK Expansion Zip Biblioteka dołączona do pakietu rozszerzeń Apk obejmuje możliwość scalania Twój z głównym plikiem rozszerzenia.

Uwaga: nawet jeśli musisz wprowadzić tylko zmiany w poprawce. pliku rozszerzenia, musisz mimo to zaktualizować pakiet APK, by umożliwić Google Play przeprowadzenie aktualizacji. Jeśli nie potrzebujesz zmian w kodzie aplikacji, zaktualizuj versionCode w pliku manifestu.

O ile nie zmienisz głównego pliku rozszerzenia powiązanego z pakietem APK. użytkownicy, którzy wcześniej zainstalowali Twoją aplikację, pobierz główny plik rozszerzenia. Dotychczasowi użytkownicy otrzymają tylko zaktualizowany plik APK z nową poprawką (z zachowaniem poprzedniego głównego pliku rozszerzenia).

Oto kilka kwestii, o których warto pamiętać przy aktualizowaniu plików rozszerzeń:

  • W przypadku aplikacji mogą być dostępne tylko 2 pliki rozszerzeń. 1 główne rozwinięcie i jednym plikiem rozszerzenia poprawki. Podczas aktualizowania pliku Google Play usuwa w poprzedniej wersji (podobnie jak w przypadku ręcznych aktualizacji).
  • Przy dodawaniu pliku rozszerzenia z poprawką system Android nie instaluje poprawek aplikacji ani głównego pliku rozszerzenia. Musisz zaprojektować aplikację tak, aby obsługiwała dane poprawek. Pakiet rozszerzenia Apk zawiera bibliotekę do używania plików ZIP. jako pliki rozszerzające, które scalają dane z pliku poprawki z głównym plikiem rozszerzenia, możesz łatwo odczytać wszystkie dane w pliku rozszerzenia.
.