Wykonaj czynności opisane w tym przewodniku, aby uzyskać dostęp do pakietów zasobów aplikacji za pomocą kodu w Javie.
Kompilacja dla Kotlin i Javy
Aby dodać Play Asset Delivery do pakietu Android App Bundle swojego projektu, wykonaj te czynności. Nie musisz używać Android Studio, aby wykonać te czynności.
Zaktualizuj wersję wtyczki Androida do obsługi Gradle w pliku
build.gradle
projektu do wersji4.0.0
lub nowszej.W katalogu najwyższego poziomu projektu utwórz katalog pakietu zasobów. Ta nazwa katalogu jest używana jako nazwa pakietu zasobów. Nazwy pakietów zasobów muszą zaczynać się od litery i mogą zawierać tylko litery, cyfry i podkreślenia.
W katalogu pakietów zasobów utwórz plik
build.gradle
i dodaj ten kod. Pamiętaj, aby podać nazwę pakietu zasobów i tylko jeden typ dostawy:Odlotowe
// In the asset pack's build.gradle file: plugins { id 'com.android.asset-pack' } assetPack { packName = "asset-pack-name" // Directory name for the asset pack dynamicDelivery { deliveryType = "[ install-time | fast-follow | on-demand ]" } }
Kotlin
// In the asset pack's build.gradle.kts file: plugins { id("com.android.asset-pack") } assetPack { packName.set("asset-pack-name") // Directory name for the asset pack dynamicDelivery { deliveryType.set("[ install-time | fast-follow | on-demand ]") } }
W pliku
build.gradle
aplikacji projektu dodaj nazwę każdego pakietu zasobów w projekcie, jak pokazano poniżej:Odlotowe
// In the app build.gradle file: android { ... assetPacks = [":asset-pack-name", ":asset-pack2-name"] }
Kotlin
// In the app build.gradle.kts file: android { ... assetPacks += listOf(":asset-pack-name", ":asset-pack2-name") }
W pliku
settings.gradle
projektu umieść wszystkie pakiety zasobów w następujący sposób:Odlotowe
// In the settings.gradle file: include ':app' include ':asset-pack-name' include ':asset-pack2-name'
Kotlin
// In the settings.gradle.kts file: include(":app") include(":asset-pack-name") include(":asset-pack2-name")
W katalogu pakietów zasobów utwórz ten podkatalog:
src/main/assets
.Umieść zasoby w katalogu
src/main/assets
. Możesz tu też tworzyć podkatalogi. Struktura katalogów aplikacji powinna teraz wyglądać tak:build.gradle
settings.gradle
app/
asset-pack-name/build.gradle
asset-pack-name/src/main/assets/your-asset-directories
Utwórz pakiet Android App Bundle za pomocą Gradle W wygenerowanym pakiecie aplikacji katalog główny zawiera teraz te elementy:
asset-pack-name/manifest/AndroidManifest.xml
: konfiguruje identyfikator pakietu zasobów i tryb dostawyasset-pack-name/assets/your-asset-directories
: katalog, który zawiera wszystkie zasoby dostarczone w ramach pakietu zasobów.
Gradle generuje plik manifestu dla każdego pakietu zasobów i wyświetla za Ciebie katalog
assets/
.(Opcjonalnie) Dołącz Play Asset Delivery Library, jeśli planujesz korzystać z szybkiej dostawy i na żądanie.
Odlotowe
implementation "com.google.android.play:asset-delivery:2.2.2" // For Kotlin use asset-delivery-ktx implementation "com.google.android.play:asset-delivery-ktx:2.2.2"
Kotlin
implementation("com.google.android.play:asset-delivery:2.2.2") // For Kotlin use core-ktx implementation("com.google.android.play:asset-delivery-ktx:2.2.2")
(Opcjonalnie) Skonfiguruj pakiet aplikacji pod kątem obsługi różnych formatów kompresji tekstur.
Integracja z interfejsem Play Asset Delivery API
Play Asset Delivery Java API udostępnia klasę AssetPackManager
do wysyłania żądań pakietów zasobów, zarządzania pobieraniem i uzyskiwania dostępu do zasobów. Pamiętaj, aby najpierw dodać do projektu bibliotekę Play Asset Delivery.
Implementujesz ten interfejs API zgodnie z typem dostawy pakietu zasobów, do którego chcesz uzyskać dostęp. Te kroki zostały pokazane na poniższym schemacie blokowym.
Dostawa w czasie instalacji
Pakiety zasobów skonfigurowane jako install-time
są dostępne od razu przy uruchomieniu aplikacji. Aby uzyskać dostęp do zasobów wyświetlanych w tym trybie, użyj interfejsu Java AssetManager API:
Kotlin
import android.content.res.AssetManager ... val context: Context = createPackageContext("com.example.app", 0) val assetManager: AssetManager = context.assets val stream: InputStream = assetManager.open("asset-name")
Java
import android.content.res.AssetManager; ... Context context = createPackageContext("com.example.app", 0); AssetManager assetManager = context.getAssets(); InputStream is = assetManager.open("asset-name");
Szybkie śledzenie i dostawy na żądanie
Z tych sekcji dowiesz się, jak uzyskać informacje o pakietach zasobów przed ich pobraniem, jak wywołać interfejs API, aby rozpocząć pobieranie, i jak uzyskać dostęp do pobranych pakietów. Te sekcje dotyczą pakietów zasobów fast-follow
i on-demand
.
Sprawdź stan
Każdy pakiet zasobów jest przechowywany w osobnym folderze w pamięci wewnętrznej aplikacji.
Użyj metody getPackLocation()
, aby określić folder główny pakietu zasobów. Ta metoda zwraca następujące wartości:
Zwracana wartość | Stan |
---|---|
Prawidłowy obiekt AssetPackLocation |
Folder główny pakietu zasobów jest gotowy do natychmiastowego dostępu pod adresem assetsPath() |
null |
Nieznany pakiet lub zasoby są niedostępne |
Pobieranie informacji o pakietach zasobów
Przed pobraniem pakietu zasobów aplikacje muszą informować o rozmiarze pobieranego pliku. Aby określić rozmiar pobieranego pliku i sprawdzić, czy pakiet jest już pobierany, użyj metody requestPackStates()
lub getPackStates()
.
Kotlin
suspend fun requestPackStates(packNames: List<String>): AssetPackStates
Java
Task<AssetPackStates> getPackStates(List<String> packNames)
requestPackStates()
to funkcja zawieszenia zwracająca obiekt AssetPackStates
, natomiast getPackStates()
jest metodą asynchroniczną, która zwraca Task<AssetPackStates>
. Metoda packStates()
obiektu AssetPackStates
zwraca Map<String,
AssetPackState>
. Ta mapa zawiera stan każdego żądanego pakietu zasobów uporządkowany według jego nazwy:
Kotlin
AssetPackStates#packStates(): Map<String, AssetPackState>
Java
Map<String, AssetPackState> AssetPackStates#packStates()
Ostateczne żądanie wygląda tak:
Kotlin
const val assetPackName = "assetPackName" coroutineScope.launch { try { val assetPackStates: AssetPackStates = manager.requestPackStates(listOf(assetPackName)) val assetPackState: AssetPackState = assetPackStates.packStates()[assetPackName] } catch (e: RuntimeExecutionException) { Log.d("MainActivity", e.message) } }
Java
final String assetPackName = "myasset"; assetPackManager .getPackStates(Collections.singletonList(assetPackName)) .addOnCompleteListener(new OnCompleteListener<AssetPackStates>() { @Override public void onComplete(Task<AssetPackStates> task) { AssetPackStates assetPackStates; try { assetPackStates = task.getResult(); AssetPackState assetPackState = assetPackStates.packStates().get(assetPackName); } catch (RuntimeExecutionException e) { Log.d("MainActivity", e.getMessage()); return; })
Te metody AssetPackState
podają rozmiar pakietu zasobów, kwotę pobraną do tej pory (w razie potrzeby) oraz kwotę już przesłaną do aplikacji:
Aby uzyskać stan pakietu zasobów, użyj metody status()
, która zwraca stan jako liczbę całkowitą odpowiadającą polu stałemu w klasie AssetPackStatus
. Pakiet zasobów, który nie został jeszcze zainstalowany, ma stan AssetPackStatus.NOT_INSTALLED
.
Jeśli żądanie nie zostanie zrealizowane, użyj metody errorCode()
, której wartość zwracana odpowiada polu stałemu w klasie AssetPackErrorCode
.
Zainstaluj
Użyj metody requestFetch()
lub fetch()
, aby po raz pierwszy pobrać pakiet zasobów, albo wywołaj jego aktualizację w celu zakończenia:
Kotlin
suspend fun AssetPackManager.requestFetch(packs: List<String>): AssetPackStates
Java
Task<AssetPackStates> fetch(List<String> packNames)
Ta metoda zwraca obiekt AssetPackStates
zawierający listę pakietów oraz ich początkowych stanów i rozmiarów pobierania.
Jeśli żądanie pakietu zasobów za pośrednictwem requestFetch()
lub fetch()
jest już pobierane, zwracany jest stan pobierania i nie rozpoczyna się kolejne pobieranie.
Monitorowanie stanu pobierania
Aby śledzić postęp instalacji pakietów zasobów, musisz wdrożyć AssetPackStateUpdatedListener
. Aktualizacje stanu są podzielone na pakiety, aby ułatwić śledzenie stanu poszczególnych pakietów zasobów. Możesz zacząć korzystać z dostępnych pakietów zasobów,
zanim wszystkie inne pliki do pobrania związane z Twoim żądaniem zostaną ukończone.
Kotlin
fun registerListener(listener: AssetPackStateUpdatedListener) fun unregisterListener(listener: AssetPackStateUpdatedListener)
Java
void registerListener(AssetPackStateUpdatedListener listener) void unregisterListener(AssetPackStateUpdatedListener listener)
Duże pliki do pobrania
Jeśli rozmiar pobierania przekracza 200 MB, a użytkownik nie korzysta z Wi-Fi, pobieranie nie rozpocznie się, dopóki użytkownik wyraźnie nie wyrazi zgody na pobieranie przy użyciu komórkowego połączenia transmisji danych. Podobnie jeśli pobierane pliki są duże, a użytkownik utraci dostęp do Wi-Fi, pobieranie zostanie wstrzymane, a dalsze korzystanie z mobilnej transmisji danych będzie wymagało uzyskania wyraźnej zgody użytkownika. Wstrzymano pakiet ma stan WAITING_FOR_WIFI
. Aby aktywować w interfejsie procedurę z prośbą o zgodę użytkownika, użyj metody showConfirmationDialog()
.
Pamiętaj, że jeśli aplikacja nie wywoła tej metody, pobieranie zostanie wstrzymane i zostanie automatycznie wznowione, gdy użytkownik znów połączy się z siecią Wi-Fi.
Wymagane potwierdzenie użytkownika
Jeśli pakiet ma stan REQUIRES_USER_CONFIRMATION
, pobieranie nie rozpocznie się, dopóki użytkownik nie zaakceptuje okna wyświetlanego z ikoną showConfirmationDialog()
.
Ten stan może wystąpić, gdy aplikacja nie zostanie rozpoznana przez Google Play – na przykład jeśli została zainstalowana z innego urządzenia.
Pamiętaj, że w tym przypadku wywołanie metody showConfirmationDialog()
spowoduje aktualizację aplikacji. Po aktualizacji musisz ponownie poprosić o zasoby.
Oto przykładowa implementacja odbiornika:
Kotlin
private val activityResultLauncher = registerForActivityResult( ActivityResultContracts.StartIntentSenderForResult() ) { result -> if (result.resultCode == RESULT_OK) { Log.d(TAG, "Confirmation dialog has been accepted.") } else if (result.resultCode == RESULT_CANCELED) { Log.d(TAG, "Confirmation dialog has been denied by the user.") } } assetPackManager.registerListener { assetPackState -> when(assetPackState.status()) { AssetPackStatus.PENDING -> { Log.i(TAG, "Pending") } AssetPackStatus.DOWNLOADING -> { val downloaded = assetPackState.bytesDownloaded() val totalSize = assetPackState.totalBytesToDownload() val percent = 100.0 * downloaded / totalSize Log.i(TAG, "PercentDone=" + String.format("%.2f", percent)) } AssetPackStatus.TRANSFERRING -> { // 100% downloaded and assets are being transferred. // Notify user to wait until transfer is complete. } AssetPackStatus.COMPLETED -> { // Asset pack is ready to use. Start the game. } AssetPackStatus.FAILED -> { // Request failed. Notify user. Log.e(TAG, assetPackState.errorCode()) } AssetPackStatus.CANCELED -> { // Request canceled. Notify user. } AssetPackStatus.WAITING_FOR_WIFI, AssetPackStatus.REQUIRES_USER_CONFIRMATION -> { if (!confirmationDialogShown) { assetPackManager.showConfirmationDialog(activityResultLauncher); confirmationDialogShown = true } } AssetPackStatus.NOT_INSTALLED -> { // Asset pack is not downloaded yet. } AssetPackStatus.UNKNOWN -> { Log.wtf(TAG, "Asset pack status unknown") } } }
Java
assetPackStateUpdateListener = new AssetPackStateUpdateListener() { private final ActivityResultLauncher<IntentSenderRequest> activityResultLauncher = registerForActivityResult( new ActivityResultContracts.StartIntentSenderForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { if (result.getResultCode() == RESULT_OK) { Log.d(TAG, "Confirmation dialog has been accepted."); } else if (result.getResultCode() == RESULT_CANCELED) { Log.d(TAG, "Confirmation dialog has been denied by the user."); } } }); @Override public void onStateUpdate(AssetPackState assetPackState) { switch (assetPackState.status()) { case AssetPackStatus.PENDING: Log.i(TAG, "Pending"); break; case AssetPackStatus.DOWNLOADING: long downloaded = assetPackState.bytesDownloaded(); long totalSize = assetPackState.totalBytesToDownload(); double percent = 100.0 * downloaded / totalSize; Log.i(TAG, "PercentDone=" + String.format("%.2f", percent)); break; case AssetPackStatus.TRANSFERRING: // 100% downloaded and assets are being transferred. // Notify user to wait until transfer is complete. break; case AssetPackStatus.COMPLETED: // Asset pack is ready to use. Start the game. break; case AssetPackStatus.FAILED: // Request failed. Notify user. Log.e(TAG, assetPackState.errorCode()); break; case AssetPackStatus.CANCELED: // Request canceled. Notify user. break; case AssetPackStatus.WAITING_FOR_WIFI: case AssetPackStatus.REQUIRES_USER_CONFIRMATION: if (!confirmationDialogShown) { assetPackManager.showConfirmationDialog(activityResultLauncher); confirmationDialogShown = true; } break; case AssetPackStatus.NOT_INSTALLED: // Asset pack is not downloaded yet. break; case AssetPackStatus.UNKNOWN: Log.wtf(TAG, "Asset pack status unknown") break; } } }
Możesz też użyć metody getPackStates()
, aby sprawdzić stan aktualnie pobranych plików.
AssetPackStates
zawiera informacje o postępie pobierania, stan pobierania i wszystkie kody błędów błędów.
Dostęp do pakietów zasobów
Możesz uzyskać dostęp do pakietu zasobów za pomocą wywołań systemu plików, gdy żądanie pobierania osiągnie stan COMPLETED
. Użyj metody getPackLocation()
, aby uzyskać folder główny pakietu zasobów.
Zasoby są przechowywane w katalogu assets
w katalogu głównym pakietu zasobów. Ścieżkę do katalogu assets
możesz uzyskać, używając metody wygodnej assetsPath()
.
Aby uzyskać ścieżkę do konkretnego zasobu, użyj tej metody:
Kotlin
private fun getAbsoluteAssetPath(assetPack: String, relativeAssetPath: String): String? { val assetPackPath: AssetPackLocation = assetPackManager.getPackLocation(assetPack) // asset pack is not ready ?: return null val assetsFolderPath = assetPackPath.assetsPath() // equivalent to: FilenameUtils.concat(assetPackPath.path(), "assets") return FilenameUtils.concat(assetsFolderPath, relativeAssetPath) }
Java
private String getAbsoluteAssetPath(String assetPack, String relativeAssetPath) { AssetPackLocation assetPackPath = assetPackManager.getPackLocation(assetPack); if (assetPackPath == null) { // asset pack is not ready return null; } String assetsFolderPath = assetPackPath.assetsPath(); // equivalent to: FilenameUtils.concat(assetPackPath.path(), "assets"); String assetPath = FilenameUtils.concat(assetsFolderPath, relativeAssetPath); return assetPath; }
Inne metody interfejsu Play Asset Delivery API
Poniżej znajdziesz dodatkowe metody interfejsu API, których możesz użyć w swojej aplikacji.
Anuluj prośbę
Użyj przycisku cancel()
, aby anulować żądanie aktywnego pakietu zasobów. Pamiętaj, że ta prośba działa z możliwie największą dokładnością.
Usuń pakiet zasobów
Użyj
requestRemovePack()
lub
removePack()
,
aby zaplanować usunięcie pakietu zasobów.
Pobieranie lokalizacji wielu pakietów zasobów
Użyj narzędzia getPackLocations()
, aby przesłać zbiorczo zapytanie o stan wielu pakietów zasobów, które wyświetli mapę pakietów zasobów i ich lokalizacji. Mapa zwrócona przez funkcję getPackLocations()
zawiera wpis dotyczący każdego pakietu, który jest obecnie pobrany i aktualny.
Następny krok
Przetestuj Play Asset Delivery lokalnie i w Google Play.