Следуйте инструкциям в этом руководстве, чтобы получить доступ к пакетам ресурсов вашего приложения из вашего Java-кода.
Сборка для Kotlin и Java
Выполните следующие шаги, чтобы интегрировать Play Asset Delivery в пакет Android-приложения вашего проекта. Для выполнения этих шагов вам не потребуется Android Studio.
Обновите версию плагина Android Gradle в файле
build.gradleвашего проекта до4.0.0или более поздней.В корневом каталоге вашего проекта создайте каталог для пакета ресурсов. Имя этого каталога будет использоваться в качестве имени пакета ресурсов. Имена пакетов ресурсов должны начинаться с буквы и могут содержать только буквы, цифры и подчеркивания.
В каталоге asset pack создайте файл
build.gradleи добавьте следующий код. Убедитесь, что указано имя asset pack и только один тип доставки:Классный
// 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 ]" } }
Котлин
// 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"] }
Котлин
// 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'
Котлин
// In the settings.gradle.kts file: include(":app") include(":asset-pack-name") include(":asset-pack2-name")
В каталоге пакета ресурсов создайте следующую подпапку:
src/main/assets.Разместите ресурсы в каталоге
src/main/assets. Здесь также можно создавать подкаталоги. Структура каталогов вашего приложения теперь должна выглядеть следующим образом:-
build.gradle -
settings.gradle -
app/ -
asset-pack-name /build.gradle -
asset-pack-name /src/main/assets/ your-asset-directories
-
Создайте пакет Android-приложения с помощью Gradle . В сгенерированном пакете приложения корневой каталог теперь содержит следующее:
-
asset-pack-name /manifest/AndroidManifest.xml: Настраивает идентификатор пакета ресурсов и режим доставки. -
asset-pack-name /assets/ your-asset-directories: Каталог, содержащий все ресурсы, входящие в состав пакета ресурсов.
Gradle генерирует манифест для каждого пакета ресурсов и выводит путь к каталогу
assets/.-
(Необязательно) Включите библиотеку Play Asset Delivery Library, если вы планируете использовать быструю доставку контента по запросу.
Классный
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"
Котлин
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")
(Необязательно) Настройте пакет приложения для поддержки различных форматов сжатия текстур .
Интеграция с API доставки игровых ресурсов.
Java API Play Asset Delivery предоставляет класс AssetPackManager для запроса пакетов ресурсов, управления загрузками и доступа к ресурсам. Перед использованием обязательно добавьте библиотеку Play Asset Delivery в свой проект.
Реализация этого API осуществляется в соответствии с типом доставки пакета ресурсов, к которому вы хотите получить доступ. Эти шаги показаны на следующей блок-схеме.

Рисунок 1. Блок-схема доступа к пакетам активов.
Доставка в момент установки
Пакеты ресурсов, настроенные как install-time становятся доступны сразу после запуска приложения. Используйте API Java AssetManager для доступа к ресурсам, предоставляемым в этом режиме:
Котлин
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() чтобы определить размер загружаемого файла и проверить, загружается ли пакет уже в данный момент.
Котлин
suspend fun requestPackStates(packNames: List<String>): AssetPackStates
Java
Task<AssetPackStates> getPackStates(List<String> packNames)
requestPackStates() — это функция приостановки, возвращающая объект AssetPackStates а метод getPackStates() — это асинхронный метод, возвращающий Task<AssetPackStates> . Метод packStates() объекта AssetPackStates возвращает Map<String, AssetPackState> . Эта карта содержит состояние каждого запрошенного пакета ресурсов, ключом к которому является его имя:
Котлин
AssetPackStates#packStates(): Map<String, AssetPackState>
Java
Map<String, AssetPackState> AssetPackStates#packStates()
Окончательный вариант запроса представлен следующим образом:
Котлин
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() для первой загрузки пакета ресурсов или для завершения обновления пакета ресурсов:
Котлин
suspend fun AssetPackManager.requestFetch(packs: List<String>): AssetPackStates
Java
Task<AssetPackStates> fetch(List<String> packNames)
Этот метод возвращает объект AssetPackStates , содержащий список пакетов ресурсов, их начальное состояние загрузки и размеры. Если пакет ресурсов, запрошенный с помощью requestFetch() или fetch() , уже загружается, возвращается статус загрузки, и дальнейшая загрузка не начинается.
Мониторинг состояний загрузки
Для отслеживания хода установки пакетов ресурсов следует реализовать обработчик состояния AssetPackStateUpdatedListener . Обновления статуса будут разбиты по пакетам, что позволит отслеживать состояние отдельных пакетов ресурсов. Вы можете начать использовать доступные пакеты ресурсов до завершения всех остальных загрузок по вашему запросу.
Котлин
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() . Этот статус может возникнуть, если приложение не распознается Play — например, если оно было установлено сторонними средствами. Обратите внимание, что вызов showConfirmationDialog() в этом случае приведет к обновлению приложения. После обновления вам потребуется повторно запросить ресурсы.
Ниже приведён пример реализации обработчика событий:
Котлин
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() . Используйте следующий метод, чтобы получить путь к конкретному ресурсу:
Котлин
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; }
Другие методы API для доставки игровых ресурсов
Ниже приведены некоторые дополнительные методы API, которые вы можете использовать в своем приложении.
Отменить запрос
Используйте cancel() для отмены активного запроса на создание пакета ресурсов. Обратите внимание, что этот запрос выполняется с максимальными усилиями.
Удалить пакет ресурсов
Используйте requestRemovePack() или removePack() для планирования удаления пакета ресурсов.
Получить местоположение нескольких пакетов ресурсов
Используйте getPackLocations() для одновременного запроса статуса нескольких пакетов ресурсов. Она возвращает карту пакетов ресурсов и их местоположений. Карта, возвращаемая функцией getPackLocations() содержит запись для каждого пакета, который в данный момент загружен и актуален.
Следующий шаг
Тестирование доставки игровых ресурсов локально и из Google Play.