Asset Delivery einbinden (Kotlin und Java)

Folgen Sie den Schritten in dieser Anleitung, um über Ihren Java-Code auf die Asset-Packs Ihrer App zuzugreifen.

Build für Kotlin und Java

Führe die folgenden Schritte aus, um Play Asset Delivery in das Android App Bundle deines Projekts zu integrieren. Sie müssen für diese Schritte nicht Android Studio verwenden.

  1. Aktualisieren Sie die Version des Android-Gradle-Plug-ins in der Datei build.gradle Ihres Projekts auf 4.0.0 oder höher.

  2. Erstellen Sie im obersten Verzeichnis Ihres Projekts ein Verzeichnis für das Asset-Pack. Dieser Verzeichnisname wird als Name des Asset-Pakets verwendet. Namen von Asset-Paketen müssen mit einem Buchstaben beginnen und dürfen nur Buchstaben, Ziffern und Unterstriche enthalten.

  3. Erstellen Sie im Asset-Pack-Verzeichnis eine build.gradle-Datei und fügen Sie den folgenden Code hinzu. Du musst den Namen des Asset-Packs und nur einen Übermittlungstyp angeben:

    Groovig

    // 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. Fügen Sie in der build.gradle-Anwendungsdatei des Projekts den Namen jedes Asset-Packs in Ihrem Projekt hinzu, wie unten gezeigt:

    Groovig

    // 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. Fügen Sie in der Datei settings.gradle des Projekts alle Asset-Packs in Ihrem Projekt ein, wie unten dargestellt:

    Groovig

    // 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. Erstellen Sie im Asset-Pack-Verzeichnis das folgende Unterverzeichnis: src/main/assets.

  7. Platzieren Sie Assets im Verzeichnis src/main/assets. Sie können hier auch Unterverzeichnisse erstellen. Die Verzeichnisstruktur für Ihre Anwendung sollte jetzt so aussehen:

    • build.gradle
    • settings.gradle
    • app/
    • asset-pack-name/build.gradle
    • asset-pack-name/src/main/assets/your-asset-directories
  8. Android App Bundle mit Gradle erstellen Im generierten App-Bundle enthält das Verzeichnis auf Stammebene jetzt Folgendes:

    • asset-pack-name/manifest/AndroidManifest.xml: Konfiguriert die Kennung und den Übermittlungsmodus des Asset-Packs
    • asset-pack-name/assets/your-asset-directories: Verzeichnis, das alle Assets enthält, die als Teil des Asset-Pakets übermittelt wurden

    Gradle generiert das Manifest für jedes Asset-Pack und gibt das Verzeichnis assets/ für Sie aus.

  9. Optional: Fügen Sie die Play Asset Delivery Library hinzu, wenn Sie Fast-Follow- und On-Demand-Übermittlung verwenden möchten.

    Groovig

    implementation "com.google.android.play:asset-delivery:2.2.1"
    // For Kotlin use asset-delivery-ktx
    implementation "com.google.android.play:asset-delivery-ktx:2.2.1"
    

    Kotlin

    implementation("com.google.android.play:asset-delivery:2.2.1")
    // For Kotlin use core-ktx
    implementation("com.google.android.play:asset-delivery-ktx:2.2.1")
    

  10. (Optional) Konfigurieren Sie Ihr App-Bundle so, dass es verschiedene Formate für die Texturkomprimierung unterstützt.

In die Play Asset Delivery API einbinden

Die Play Asset Delivery Java API bietet die Klasse AssetPackManager zum Anfordern von Asset-Packs, zum Verwalten von Downloads und zum Zugriff auf Assets. Achten Sie darauf, Ihrem Projekt zuerst die Play Asset Delivery Library hinzuzufügen.

Sie implementieren diese API entsprechend dem Übermittlungstyp des Asset-Packs, auf das Sie zugreifen möchten. Diese Schritte sind im folgenden Flussdiagramm dargestellt.

Asset-Pack-Flussdiagramm für die Programmiersprache Java

