Aby uzyskać dostęp do pakietów zasobów aplikacji z kodu Java, wykonaj czynności opisane w tym przewodniku.
Tworzenie aplikacji w Kotlinie i Javie
Aby wdrożyć Play Asset Delivery w pakiecie Android App Bundle projektu, wykonaj te czynności. Nie musisz używać Android Studio.
Zaktualizuj wersję wtyczki Androida do obsługi Gradle w pliku
build.gradleprojektu do wersji4.0.0lub nowszej.W katalogu najwyższego poziomu projektu utwórz katalog pakietu zasobów. Nazwa tego 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 pakietu zasobów utwórz plik
build.gradlei dodaj ten kod. Pamiętaj, aby określić nazwę pakietu zasobów i tylko 1 typ dostawy:Dynamiczny
// 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.gradleaplikacji projektu dodaj nazwę każdego pakietu zasobów w projekcie, jak pokazano poniżej:Dynamiczny
// 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.gradleprojektu uwzględnij wszystkie pakiety zasobów w projekcie, jak pokazano poniżej:Dynamiczny
// 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 pakietu zasobów utwórz ten podkatalog:
src/main/assets.Umieść zasoby w katalogu
src/main/assets. Możesz też utworzyć w nim podkatalogi. Struktura katalogów aplikacji powinna teraz wyglądać tak:build.gradlesettings.gradleapp/asset-pack-name/build.gradleasset-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 wyświetlania.asset-pack-name/assets/your-asset-directories: katalog zawierający wszystkie zasoby dostarczane w ramach pakietu zasobów.
Gradle generuje manifest dla każdego pakietu zasobów i tworzy katalog
assets/.(Opcjonalnie) Jeśli planujesz korzystać z dostawy typu fast-follow i na żądanie, uwzględnij bibliotekę Play Asset Delivery.
Dynamiczny
implementation "com.google.android.play:asset-delivery:2.3.0" // For Kotlin use asset-delivery-ktx implementation "com.google.android.play:asset-delivery-ktx:2.3.0"
Kotlin
implementation("com.google.android.play:asset-delivery:2.3.0") // For Kotlin use core-ktx implementation("com.google.android.play:asset-delivery-ktx:2.3.0")
(Opcjonalnie) Skonfiguruj pakiet aplikacji tak, aby obsługiwał różne formaty kompresji tekstur.
Integracja z interfejsem Play Asset Delivery API
Interfejs Play Asset Delivery Java API
udostępnia klasę
AssetPackManager
do wysyłania próśb o pakiety zasobów, zarządzania pobieraniem i uzyskiwania dostępu do zasobów. Najpierw dodaj bibliotekę Play Asset Delivery do projektu.
Ten interfejs API implementujesz zgodnie z typem dostawy pakietu zasobów, do którego chcesz uzyskać dostęp. Te czynności są przedstawione na tym schemacie blokowym.
Rysunek 1. Schemat blokowy uzyskiwania dostępu do pakietów zasobów
Dostawa typu install-time
Pakiety zasobów skonfigurowane jako install-time są dostępne od razu po uruchomieniu aplikacji. Aby uzyskać dostęp do zasobów
udostępnianych 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");
Dostawa typu fast-follow i na żądanie
W kolejnych sekcjach dowiesz się, jak uzyskać informacje o pakietach zasobów przed ich pobraniem, jak wywołać interfejs API, aby rozpocząć pobieranie, a następnie 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.
Aby określić folder główny pakietu zasobów, użyj metody
getPackLocation(). Ta metoda zwraca te wartości:
| Zwracana wartość | Stan |
|---|---|
Prawidłowy AssetPackLocation obiekt |
Folder główny pakietu zasobów jest gotowy do natychmiastowego dostępu w assetsPath() |
null |
Nieznany pakiet zasobów lub zasoby są niedostępne |
Pobieranie informacji o pakietach zasobów
Przed pobraniem pakietu zasobów aplikacje muszą ujawnić rozmiar 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 zawieszająca, która zwraca obiekt
AssetPackStates
, a getPackStates() to metoda asynchroniczna, która zwraca Task<AssetPackStates>. Metoda
packStates()
obiektu AssetPackStates zwraca Map<String,
AssetPackState>. Ta mapa zawiera stan każdego żądanego pakietu zasobów, z kluczem w postaci jego nazwy:
Kotlin
AssetPackStates#packStates(): Map<String, AssetPackState>
Java
Map<String, AssetPackState> AssetPackStates#packStates()
Ostatnie żądanie jest pokazane poniżej:
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; })
Aby uzyskać stan pakietu zasobów, użyj
status()
metody, która zwraca stan jako liczbę całkowitą odpowiadającą stałemu
polu w
AssetPackStatus
klasie. Pakiet zasobów, który nie jest jeszcze zainstalowany, ma stan AssetPackStatus.NOT_INSTALLED.
Jeśli żądanie się nie powiedzie, użyj metody
errorCode(), której wartość zwracana odpowiada stałemu polu w klasie
AssetPackErrorCode.
Zainstaluj
Aby pobrać pakiet zasobów po raz pierwszy lub wywołać aktualizację pakietu zasobów, użyj metody requestFetch() lub
fetch():
Kotlin
suspend fun AssetPackManager.requestFetch(packs: List<String>): AssetPackStates
Java
Task<AssetPackStates> fetch(List<String> packNames)
Ta metoda zwraca obiekt zawierający listę pakietów oraz ich początkowe stany i rozmiary pobierania.AssetPackStates
Jeśli pakiet zasobów, o który poproszono za pomocą requestFetch() lub fetch(), jest już pobierany, zwracany jest stan pobierania i nie jest rozpoczynane dodatkowe pobieranie.
Monitorowanie stanów pobierania
Aby śledzić postęp instalacji pakietów zasobów, zaimplementuj
AssetPackStateUpdatedListener. Aktualizacje stanu są dzielone na pakiety, aby można było śledzić stan poszczególnych pakietów zasobów. Możesz zacząć korzystać z dostępnych pakietów zasobów, zanim zakończą się wszystkie inne pobierania w ramach żądania.
Kotlin
fun registerListener(listener: AssetPackStateUpdatedListener) fun unregisterListener(listener: AssetPackStateUpdatedListener)
Java
void registerListener(AssetPackStateUpdatedListener listener) void unregisterListener(AssetPackStateUpdatedListener listener)
Pobieranie dużych plików
Jeśli pobierany plik ma więcej niż 200 MB i użytkownik nie korzysta z Wi-Fi, pobieranie nie rozpocznie się, dopóki użytkownik nie wyrazi wyraźnie zgody na kontynuowanie pobierania za pomocą połączenia komórkowego. Podobnie jeśli pobierany plik jest duży, a użytkownik utraci połączenie z Wi-Fi, pobieranie zostanie wstrzymane i wymagana będzie wyraźna zgoda na kontynuowanie pobierania za pomocą połączenia komórkowego. Wstrzymany pakiet ma stan WAITING_FOR_WIFI. Aby wywołać interfejs użytkownika z prośbą o zgodę, użyj
metody showConfirmationDialog().
Jeśli aplikacja nie wywoła tej metody, pobieranie zostanie wstrzymane i wznowione automatycznie dopiero wtedy, gdy użytkownik ponownie połączy się z Wi-Fi.
Wymagane potwierdzenie użytkownika
Jeśli pakiet ma stan REQUIRES_USER_CONFIRMATION, pobieranie nie będzie
kontynuowane, dopóki użytkownik nie zaakceptuje okna dialogowego wyświetlanego za pomocą
showConfirmationDialog().
Ten stan może wystąpić, gdy aplikacja nie jest rozpoznawana przez Sklep Play, np. jeśli została zainstalowana z innego urządzenia.
Wywołanie
showConfirmationDialog()
w tym przypadku spowoduje zaktualizowanie aplikacji. Po aktualizacji musisz ponownie poprosić o zasoby.
Oto przykładowa implementacja słuchacza:
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 uzyskać stan bieżących pobrań.
AssetPackStates
zawiera postęp pobierania, stan pobierania i kody błędów.
Uzyskiwanie dostępu do pakietów zasobów
Po osiągnięciu przez żądanie pobierania
stanu
COMPLETED
możesz uzyskać dostęp do pakietu zasobów za pomocą wywołań systemu plików. Aby uzyskać folder główny pakietu zasobów, użyj metody
getPackLocation().
Zasoby są przechowywane w katalogu assets w katalogu głównym pakietu zasobów. Ścieżkę do katalogu assets możesz uzyskać za pomocą
metody pomocniczej
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
Oto kilka dodatkowych metod interfejsu API, których możesz użyć w aplikacji.
Anuluj prośbę
Aby anulować aktywne żądanie pakietu zasobów, użyj
cancel(). Pamiętaj, że to żądanie jest operacją, która ma na celu podjęcie wszelkich możliwych działań.
Usuwanie pakietu zasobów
Aby zaplanować usunięcie pakietu zasobów, użyj
requestRemovePack()
lub
removePack().
Pobieranie lokalizacji wielu pakietów zasobów
Aby zbiorczo sprawdzić stan wielu pakietów zasobów, użyj
getPackLocations()
, która zwraca mapę
pakietów zasobów i ich lokalizacji. Mapa zwracana przez getPackLocations() zawiera wpis dla każdego pakietu, który jest obecnie pobrany i aktualny.
Następny krok
Testowanie Play Asset Delivery lokalnie i w Google Play.