Integrare la distribuzione degli asset (Kotlin e Java)

Segui i passaggi in questa guida per accedere ai pacchetti di asset della tua app dal tuo codice Java.

Crea per Kotlin e Java

Segui questi passaggi per creare Play Asset Delivery nell'Android App Bundle del tuo progetto. Per eseguire questi passaggi non è necessario utilizzare Android Studio.

  1. Aggiorna la versione del plug-in Android per Gradle nel file build.gradle del tuo progetto a 4.0.0 o a una versione successiva.

  2. Nella directory di primo livello del progetto, crea una directory per il pacchetto di asset. Questo nome della directory viene utilizzato come nome del pacchetto di asset. I nomi dei pacchetti di asset devono iniziare con una lettera e possono contenere solo lettere, numeri e trattini bassi.

  3. Nella directory degli asset pack, crea un file build.gradle e aggiungi il codice seguente. Assicurati di specificare il nome del pacchetto di asset e un solo tipo di pubblicazione:

    trendy

    // 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. Nel file build.gradle dell'app del progetto, aggiungi il nome di ogni pacchetto di asset del progetto come mostrato di seguito:

    trendy

    // 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. Nel file settings.gradle del progetto, includi tutti i pacchetti di asset nel progetto come mostrato di seguito:

    trendy

    // 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. Nella directory dei pacchetti di asset, crea la seguente sottodirectory: src/main/assets.

  7. Posiziona gli asset nella directory src/main/assets. Qui puoi creare anche sottodirectory. Ora la struttura della directory della tua app dovrebbe avere il seguente aspetto:

    • build.gradle
    • settings.gradle
    • app/
    • asset-pack-name/build.gradle
    • asset-pack-name/src/main/assets/your-asset-directories
  8. Crea Android App Bundle con Gradle. Nell'app bundle generato, la directory di livello principale ora include quanto segue:

    • asset-pack-name/manifest/AndroidManifest.xml: configura l'identificatore e la modalità di pubblicazione del pacchetto di asset
    • asset-pack-name/assets/your-asset-directories: directory che contiene tutti gli asset pubblicati come parte del pacchetto di asset

    Gradle genera il manifest per ogni pacchetto di asset e genera automaticamente la directory assets/.

  9. (Facoltativo) Includi la raccolta Asset Delivery di Google Play se prevedi di utilizzare la pubblicazione rapida e on demand.

    trendy

    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. (Facoltativo) Configura l'app bundle in modo che supporti diversi formati di compressione delle texture.

Eseguire l'integrazione con l'API Play Asset Delivery

L'API Play Asset Delivery Java fornisce la classe AssetPackManager per richiedere pacchetti di asset, gestire i download e accedere agli asset. Innanzitutto, assicurati di aggiungere la raccolta di Asset Delivery di Google Play al tuo progetto.

Puoi implementare questa API in base al tipo di pubblicazione del pacchetto di asset a cui vuoi accedere. Questi passaggi sono mostrati nel diagramma di flusso riportato di seguito.

Diagramma di flusso del pacchetto di asset per il linguaggio di programmazione Java

Figura 1. Diagramma di flusso per l'accesso ai pacchetti di asset

Consegna al momento dell'installazione

I pacchetti di asset configurati come install-time sono immediatamente disponibili al momento del lancio dell'app. Utilizza l'API AssetManager Java per accedere agli asset pubblicati in questa modalità:

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

Distribuzione rapida e on demand

Le seguenti sezioni mostrano come ottenere informazioni sui pacchetti di asset prima di scaricarli, come chiamare l'API per avviare il download e come accedere ai pacchetti scaricati. Queste sezioni si applicano ai pacchetti di asset fast-follow e on-demand.

Verifica lo stato

Ogni pacchetto di asset viene archiviato in una cartella separata nella memoria interna dell'app. Utilizza il metodo getPackLocation() per determinare la cartella principale di un pacchetto di asset. Questo metodo restituisce i seguenti valori:

Valore restituito Stato
Un oggetto AssetPackLocation valido La cartella principale del pacchetto di asset è pronta per l'accesso immediato all'indirizzo assetsPath()
null Pacchetti di asset o asset sconosciuti non disponibili

Ricevere informazioni sui download dei pacchetti di asset

Le app devono indicare le dimensioni del download prima di poter recuperare il pacchetto di asset. Utilizza il metodo requestPackStates() o getPackStates() per determinare le dimensioni del download e se il pacchetto è già in fase di download.

Kotlin

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

Java

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

requestPackStates() è una funzione di sospensione che restituisce un oggetto AssetPackStates, mentre getPackStates() è un metodo asincrono che restituisce un oggetto Task<AssetPackStates>. Il metodo packStates() di un oggetto AssetPackStates restituisce Map<String, AssetPackState>. Questa mappa contiene lo stato di ogni pacchetto di asset richiesto, indicato dal nome:

Kotlin

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

Java

Map<String, AssetPackState> AssetPackStates#packStates()

La richiesta finale viene mostrata come segue:

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

I seguenti metodi per AssetPackState forniscono le dimensioni del pacchetto di asset, la quantità scaricata finora (se richiesto) e l'importo già trasferito all'app:

Per ottenere lo stato di un pacchetto di asset, utilizza il metodo status(), che restituisce lo stato come numero intero corrispondente a un campo costante nella classe AssetPackStatus. Un pacchetto di asset non ancora installato ha lo stato AssetPackStatus.NOT_INSTALLED.

Se una richiesta non va a buon fine, utilizza il metodo errorCode(), il cui valore restituito corrisponde a un campo costante nella classe AssetPackErrorCode.

Installa

Utilizza il metodo requestFetch() o fetch() per scaricare un pacchetto di asset per la prima volta o per completare l'aggiornamento di un pacchetto di asset:

Kotlin

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

Java

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

Questo metodo restituisce un oggetto AssetPackStates contenente un elenco di pacchetti con i relativi stati e dimensioni di download iniziali. Se un pacchetto di asset richiesto tramite requestFetch() o fetch() è già in fase di download, viene restituito lo stato di download e non vengono avviati ulteriori download.

Monitorare gli stati di download

Devi implementare un elemento AssetPackStateUpdatedListener per monitorare l'avanzamento dell'installazione dei pacchetti di asset. Gli aggiornamenti dello stato sono suddivisi per pacchetto al fine di supportare il monitoraggio dello stato dei singoli pacchetti di asset. Puoi iniziare a utilizzare i pacchetti di asset disponibili prima che tutti gli altri download per la tua richiesta siano stati completati.

Kotlin

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

Java

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

Download di grandi dimensioni

Se il download ha dimensioni superiori a 200 MB e l'utente non è connesso a una rete Wi-Fi, il download non inizia finché l'utente non dà esplicitamente il suo consenso a procedere con il download utilizzando una connessione dati mobili. Analogamente, se il download è di grandi dimensioni e l'utente perde la connessione Wi-Fi, il download viene messo in pausa ed è richiesto il consenso esplicito per procedere utilizzando una connessione dati mobili. Un pacchetto in pausa ha lo stato WAITING_FOR_WIFI. Per attivare il flusso della UI in modo da richiedere il consenso all'utente, utilizza il metodo showConfirmationDialog().

Tieni presente che se l'app non chiama questo metodo, il download viene sospeso e riprenderà automaticamente solo quando l'utente sarà di nuovo connesso a una connessione Wi-Fi.

Conferma dell'utente obbligatoria

Se un pacchetto ha lo stato REQUIRES_USER_CONFIRMATION, il download non verrà proceduto finché l'utente non accetta la finestra di dialogo visualizzata con showConfirmationDialog(). Questo stato può verificarsi quando l'app non è riconosciuta da Play, ad esempio se l'app è stata installata tramite sideload. Tieni presente che in questo caso la chiamata al numero showConfirmationDialog() comporta l'aggiornamento dell'app. Dopo l'aggiornamento, dovrai richiedere di nuovo gli asset.

Di seguito è riportato un esempio di implementazione di un listener:

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

In alternativa, puoi utilizzare il metodo getPackStates() per ottenere lo stato dei download correnti. AssetPackStates contiene l'avanzamento del download, lo stato del download ed eventuali codici di errore di errore.

Accedi ai pacchetti di asset

Puoi accedere a un pacchetto di asset utilizzando le chiamate del file system dopo che la richiesta di download raggiunge lo stato COMPLETED. Utilizza il metodo getPackLocation() per recuperare la cartella principale del pacchetto di asset.

Gli asset vengono archiviati nella directory assets all'interno della directory principale del pacchetto di asset. Puoi ottenere il percorso della directory assets utilizzando il metodo pratico assetsPath(). Utilizza il metodo seguente per recuperare il percorso di un asset specifico:

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

Altri metodi dell'API Play Asset Delivery

Di seguito sono riportati alcuni metodi API aggiuntivi che puoi utilizzare nella tua app.

Annulla richiesta

Utilizza cancel() per annullare una richiesta di pacchetto di asset attiva. Tieni presente che questa richiesta è un'operazione del miglior sforzo.

Rimuovere un pacchetto di asset

Utilizza requestRemovePack() o removePack() per pianificare la rimozione di un pacchetto di asset.

Visualizza le posizioni di più pacchetti di asset

Utilizza getPackLocations() per eseguire query sullo stato di più pacchetti di asset contemporaneamente, ottenendo una mappa dei pacchetti di asset e la relativa posizione. La mappa restituita da getPackLocations() contiene una voce per ogni pacchetto attualmente scaricato e aggiornato.

Passaggio successivo

Testa Play Asset Delivery in locale e da Google Play.