Abbildung 1: Flussdiagramm für den Zugriff auf Asset-Packs

Installationszeitpunkt-Lieferung

Als install-time konfigurierte Asset-Packs sind sofort beim Start der App verfügbar. Mit der AssetManager API für Java kannst du auf Assets zugreifen, die in diesem Modus bereitgestellt werden:

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

Schnelle Lieferung und On-Demand-Bereitstellung

In den folgenden Abschnitten wird beschrieben, wie Sie vor dem Herunterladen Informationen zu Asset-Packs abrufen, die API aufrufen, um den Download zu starten, und anschließend auf die heruntergeladenen Pakete zugreifen. Diese Abschnitte gelten für fast-follow- und on-demand-Asset-Packs.

Status prüfen

Jedes Asset-Pack wird in einem separaten Ordner im internen Speicher der App gespeichert. Verwenden Sie die Methode getPackLocation(), um den Stammordner eines Asset-Packs zu ermitteln. Diese Methode gibt die folgenden Werte zurück:

Rückgabewert Status
Ein gültiges AssetPackLocation-Objekt Der Stammordner des Asset-Packs kann unter assetsPath() sofort aufgerufen werden.
null Unbekanntes Asset-Pack oder unbekannte Assets nicht verfügbar

Informationen zu Asset-Packs herunterladen

Apps müssen die Größe des Downloads offenlegen, bevor das Asset-Pack abgerufen wird. Mit der Methode requestPackStates() oder getPackStates() kannst du die Größe des Downloads ermitteln und feststellen, ob das Paket bereits heruntergeladen wird.

Kotlin

suspend fun requestPackStates(packNames: List<String>): AssetPackStates

Java

Task<AssetPackStates> getPackStates(List<String> packNames)

requestPackStates() ist eine Anhaltefunktion, die ein AssetPackStates-Objekt zurückgibt, während getPackStates() eine asynchrone Methode ist, die einen Task<AssetPackStates> zurückgibt. Die Methode packStates() eines AssetPackStates-Objekts gibt einen Map<String, AssetPackState> zurück. Diese Karte enthält den Status jedes angeforderten Asset-Packs mit seinem Namen:

Kotlin

AssetPackStates#packStates(): Map<String, AssetPackState>

Java

Map<String, AssetPackState> AssetPackStates#packStates()

Die endgültige Anfrage wird so dargestellt:

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;
            })

Die folgenden AssetPackState-Methoden geben die Größe des Asset-Packs, die bisher heruntergeladene Menge (falls angefordert) und die bereits an die App übertragene Menge an:

Um den Status eines Asset-Packs abzurufen, verwenden Sie die Methode status(), die den Status als Ganzzahl zurückgibt, die einem konstanten Feld in der Klasse AssetPackStatus entspricht. Ein Asset-Pack, das noch nicht installiert ist, hat den Status AssetPackStatus.NOT_INSTALLED.

Wenn eine Anfrage fehlschlägt, verwenden Sie die Methode errorCode(), deren Rückgabewert einem konstanten Feld in der Klasse AssetPackErrorCode entspricht.

Installieren

Verwenden Sie die Methode requestFetch() oder fetch(), um ein Asset-Pack zum ersten Mal herunterzuladen, oder rufen Sie die Aktualisierung eines Asset-Packs auf:

Kotlin

suspend fun AssetPackManager.requestFetch(packs: List<String>): AssetPackStates

Java

Task<AssetPackStates> fetch(List<String> packNames)

Diese Methode gibt ein AssetPackStates-Objekt zurück, das eine Liste von Paketen sowie deren anfängliche Downloadstatus und -größen enthält. Wenn ein über requestFetch() oder fetch() angefordertes Asset-Pack bereits heruntergeladen wird, wird der Downloadstatus zurückgegeben und kein weiterer Download gestartet.

Downloadstatus überwachen

