Java コードからアプリのアセットパックにアクセスするには、このガイドの手順を実施します。
Kotlin と Java 用にビルドする
プロジェクトの Android App Bundle に Play Asset Delivery を組み込む手順は次のとおりです。この手順で Android Studio を使用する必要はありません。
プロジェクトの
build.gradle
ファイル内の Android Gradle プラグインのバージョンを4.0.0
以降に更新します。プロジェクトの最上位ディレクトリに、アセットパックのディレクトリを作成します。このディレクトリ名はアセットパック名として使用されます。アセットパック名の先頭は英字にしてください。その後には、英字、数字、アンダースコアのみ使用できます。
アセットパックのディレクトリに
build.gradle
ファイルを作成し、下記のコードを入力します。アセットパックの名前と、配信タイプを 1 つだけ指定します。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 ]") } }
プロジェクトのアプリの
build.gradle
ファイルで、下記のように、プロジェクト内の各アセットパックの名前を追加します。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") }
次のように、プロジェクトの
settings.gradle
ファイルにプロジェクト内のすべてのアセットパックをインクルードします。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")
アセットパックのディレクトリにサブディレクトリ
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
Gradle を使用して Android App Bundle をビルドします。生成された App Bundle のルートレベルのディレクトリには、以下が含まれるようになりました。
asset-pack-name/manifest/AndroidManifest.xml
: アセットパックの識別子と配信モードを設定しますasset-pack-name/assets/your-asset-directories
: アセットパックの一部として配信されるすべてのアセットを含むディレクトリです
Gradle は各アセットパックのマニフェストを生成し、
assets/
ディレクトリを出力します。(省略可)fast-follow 配信や on-demand 配信を使用する場合は、Play Asset Delivery Library を含めます。
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")
(省略可)さまざまなテクスチャ圧縮形式をサポートするように App Bundle を構成します。
Play Asset Delivery API と統合する
Play Asset Delivery Java API には、アセットパックのリクエスト、ダウンロードの管理、アセットへのアクセスを行うための AssetPackManager
クラスが用意されています。まず、プロジェクトに Play Asset Delivery Library を追加します。
アクセスするアセットパックの配信タイプに応じて、この API を実装します。アセットパックにアクセスする手順を次のフローチャートに示します。
インストール時の配信
install-time
として設定されたアセットパックは、アプリの起動時にすぐに利用できます。このモードで配信されるアセットにアクセスするには、Java AssetManager API を使用します。
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");
fast-follow 配信と on-demand 配信
以下のセクションでは、アセットパックに関する情報をダウンロード前に取得する方法、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
オブジェクトを返す suspend 関数ですが、getPackStates()
は Task<AssetPackStates>
を返す非同期メソッドです。AssetPackStates
オブジェクトの packStates()
メソッドは 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 MB を超えていて、ユーザーが Wi-Fi に接続していない場合、モバイルデータ通信でダウンロードを続行することにユーザーが明示的に同意するまで、ダウンロードは開始されません。同様に、ダウンロードのサイズが大きく、ユーザーの Wi-Fi 接続が切断された場合は、ダウンロードが一時停止され、モバイルデータ接続を使用してダウンロードを続行するにはユーザーの明示的な同意が必要になります。一時停止されたパックは WAITING_FOR_WIFI
の状態になります。ユーザーに同意を求める UI フローをトリガーするには、showConfirmationDialog()
メソッドを使用します。
アプリがこのメソッドを呼び出さなかった場合、ダウンロードは一時停止され、ユーザーの Wi-Fi 接続が回復したときに限り、自動的に再開されます。
ユーザー確認が必要
パックのステータスが REQUIRES_USER_CONFIRMATION
の場合、ユーザーが showConfirmationDialog()
で表示されるダイアログを承認するまで、ダウンロードは開始されません。このステータスは、アプリが 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
ディレクトリに保存されます。assetsPath()
コンビニエンス メソッドを使用して、assets
ディレクトリへのパスを取得できます。特定のアセットへのパスを取得するには、次のメソッドを使用します。
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()
によって返されるマップのエントリは、現在ダウンロードされている最新のパックです。
次のステップ
ローカルおよび Google Play で Play Asset Delivery をテストします。