Intégrer Asset Delivery (Kotlin et Java)

Suivez les étapes de ce guide pour accéder aux packs d'éléments de votre application à partir de votre code Java.

Compiler pour Kotlin et Java

Procédez comme suit pour intégrer Play Asset Delivery dans le fichier Android App Bundle de votre projet. Vous n'avez pas besoin d'utiliser Android Studio pour effectuer cette procédure.

  1. Mettez à jour le plug-in Android Gradle dans le fichier build.gradle de votre projet vers la version 4.0.0 ou ultérieure.

  2. Dans le répertoire racine de votre projet, créez un répertoire pour le pack d'éléments. Ce nom de répertoire est utilisé comme nom du pack d'éléments. Les noms des packs d'éléments doivent commencer par une lettre et ne peuvent contenir que des lettres, des chiffres et des traits de soulignement.

  3. Dans le répertoire du pack d'éléments, créez un fichier build.gradle et ajoutez-y le code suivant. Veillez à spécifier le nom du pack d'éléments et un seul type de distribution :

    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. Dans le fichier build.gradle de l'application du projet, ajoutez le nom de chaque pack d'éléments de votre projet comme indiqué ci-dessous :

    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. Dans le fichier settings.gradle du projet, incluez tous les packs d'éléments de votre projet comme indiqué ci-dessous :

    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. Dans le répertoire du pack d'éléments, créez le sous-répertoire suivant : src/main/assets.

  7. Placez des éléments dans le répertoire src/main/assets. Vous pouvez aussi créer des sous-répertoires dans ce répertoire. La structure de répertoire de votre application devrait maintenant se présenter comme suit :

    • build.gradle
    • settings.gradle
    • app/
    • asset-pack-name/build.gradle
    • asset-pack-name/src/main/assets/your-asset-directories
  8. Compilez le package Android App Bundle avec Gradle. Dans l'app bundle généré, le répertoire racine inclut désormais les éléments suivants :

    • asset-pack-name/manifest/AndroidManifest.xml : configure l'identifiant et le mode de distribution du pack d'éléments
    • asset-pack-name/assets/your-asset-directories : répertoire contenant tous les éléments distribués dans le pack d'éléments

    Gradle génère le fichier manifeste pour chaque pack d'éléments et fournit le répertoire assets/ pour vous.

  9. (Facultatif) Incluez la bibliothèque Play Asset Delivery si vous prévoyez d'utiliser la distribution rapide et à la demande.

    Groovy

    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. (Facultatif) Configurez votre app bundle pour qu'il soit compatible avec différents formats de compression de texture.

Intégrer à l'API Play Asset Delivery

L'API Play Asset Delivery pour Java fournit la classe AssetPackManager pour demander des packs d'éléments, gérer les téléchargements et accéder aux éléments. Assurez-vous d'abord d'ajouter la bibliothèque Play Asset Delivery à votre projet.

Vous implémentez cette API en fonction du type de distribution du pack d'éléments auquel vous souhaitez accéder. Ces étapes sont présentées dans l'organigramme suivant.

Schéma du flux du pack d'éléments pour le langage de programmation Java

Figure 1 : Organigramme illustrant l'accès aux packs d'éléments

Distribution au moment de l'installation

Les packs d'éléments configurés en tant que install-time sont disponibles immédiatement au lancement de l'application. Utilisez l'API AssetManager Java pour accéder aux éléments diffusés dans ce mode :

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

Distribution rapide et à la demande

Les sections suivantes expliquent comment obtenir des informations sur les packs d'éléments avant de les télécharger, comment appeler l'API pour lancer le téléchargement et comment accéder aux packs téléchargés. Ces sections s'appliquent aux packs d'éléments fast-follow et on-demand.

Vérifier l'état

Chaque pack d'éléments est stocké dans un dossier distinct de la mémoire de stockage interne de l'application. Utilisez la méthode getPackLocation() pour déterminer le dossier racine d'un pack d'éléments. Cette méthode renvoie les valeurs suivantes :

Valeur renvoyée État
Un objet AssetPackLocation valide Le dossier racine du pack d'éléments est prêt pour un accès immédiat sur assetsPath()
null Pack d'éléments inconnu ou éléments non disponibles

Obtenir des informations de téléchargement sur les packs d'éléments

Les applications doivent indiquer la taille du téléchargement avant la récupération du pack d'éléments. Utilisez la méthode requestPackStates() ou getPackStates() pour déterminer la taille du téléchargement et si le pack est déjà en cours de téléchargement.

Kotlin

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

Java

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

requestPackStates() est une fonction de suspension renvoyant un objet AssetPackStates, tandis que getPackStates() est une méthode asynchrone qui renvoie un Task<AssetPackStates>. La méthode packStates() d'un objet AssetPackStates renvoie un Map<String, AssetPackState>. Cette carte contient l'état de chaque pack d'éléments demandé, associé à son nom :

Kotlin

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

Java

