Use as etapas deste guia para acessar os pacotes de recursos do app no código Java.
Criar para Kotlin e Java
Use as etapas a seguir para criar o recurso Play Asset Delivery no Android App Bundle do seu projeto. Não é necessário usar o Android Studio para executar estas etapas.
Atualize a versão do Plug-in do Android para Gradle no arquivo
build.gradle
do projeto para4.0.0
ou mais recente.No diretório de nível superior do projeto, crie um diretório para o pacote de recursos. O nome do diretório é usado como nome do pacote de recursos. Os nomes de pacotes de recursos precisam começar com uma letra e só podem conter letras, números e sublinhados.
No diretório do pacote de recursos, crie um arquivo
build.gradle
e adicione o seguinte código. Especifique o nome do pacote de recursos e apenas um tipo de entrega: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 ]") } }
No arquivo
build.gradle
do app do projeto, adicione o nome de cada pacote de recursos, conforme mostrado a seguir: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") }
No arquivo
settings.gradle
do projeto, inclua todos os pacotes de recursos, conforme mostrado a seguir: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")
No diretório do pacote de recursos, crie o seguinte subdiretório:
src/main/assets
.Coloque recursos no diretório
src/main/assets
. Você também pode criar subdiretórios nesse local. A estrutura de diretórios do seu app agora terá a seguinte aparência:build.gradle
settings.gradle
app/
asset-pack-name/build.gradle
asset-pack-name/src/main/assets/your-asset-directories
Crie o Android App Bundle com o Gradle. No pacote de apps gerado, o diretório de nível raiz agora inclui o seguinte:
asset-pack-name/manifest/AndroidManifest.xml
: configura o identificador e o modo de entrega do pacote de recursosasset-pack-name/assets/your-asset-directories
: diretório que contém todos os recursos enviados como parte do pacote de recursos
O Gradle gera o manifesto para cada pacote de recursos e gera o diretório
assets/
para você.(Opcional) Inclua a biblioteca Play Asset Delivery se você quiser usar a entrega rápida e sob demanda.
Groovy
implementation "com.google.android.play:asset-delivery:2.2.2" // For Kotlin use asset-delivery-ktx implementation "com.google.android.play:asset-delivery-ktx:2.2.2"
Kotlin
implementation("com.google.android.play:asset-delivery:2.2.2") // For Kotlin use core-ktx implementation("com.google.android.play:asset-delivery-ktx:2.2.2")
(Opcional) Configure seu pacote de apps para oferecer suporte a diferentes formatos de compactação de textura.
Integrar com a API Play Asset Delivery
A API Play Asset Delivery para Java
fornece a classe
AssetPackManager
para solicitar pacotes de recursos, gerenciar downloads e acessar os recursos. Primeiro, adicione a biblioteca Play Asset Delivery ao seu projeto.
Implemente essa API de acordo com o tipo de entrega do pacote de recursos que você quer acessar. Essas etapas são mostradas no fluxograma a seguir.
Entrega no momento da instalação
Os pacotes de recursos configurados como install-time
estão imediatamente disponíveis na
inicialização do app. Use a API AssetManager do
Java para acessar recursos
veiculados nesse modo:
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");
Entrega rápida e sob demanda
As seções a seguir mostram como acessar informações sobre pacotes de recursos antes
de fazer o download deles, como chamar a API para iniciar o download e como
acessá-los após o download. Essas seções se aplicam aos pacotes de recursos fast-follow
e
on-demand
.
Verificar status
Cada pacote de recursos é armazenado em uma pasta separada no armazenamento interno do app.
Use o método
getPackLocation()
para determinar a pasta raiz de um pacote de recursos. Esse método retorna os
seguintes valores:
Valor de retorno | Status |
---|---|
Um objeto AssetPackLocation válido |
A pasta raiz do pacote de recursos está pronta para acesso imediato em assetsPath() |
null |
Pacotes de recursos desconhecidos ou indisponíveis |
Receber informações de download sobre pacotes de recursos
Os apps precisam divulgar o tamanho do download antes de buscar o pacote de
recursos. Use o método
requestPackStates()
ou getPackStates()
para determinar o tamanho do download e se o pacote já está sendo
transferido por download.
Kotlin
suspend fun requestPackStates(packNames: List<String>): AssetPackStates
Java
Task<AssetPackStates> getPackStates(List<String> packNames)
requestPackStates()
é uma função de suspensão que retorna um
objeto AssetPackStates
,
e getPackStates()
é um método assíncrono que retorna um Task<AssetPackStates>
. O método
packStates()
de um objeto AssetPackStates
retorna um Map<String,
AssetPackState>
. Esse mapa contém o estado de cada pacote de recursos
solicitado, codificado pelo nome:
Kotlin
AssetPackStates#packStates(): Map<String, AssetPackState>
Java
Map<String, AssetPackState> AssetPackStates#packStates()
A solicitação final é mostrada por:
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; })
Os métodos
AssetPackState
abaixo fornecem o tamanho do pacote de recursos, o valor transferido por download até o momento (se
solicitado) e o valor já transferido ao app.
Para saber o status de um pacote de recursos, use o método
status()
,
que retorna o status como um número inteiro que corresponde a um campo de
constante na
classe
AssetPackStatus
. Um pacote de recursos ainda não instalado tem o status
AssetPackStatus.NOT_INSTALLED
.
Se uma solicitação falhar, use o método
errorCode()
,
cujo valor de retorno corresponde a um campo de constante na
classe
AssetPackErrorCode
.
Instalar
Use os métodos requestFetch()
ou
fetch()
para fazer o download de um pacote de recursos pela primeira vez ou chame a atualização de um
pacote de recursos para concluir:
Kotlin
suspend fun AssetPackManager.requestFetch(packs: List<String>): AssetPackStates
Java
Task<AssetPackStates> fetch(List<String> packNames)
Esse método retorna um objeto
AssetPackStates
contendo uma lista de pacotes e os estados e tamanhos iniciais de download deles.
Se um download de pacote de recurso solicitado pelo método requestFetch()
ou fetch()
já estiver sendo feito, o status do
download é retornado e nenhum outro download vai ser iniciado.
Monitorar estados de download
Implemente um
AssetPackStateUpdatedListener
para monitorar o progresso da instalação de pacotes
de recursos. As atualizações de status são divididas por pacote para auxiliar no monitoramento do
status de pacotes de recursos individuais. Você pode começar a usar os pacotes de recursos
disponíveis antes que todos os outros downloads da sua solicitação sejam concluídos.
Kotlin
fun registerListener(listener: AssetPackStateUpdatedListener) fun unregisterListener(listener: AssetPackStateUpdatedListener)
Java
void registerListener(AssetPackStateUpdatedListener listener) void unregisterListener(AssetPackStateUpdatedListener listener)
Downloads grandes
Se o download for maior que 200 MB e o usuário não estiver conectado ao Wi-Fi, o download
não será iniciado até que o usuário conceda explicitamente o consentimento para prosseguir com o
download usando uma conexão de dados móveis. Da mesma forma, se o download for grande e
o usuário perder a conexão ao Wi-Fi, o download será pausado e o consentimento explícito será necessário para
continuar usando uma conexão de dados móveis. Um pacote pausado tem o estado
WAITING_FOR_WIFI
. Para acionar o fluxo da IU para solicitar o consentimento do usuário, use
o método
showConfirmationDialog()
.
Se o app não chamar esse método, o download será pausado e retomado automaticamente somente quando o usuário voltar a se conectar por Wi-Fi.
Confirmação do usuário necessária
Se um pacote tiver o status REQUIRES_USER_CONFIRMATION
, o download não
continuará até que o usuário aceite a caixa de diálogo mostrada com
showConfirmationDialog()
.
Esse status pode ocorrer quando o app não é reconhecido pelo Google Play, por exemplo, se
ele foi transferido por sideload.
Observe que chamar
showConfirmationDialog()
nesse caso fará com que o app seja atualizado. Após a atualização, será necessário
solicitar os recursos novamente.
Este é um exemplo de implementação de um 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; } } }
Se preferir, use o método
getPackStates()
para ver o status dos downloads atuais.
AssetPackStates
contém o progresso do download, o status do download e todos os códigos de erro de falha.
Acessar pacotes de recursos
É possível acessar um pacote de recursos usando chamadas do sistema de arquivos após a solicitação de download
chegar ao
estado
COMPLETED
. Use o método
getPackLocation()
para acessar a pasta raiz do pacote de recursos.
Os recursos são armazenados no diretório assets
dentro do diretório
raiz do pacote de recursos. Você pode acessar o caminho para o diretório assets
usando o
método de conveniência
assetsPath()
.
Use o método abaixo para acessar o caminho de um recurso específico:
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; }
Outros métodos da API Play Asset Delivery
Mostramos abaixo alguns outros métodos da API que podem ser usados no seu app.
Cancelar solicitação
Use
cancel()
para cancelar uma solicitação ativa de pacote de recursos. Observe que essa solicitação é uma operação de melhor esforço.
Remover um pacote de recursos
Use
requestRemovePack()
ou
removePack()
para programar a remoção de um pacote de recursos.
Acessar locais de vários pacotes de recursos
Use
getPackLocations()
para consultar o status de vários pacotes de recursos em massa. Isso retorna um mapa de
pacotes de recursos e os locais deles. O mapa retornado por getPackLocations()
contém uma entrada para cada pacote que está atualmente salvo e atualizado.
A seguir
Teste o Play Asset Delivery localmente e no Google Play.