Zintegruj przesyłanie zasobów (kotlin i Java)

Aby uzyskać dostęp do pakietów zasobów aplikacji z poziomu kodu w Javie, wykonaj czynności opisane w tym przewodniku.

Tworzenie aplikacji w językach Kotlin i Java

Aby włączyć dostarczanie zasobów Play do pakietu aplikacji na Androida w projekcie, wykonaj te czynności. Aby wykonać te czynności, nie musisz używać Androida Studio.

  1. Zaktualizuj wersję wtyczki Androida do obsługi Gradle w pliku build.gradle projektu do wersji 4.0.0 lub nowszej.

  2. 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.

  3. W katalogu pakietu zasobów utwórz plik build.gradle i dodaj ten kod: Podaj nazwę pakietu komponentów i tylko jeden typ dostawy:

    Groovy

    // 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 ]")
      }
    }
  4. W pliku aplikacji projektu build.gradle dodaj nazwę każdego pakietu zasobów w projekcie, jak pokazano poniżej:

    Groovy

    // 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")
    }
  5. W pliku settings.gradle projektu umieść wszystkie pakiety komponentów w projekcie, jak pokazano poniżej:

    Groovy

    // 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")
  6. W katalogu pakietu komponentów utwórz ten podkatalog:src/main/assets

  7. 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
  8. Utwórz pakiet Android App Bundle za pomocą Gradle W wygenerowanym pakiecie aplikacji katalog najwyższego poziomu zawiera teraz te elementy:

    • asset-pack-name/manifest/AndroidManifest.xml: Konfiguruje identyfikator pakietu zasobów i tryb dostarczania.
    • asset-pack-name/assets/your-asset-directories: Katalog zawierający wszystkie komponenty dostarczone w ramach pakietu komponentów

    Gradle generuje plik manifestu dla każdego pakietu zasobów i tworzy dla Ciebie katalog assets/.

  9. (Opcjonalnie) Jeśli planujesz korzystać z szybkiego wdrażania i dostarczania na żądanie, dodaj Play Asset Delivery Library.

    Groovy

    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")

  10. (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 zawiera klasę AssetPackManager do wysyłania żądań dotyczących pakietów zasobów, zarządzania pobieraniem i uzyskiwania dostępu do zasobów. Najpierw dodaj do projektu bibliotekę Play Asset Delivery.

Ten interfejs API wdrażasz zgodnie z typem dostawy pakietu zasobów, do którego chcesz uzyskać dostęp. Te kroki przedstawia poniższy schemat blokowy.

Schemat blokowy pakietu zasobów w języku programowania Java

Rysunek 1. Schemat blokowy dostępu do pakietów komponentów

Przesyłanie podczas instalacji

Pakiety zasobów skonfigurowane jako install-time są dostępne natychmiast po uruchomieniu aplikacji. Aby uzyskać dostęp do komponentó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");

Szybkie i na żądanie przesyłanie

W sekcjach poniżej znajdziesz informacje o tym, 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-followon-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 te wartości:

Zwracana wartość Stan
prawidłowy obiekt AssetPackLocation, Folder główny pakietu komponentów jest gotowy do natychmiastowego dostępu pod adresem assetsPath()
null Nieznany pakiet komponentów lub komponenty są niedostępne

Pobieranie informacji o pobranych pakietach zasobów

Aplikacje muszą podać rozmiar pobieranego pakietu zasobów przed jego pobraniem. 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, z którego kluczem jest jego nazwa:

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 metodyAssetPackStatepodają rozmiar pakietu zasobów, pobraną do tej pory ilość (jeśli jest wymagana) i ilość już przesłaną do aplikacji:

Aby uzyskać stan pakietu komponentó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 jest jeszcze zainstalowany, ma stanAssetPackStatus.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 AssetPackStates zawierający listę pakietów oraz ich początkowe stany pobierania i rozmiary. Jeśli pakiet zasobów zażądany za pomocą funkcji requestFetch() lub fetch() jest już pobierany, zwracany jest stan pobierania i nie rozpoczyna się żadne dodatkowe pobieranie.

Monitorowanie stanów pobierania

Aby śledzić postęp instalacji pakietów komponentów, zaimplementuj AssetPackStateUpdatedListener. Aktualizacje stanu są podzielone na pakiety, aby można było śledzić stan poszczególnych pakietów zasobów. Możesz zacząć korzystać z dostępnych pakietów komponentów, zanim zostaną ukończone wszystkie inne pobierania związane z Twoją prośbą.

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 pobieranie przekracza 200 MB, a użytkownik nie korzysta 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 pobieranie jest duże, a użytkownik utraci połączenie Wi-Fi, pobieranie zostanie wstrzymane i do kontynuowania pobierania przy użyciu mobilnej transmisji danych wymagana będzie wyraźna zgoda. Wstrzymany pakiet ma stanWAITING_FOR_WIFI. Aby wywołać interfejs, który poprosi użytkownika o wyrażenie zgody, 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 siecią Wi-Fi.

Wymagane potwierdzenie użytkownika

Jeśli pakiet ma stan REQUIRES_USER_CONFIRMATION, pobieranie nie zostanie rozpoczęte, dopóki użytkownik nie zaakceptuje okna dialogowego wyświetlanego z ikoną 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 komponenty.

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 bieżących pobrań. AssetPackStates zawiera postęp pobierania, stan pobierania i kody błędów.

Dostęp do pakietów zasobów

Po osiągnięciu przez żądanie pobierania stanu COMPLETED możesz uzyskać dostęp do pakietu komponentów za pomocą wywołań systemu plików. Aby uzyskać folder główny pakietu komponentów, użyj metody getPackLocation().

Komponenty są przechowywane w katalogu assets w katalogu głównym pakietu komponentów. Ścieżkę do katalogu assets możesz uzyskać za pomocą metody pomocniczej assetsPath(). Aby uzyskać ścieżkę do konkretnego komponentu:

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 dodatkowe metody interfejsu API, których możesz używać w aplikacji.

Anuluj prośbę

Użyj cancel() aby anulować aktywną prośbę o pakiet komponentów. Pamiętaj, że ta prośba jest operacją wykonywaną w miarę możliwości.

Usuwanie pakietu komponentów

Użyj requestRemovePack() lub removePack() aby zaplanować usunięcie pakietu zasobów.

Pobieranie lokalizacji wielu pakietów komponentów

Użyj getPackLocations() do zbiorczego sprawdzania stanu wielu pakietów zasobów, co zwraca mapę pakietów zasobów i ich lokalizacji. Mapa zwrócona przez getPackLocations() zawiera wpis dla każdego pakietu, który jest obecnie pobrany i aktualny.

Następny krok

Testuj Play Asset Delivery lokalnie i w Google Play.