Map<String, AssetPackState> AssetPackStates#packStates()

La requête finale est affichée comme suit :

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

Les méthodes AssetPackState suivantes fournissent la taille du pack d'éléments, le nombre d'éléments téléchargés jusqu'à présent (si demandé) et le montant déjà transféré vers l'application :

Pour connaître l'état d'un pack d'éléments, utilisez la méthode status(), qui renvoie l'état sous la forme d'un entier correspondant à un champ constant dans la classe AssetPackStatus. Un pack d'éléments qui n'est pas encore installé est à l'état AssetPackStatus.NOT_INSTALLED.

Si une requête échoue, utilisez la méthode errorCode(), dont la valeur renvoyée correspond à un champ constant dans la classe AssetPackErrorCode.

Installer

Utilisez la méthode requestFetch() ou fetch() pour télécharger un pack d'éléments pour la première fois ou appeler la mise à jour d'un pack d'éléments :

Kotlin

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

Java

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

Cette méthode renvoie un objet AssetPackStates contenant une liste de packs, ainsi que leurs états et tailles de téléchargement initiaux. Si un pack d'éléments demandé via requestFetch() ou fetch() est déjà en cours de téléchargement, l'état du téléchargement est renvoyé et aucun téléchargement supplémentaire n'est lancé.

Surveiller l'état des téléchargements

Vous devez mettre en œuvre un AssetPackStateUpdatedListener pour suivre la progression de l'installation des packs d'éléments. Les mises à jour de l'état sont réparties par pack afin de permettre le suivi de l'état de chaque pack d'éléments. Vous pouvez commencer à utiliser les packs d'éléments disponibles avant la fin de tous les autres téléchargements.

Kotlin

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

Java

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

Téléchargements volumineux

Si le téléchargement est supérieur à 200 Mo et que l'utilisateur n'est pas connecté au Wi-Fi, le téléchargement ne démarre pas tant que l'utilisateur n'a pas explicitement autorisé le téléchargement à l'aide d'une connexion de données mobiles. De même, si le téléchargement est volumineux et que l'utilisateur perd la connexion au réseau Wi-Fi, le téléchargement est suspendu et l'utilisateur doit explicitement accepter de poursuivre le téléchargement à l'aide d'une connexion de données mobiles. Un pack mis en pause possède l'état WAITING_FOR_WIFI. Pour déclencher le flux d'interface utilisateur afin de demander le consentement de l'utilisateur, utilisez la méthode showConfirmationDialog().

Notez que si l'application n'appelle pas cette méthode, le téléchargement est suspendu et ne reprendra automatiquement que lorsque l'utilisateur sera de nouveau connecté à un réseau Wi-Fi.

Confirmation de l'utilisateur requise

Si un pack présente l'état REQUIRES_USER_CONFIRMATION, le téléchargement ne se poursuit pas tant que l'utilisateur n'a pas accepté la boîte de dialogue qui s'affiche avec showConfirmationDialog(). Cet état peut s'afficher lorsque l'application n'est pas reconnue par Play, par exemple si elle a été téléchargée indépendamment. Notez que l'appel de showConfirmationDialog() dans ce cas entraîne la mise à jour de l'application. Après la mise à jour, vous devrez redemander les éléments.

Voici un exemple d'implémentation d'un écouteur :

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

Vous pouvez également utiliser la méthode getPackStates() pour obtenir l'état des téléchargements actuels. AssetPackStates contient la progression du téléchargement, l'état du téléchargement et les codes d'erreur éventuels.

Accéder aux packs d'éléments

Vous pouvez accéder à un pack d'éléments à l'aide d'appels au système de fichiers, une fois que la requête de téléchargement a atteint l'état COMPLETED. Utilisez la méthode getPackLocation() pour obtenir le dossier racine du pack d'éléments.

Les éléments sont stockés dans le répertoire assets du répertoire racine du pack d'éléments. Vous pouvez obtenir le chemin d'accès au répertoire assets à l'aide de la méthode pratique assetsPath(). Utilisez la méthode suivante pour obtenir le chemin d'accès à un élément spécifique :

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

Autres méthodes de l'API Play Asset Delivery

Voici quelques méthodes d'API supplémentaires que vous pouvez utiliser dans votre application.

Annuler la requête

Utilisez cancel() pour annuler une requête active relative au pack d'éléments. Notez que cette requête est effectuée dans la mesure du possible.

Supprimer un pack d'éléments

Utilisez requestRemovePack() ou removePack() pour planifier la suppression d'un pack d'éléments.

Obtenir les emplacements de plusieurs packs d'éléments

Utilisez getPackLocations() pour interroger de façon groupée l'état de plusieurs packs d'éléments, ce qui renvoie une carte des packs d'éléments et de leur emplacement. La carte renvoyée par getPackLocations() contient une entrée pour chaque pack actuellement téléchargé et à jour.

Étape suivante

Testez Play Asset Delivery en local et à partir de Google Play.