Чтобы получить доступ к пакетам объектов приложения из кода Java, следуйте инструкциям в этом руководстве.
Разработка для Kotlin и Java
Чтобы встроить Play Asset Delivery в набор Android App Bundle, выполните следующие действия: Для выполнения этих действий не требуется Android Studio.
Обновите версию плагина Android Gradle в файле
build.gradleпроекта до4.0.0или более поздней.В каталоге верхнего уровня проекта создайте каталог для пакета объектов. Название каталога используется в качестве названия пакета объектов. Название пакета объектов должно начинаться с буквы и может содержать только буквы, цифры и символы подчеркивания.
В каталоге пакета объектов создайте файл
build.gradleи добавьте в него следующий код: Укажите название пакета объектов и только один тип доставки:Яркий
// 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 ]") } }
В файле
build.gradleприложения добавьте название каждого пакета объектов в проекте, как показано ниже.Яркий
// 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") }
В файле
settings.gradleпроекта укажите все пакеты объектов, как показано ниже:Яркий
// 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")
В каталоге пакета объектов создайте подкаталог
src/main/assets.Поместите объекты в каталог
src/main/assets. Здесь вы также можете создавать подкаталоги. Структура каталогов приложения должна выглядеть следующим образом:build.gradlesettings.gradleapp/asset-pack-name/build.gradleasset-pack-name/src/main/assets/your-asset-directories
Как создать набор Android App Bundle с помощью Gradle В созданном наборе App Bundle корневой каталог теперь содержит следующее:
asset-pack-name/manifest/AndroidManifest.xml: настраивает идентификатор пакета объектов и режим доставки.asset-pack-name/assets/your-asset-directories– каталог, содержащий все объекты, которые поставляются в составе пакета объектов.
Gradle генерирует манифест для каждого пакета объектов и создает каталог
assets/.При необходимости добавьте библиотеку Play Asset Delivery, если вы планируете использовать быструю доставку и доставку по запросу.
Яркий
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")
При необходимости настройте поддержку разных форматов сжатия текстур в наборе App Bundle.
Интеграция с Play Asset Delivery API
Play Asset Delivery Java API предоставляет класс AssetPackManager для запроса пакетов объектов, управления скачиваниями и доступа к объектам. Сначала добавьте библиотеку Play Asset Delivery в проект.
Реализация API зависит от типа доставки пакета объектов, к которому вы хотите получить доступ. Эти шаги показаны на блок-схеме ниже.
Рисунок 1. Блок-схема доступа к пакетам объектов
Доставка при установке
Пакеты объектов, настроенные как install-time, доступны сразу после запуска приложения. Для доступа к объектам, которые показываются в этом режиме, используйте AssetManager API для 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");
Быстрая доставка и доставка по запросу
В разделах ниже рассказывается, как получить информацию о пакетах объектов перед их скачиванием, как вызвать API, чтобы начать скачивание, и как получить доступ к скачанным пакетам. Эти разделы относятся к пакетам объектов fast-follow и on-demand.
Проверить статус
Каждый пакет объектов хранится в отдельной папке во внутреннем хранилище приложения.
Чтобы определить корневую папку пакета объектов, используйте метод getPackLocation(). Этот метод возвращает следующие значения:
| Возвращаемое значение | Статус |
|---|---|
Действительный объект AssetPackLocation. |
Корневая папка пакета объектов доступна по адресу assetsPath(). |
null |
Неизвестный пакет объектов или объекты недоступны. |
Как получить информацию о скачивании пакетов объектов
Перед скачиванием пакета объектов приложение должно сообщить пользователю размер файла. Чтобы определить размер скачиваемого файла и узнать, скачивается ли уже пакет, используйте метод requestPackStates() или getPackStates().
Kotlin
suspend fun requestPackStates(packNames: List<String>): AssetPackStates
Java
Task<AssetPackStates> getPackStates(List<String> packNames)
requestPackStates() – это функция приостановки, которая возвращает объект AssetPackStates, а getPackStates() – асинхронный метод, возвращающий Task<AssetPackStates>. Метод packStates() объекта AssetPackStates возвращает Map<String,
AssetPackState>. Эта карта содержит статус каждого запрошенного пакета объектов, ключом которого является его название:
Kotlin
AssetPackStates#packStates(): Map<String, AssetPackState>
Java
Map<String, AssetPackState> AssetPackStates#packStates()
Окончательный запрос выглядит следующим образом:
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; })
Следующие методы AssetPackState позволяют узнать размер пакета объектов, объем скачанных данных (если запрашивается) и объем данных, уже переданных в приложение:
Чтобы получить статус пакета объектов, используйте метод status(), который возвращает статус в виде целого числа, соответствующего постоянному полю в классе AssetPackStatus. Пакет объектов, который ещё не установлен, имеет статус AssetPackStatus.NOT_INSTALLED.
Если запрос не удается выполнить, используйте метод errorCode(), возвращаемое значение которого соответствует постоянному полю в классе AssetPackErrorCode.
Установить
Чтобы скачать пакет объектов в первый раз или завершить его обновление, используйте метод requestFetch() или fetch().
Kotlin
suspend fun AssetPackManager.requestFetch(packs: List<String>): AssetPackStates
Java
Task<AssetPackStates> fetch(List<String> packNames)
Этот метод возвращает объект AssetPackStates, содержащий список наборов, их начальные статусы скачивания и размеры.
Если пакет объектов, запрошенный с помощью requestFetch() или fetch(), уже скачивается, возвращается статус скачивания и дополнительное скачивание не запускается.
Как отслеживать статусы скачивания
Чтобы отслеживать ход установки пакетов объектов, реализуйте AssetPackStateUpdatedListener. Обновления статуса разбиты по пакетам, чтобы можно было отслеживать статус отдельных пакетов объектов. Вы можете начать использовать доступные пакеты объектов,
не дожидаясь завершения скачивания остальных пакетов.
Kotlin
fun registerListener(listener: AssetPackStateUpdatedListener) fun unregisterListener(listener: AssetPackStateUpdatedListener)
Java
void registerListener(AssetPackStateUpdatedListener listener) void unregisterListener(AssetPackStateUpdatedListener listener)
Большие скачиваемые файлы
Если размер скачиваемого файла превышает 200 МБ и пользователь не подключен к сети Wi-Fi, скачивание не начнется, пока пользователь не даст явное согласие на скачивание с использованием мобильного интернета. Аналогично, если скачивается большой файл и пользователь теряет подключение к Wi-Fi, скачивание приостанавливается и для его продолжения с использованием мобильного интернета требуется явное согласие. Приостановленный набор имеет статус WAITING_FOR_WIFI. Чтобы запустить интерфейс для получения согласия пользователя, используйте метод showConfirmationDialog().
Если приложение не вызывает этот метод, скачивание приостанавливается и возобновляется автоматически, только когда пользователь снова подключается к сети Wi-Fi.
Требуется подтверждение пользователя
Если у пакета статус REQUIRES_USER_CONFIRMATION, скачивание не начнется, пока пользователь не подтвердит его в диалоговом окне, которое показывается с помощью showConfirmationDialog().
Такой статус может быть у приложения, которое не распознается Google Play, например если оно было установлено из неизвестного источника.
Обратите внимание, что вызов showConfirmationDialog() в этом случае приведет к обновлению приложения. После обновления вам нужно будет запросить объекты снова.
Ниже приведен пример реализации прослушивателя.
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; } } }
Вы также можете использовать метод getPackStates(), чтобы узнать статус текущих скачиваний.
AssetPackStates
содержит информацию о ходе скачивания, его статусе и кодах ошибок.
Как получить доступ к пакетам объектов
Вы можете получить доступ к пакету объектов, используя вызовы файловой системы, после того как запрос на скачивание перейдет в состояние COMPLETED. Используйте метод getPackLocation(), чтобы получить корневую папку пакета объектов.
Объекты хранятся в каталоге assets в корневом каталоге пакета объектов. Путь к каталогу assets можно получить с помощью удобного метода assetsPath().
Чтобы узнать путь к определенному объекту, выполните следующие действия:
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; }
Другие методы Play Asset Delivery API
Ниже приведены дополнительные методы API, которые вы можете использовать в своем приложении.
Отменить запрос
Чтобы отменить активный запрос пакета объектов, используйте cancel(). Обратите внимание, что этот запрос выполняется по мере возможности.
Как удалить пакет объектов
Чтобы запланировать удаление пакета объектов, используйте requestRemovePack() или removePack().
Как получить местоположения нескольких пакетов объектов
Используйте getPackLocations(), чтобы запросить статус нескольких пакетов объектов. Вы получите карту пакетов объектов и их местоположений. Карта, возвращаемая getPackLocations(), содержит запись для каждого пакета, который в настоящее время скачан и обновлен.
Дальнейшие действия
Протестируйте Play Asset Delivery локально и в Google Play.