Wykonaj czynności opisane w tym przewodniku, aby uzyskać dostęp do pakietów zasobów aplikacji z kodu Java.
Tworzenie aplikacji w językach Kotlin i Java
Aby wbudować Play Asset Delivery w pakiet Android App Bundle 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.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 do niego ten kod. Pamiętaj, aby podać nazwę pakietu zasobów i tylko jeden typ dostarczania: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 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.gradlesettings.gradleapp/asset-pack-name/build.gradleasset-pack-name/src/main/assets/your-asset-directories
Tworzenie pakietu Android App Bundle za pomocą Gradle W wygenerowanym pakiecie aplikacji katalog na poziomie głównym zawiera teraz te elementy:
asset-pack-name/manifest/AndroidManifest.xml: konfiguruje identyfikator i tryb dostarczania pakietu zasobów.asset-pack-name/assets/your-asset-directories: katalog zawierający wszystkie zasoby dostarczane w ramach pakietu zasobów.
Gradle generuje plik manifestu dla każdego pakietu zasobów i tworzy katalog
assets/.(Opcjonalnie) Dołącz bibliotekę Play Asset Delivery, jeśli planujesz używać dostarczania po pobraniu i na żądanie.
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, która umożliwia wysyłanie żądań dotyczących pakietów zasobów, zarządzanie pobieraniem i uzyskiwanie dostępu do zasobów. Najpierw dodaj do projektu bibliotekę Play Asset Delivery.
Interfejs API implementuje się zgodnie z typem dostarczania pakietu zasobów, do którego chcesz uzyskać dostęp. Te kroki są przedstawione na schemacie blokowym poniżej.
Rysunek 1. Diagram przepływu dotyczący uzyskiwania dostępu do pakietów zasobów
Dostarczanie w czasie instalacji
Pakiety zasobów skonfigurowane jako install-time są dostępne od razu po uruchomieniu aplikacji. Aby uzyskać dostęp do zasobów wyświetlanych w tym trybie, użyj interfejsu AssetManager API w języku Java:
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");
Szybka dostawa i dostawa na żądanie
W sekcjach poniżej 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.
Aby określić folder główny pakietu zasobów, użyj metody getPackLocation(). Ta metoda zwraca te 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 zasobów lub zasoby są niedostępne |
Uzyskiwanie informacji o pobieraniu pakietów zasobów
Aplikacje muszą ujawniać rozmiar pliku do pobrania przed pobraniem pakietu zasobów. Użyj metody requestPackStates() lub getPackStates(), aby określić rozmiar pobieranego pakietu i sprawdzić, czy jest on już pobierany.
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, który jest kluczowany według 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, ilość pobranych danych (jeśli jest to wymagane) i ilość danych już przesłanych do aplikacji:
Aby uzyskać stan pakietu zasobów, użyj metody status(), która zwraca stan jako liczbę całkowitą odpowiadającą stałemu polu w klasie AssetPackStatus. Pakiet zasobów, który nie został jeszcze zainstalowany, ma stan AssetPackStatus.NOT_INSTALLED.
Jeśli żądanie się nie powiedzie, użyj metody errorCode(), której zwracana wartość odpowiada stałemu polu w klasie AssetPackErrorCode.
Zainstaluj
Użyj metody requestFetch() lub fetch(), aby pobrać pakiet zasobów po raz pierwszy lub wywołać aktualizację pakietu zasobów:
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ątkowe stany i rozmiary pobierania.
Jeśli pakiet zasobów, o który poproszono za pomocą requestFetch() lub fetch(), jest już pobierany, zwracany jest stan pobierania i nie rozpoczyna się dodatkowe pobieranie.
Monitorowanie stanów pobierania
Aby śledzić postępy instalacji pakietów zasobów, zaimplementuj AssetPackStateUpdatedListener. Aktualizacje stanu są podzielone według pakietów, aby ułatwić śledzenie stanu poszczególnych pakietów zasobów. Możesz zacząć korzystać z dostępnych pakietów zasobów, zanim zostaną pobrane wszystkie pozostałe pliki, o które prosisz.
Kotlin
fun registerListener(listener: AssetPackStateUpdatedListener) fun unregisterListener(listener: AssetPackStateUpdatedListener)
Java
void registerListener(AssetPackStateUpdatedListener listener) void unregisterListener(AssetPackStateUpdatedListener listener)
pobierania dużych plików,
Jeśli rozmiar pobieranych danych przekracza 200 MB, a użytkownik nie jest połączony z Wi-Fi, pobieranie nie rozpocznie się, dopóki użytkownik nie wyrazi wyraźnej zgody na pobieranie przy użyciu komórkowego połączenia transmisji danych. Podobnie, jeśli pobierany plik jest duży, a użytkownik straci połączenie z Wi-Fi, pobieranie zostanie wstrzymane i będzie wymagało wyraźnej zgody na kontynuowanie przy użyciu komórkowego połączenia danych. Wstrzymany pakiet ma stan WAITING_FOR_WIFI. Aby uruchomić proces interfejsu, który poprosi użytkownika o zgodę, użyj metody showConfirmationDialog().
Pamiętaj, że jeśli aplikacja nie wywoła tej metody, pobieranie zostanie wstrzymane i zostanie wznowione automatycznie dopiero wtedy, gdy użytkownik ponownie połączy się z połączeniem Wi-Fi.
Wymagana zgoda użytkownika
Jeśli pakiet ma stan REQUIRES_USER_CONFIRMATION, pobieranie nie rozpocznie się, dopóki użytkownik nie zaakceptuje okna wyświetlanego za pomocą metody showConfirmationDialog().
Ten stan może wystąpić, gdy aplikacja nie jest rozpoznawana przez Google Play, np. jeśli została zainstalowana z innego urządzenia.
Pamiętaj, że wywołanie showConfirmationDialog() w tym przypadku spowoduje zaktualizowanie aplikacji. Po aktualizacji musisz ponownie poprosić o zasoby.
Oto przykładowa implementacja detektora:
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 bieżących pobrań.
AssetPackStates
zawiera postęp pobierania, stan pobierania i kody błędów.
Dostęp do pakietów zasobów
Dostęp do pakietu zasobów możesz uzyskać za pomocą wywołań systemu plików, gdy prośba o pobranie osiągnie stan COMPLETED. Aby uzyskać folder główny pakietu zasobów, użyj metody getPackLocation().
Komponenty są przechowywane w katalogu assets w katalogu głównym pakietu zasobów. Ścieżkę do katalogu assets możesz uzyskać za pomocą metody assetsPath().
Aby uzyskać ścieżkę do konkretnego komponentu, 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ę
Użyj cancel(), aby anulować aktywne żądanie pakietu zasobów. Pamiętaj, że ta prośba jest operacją wykonywaną w miarę możliwości.
Usuwanie pakietu zasobów
Użyj requestRemovePack() lub removePack(), aby zaplanować usunięcie pakietu zasobów.
Pobieranie lokalizacji wielu pakietów zasobów
Użyj metody getPackLocations(), aby zbiorczo sprawdzić stan wielu pakietów zasobów. Zwróci ona mapę pakietów zasobów i ich lokalizacji. Mapa zwracana 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.