Sie sollten einen AssetPackStateUpdatedListener implementieren, um den Installationsfortschritt von Asset-Packs zu verfolgen. Die Statusaktualisierungen werden nach Paket aufgeschlüsselt, um die Verfolgung des Status einzelner Asset-Packs zu unterstützen. Sie können verfügbare Asset-Packs verwenden, bevor alle anderen Downloads für Ihre Anfrage abgeschlossen sind.

Kotlin

fun registerListener(listener: AssetPackStateUpdatedListener)
fun unregisterListener(listener: AssetPackStateUpdatedListener)

Java

void registerListener(AssetPackStateUpdatedListener listener)
void unregisterListener(AssetPackStateUpdatedListener listener)

Große Downloads

Wenn der Download größer als 200 MB ist und der Nutzer keine WLAN-Verbindung hat, wird der Download erst gestartet, wenn der Nutzer ausdrücklich seine Einwilligung für den Download über eine mobile Datenverbindung erteilt hat. Falls der Download sehr groß ist und der Nutzer die WLAN-Verbindung verliert, wird der Download angehalten und es ist eine ausdrückliche Zustimmung erforderlich, um über eine mobile Datenverbindung fortzufahren. Ein pausiertes Paket hat den Status WAITING_FOR_WIFI. Verwenden Sie die Methode showConfirmationDialog(), um den UI-Ablauf auszulösen, bei dem der Nutzer um seine Einwilligung gebeten wird.

Wenn die App diese Methode nicht aufruft, wird der Download angehalten und erst dann automatisch fortgesetzt, wenn der Nutzer wieder eine WLAN-Verbindung hat.

Erforderliche Nutzerbestätigung

Wenn ein Paket den Status REQUIRES_USER_CONFIRMATION hat, wird der Download erst fortgesetzt, wenn der Nutzer das Dialogfeld mit showConfirmationDialog() akzeptiert. Dieser Status kann auftreten, wenn die App von Play nicht erkannt wird, z. B. wenn sie per Sideload übertragen wurde. Wenn Sie in diesem Fall showConfirmationDialog() aufrufen, wird die App aktualisiert. Nach dem Update müssen Sie die Assets noch einmal anfordern.

Im Folgenden finden Sie eine Beispielimplementierung eines Listeners:

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;
      }
    }
}

Alternativ können Sie die Methode getPackStates() verwenden, um den Status aktueller Downloads abzurufen. AssetPackStates enthält den Downloadfortschritt, den Downloadstatus und etwaige Fehlerfehlercodes.

Auf Asset-Packs zugreifen

Sie können mithilfe von Dateisystemaufrufen auf ein Asset-Pack zugreifen, wenn die Downloadanfrage den Status COMPLETED erreicht hat. Verwenden Sie die Methode getPackLocation(), um den Stammordner des Asset-Packs abzurufen.

Assets werden im Verzeichnis assets im Asset-Pack-Stammverzeichnis gespeichert. Sie können den Pfad zum Verzeichnis assets mithilfe der praktischen Methode assetsPath() abrufen. Verwende die folgende Methode, um den Pfad zu einem bestimmten Asset abzurufen:

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;
}

Andere Play Asset Delivery API-Methoden

Nachfolgend finden Sie einige zusätzliche API-Methoden, die Sie in Ihrer App verwenden können.

Anfrage abbrechen

Verwenden Sie cancel(), um eine aktive Asset-Pack-Anfrage abzubrechen. Beachten Sie, dass es sich bei dieser Anfrage um einen Best-Effort-Vorgang handelt.

Asset-Pack entfernen

Verwende requestRemovePack() oder removePack(), um das Entfernen eines Asset-Packs zu planen.

Standorte mehrerer Asset-Packs abrufen

Mit getPackLocations() können Sie den Status mehrerer Asset-Packs im Bulk abfragen. Dadurch wird eine Karte mit Asset-Packs und ihren Standorten zurückgegeben. Die von getPackLocations() zurückgegebene Karte enthält einen Eintrag für jedes Paket, das derzeit heruntergeladen wurde und auf dem neuesten Stand ist.

Nächster Schritt

Teste die Play Asset Delivery lokal und über Google Play.