アセット配信を統合する(Unity)

アセット送付を統合するときに、Unity ゲームは Addressables または AssetBundle を使ってアセットパックにアクセスできます。Addressables は Unity 2019.4 以降でビルドされたゲーム用に推奨される最新のアセット送付ソリューションで、AssetBundle は Unity 2017.4 および 2018.4 のアセットパックをサポートしています。

Unity Addressables

Unity 2019.4 以降でビルドされたゲームは、Android でのアセット送付に Addressables を使用してください。Unity は Addressables を使用した Android アセットパックの処理用に Play Asset Deliver(PAD)API を用意しています。Addressables の使用について詳細は、以下をご覧ください。

AssetBundle ファイルを使用する

Unity 2017.4 および 2018.4 でビルドされたゲームでは、Android でのアセット送付に AssetBundle ファイルを使用できます。Unity AssetBundle ファイルにはシリアル化されたアセットが含まれており、アプリの実行中に Unity エンジンに読み込めます。これらのファイルはプラットフォーム固有(Android 用など)に作成され、アセットパックと組み合わせて使用できます。ほとんどの場合、1 つの AssetBundle ファイルが 1 つのアセットパックにパッケージ化され、そのアセットパックは AssetBundle と同じ名前を使用します。アセットパックをより柔軟に作成するには、API を使用してアセットパックを設定します。

実行時に、Unity の Play Asset Delivery クラスを使用して、アセットパックにパッケージ化された AssetBundle を取得します。

前提条件

  1. 開発環境を設定する

OpenUPM-CLI

OpenUPM CLI がインストールされている場合は、次のコマンドを使用して OpenUPM レジストリをインストールできます。

openupm add com.google.play.assetdelivery

OpenUPM

  1. Unity のメニュー オプション [Edit] > [Project Settings] > [Package Manager] を選択して、パッケージ マネージャーの設定を開きます。

  2. OpenUPM をスコープ付きレジストリとして Package Manager ウィンドウに追加します。

    Name: package.openupm.com
    URL: https://package.openupm.com
    Scopes: com.google.external-dependency-manager
      com.google.play.common
      com.google.play.core
      com.google.play.assetdelivery
      com.google.android.appbundle
    
  3. Unity のメニュー オプション [Window] > [Package Manager] を選択して、Package Manager メニューを開きます。

  4. マネージャー スコープのプルダウンで [My Registries] を選択します。

  5. パッケージのリストから Google Play Integrity plugin for Unity パッケージを選択し、[Install] を押します。

GitHub からインポート

  1. GitHub から最新の .unitypackage リリースをダウンロードします。

  2. Unity メニュー オプションの [Assets] > [Import Package] > [Custom Package] を選択し、すべてのアイテムをインポートして、.unitypackage ファイルをインポートします。

  1. Unity で AssetBundle を作成します

UI を使用して AssetBundle を設定する

  1. アセットパック内の各 AssetBundle を設定します。

    1. [Google] > [Android App Bundle] > [Asset Delivery Settings] を選択します。
    2. AssetBundle ファイルを直接含むフォルダを選択するために、[Add Folder] をクリックします。

  2. バンドルごとに [Delivery Mode] を [Install Time]、[Fast Follow]、[On Demand] のいずれかに変更します。エラーや依存関係を解決し、ウィンドウを閉じます。

  3. [Google] > [Build Android App Bundle] を選択して App Bundle をビルドします。

  4. (省略可)さまざまなテクスチャ圧縮形式をサポートするように App Bundle を構成します。

API を使用してアセットパックを設定する

自動ビルドシステムの一部として実行できるエディタ スクリプトを使用して Asset Delivery を設定できます。

AssetPackConfig クラスを使用して、Android App Bundle ビルドに含めるアセットと、アセットの配信モードを定義します。これらのアセットパックに AssetBundle を含める必要はありません。

public void ConfigureAssetPacks {
   // Creates an AssetPackConfig with a single asset pack, named
   // examplePackName, containing all the files in path/to/exampleFolder.
   var assetPackConfig = new AssetPackConfig();
   assetPackConfig.AddAssetsFolder("examplePackName",
                                   "path/to/exampleFolder",
                                   AssetPackDeliveryMode.OnDemand);

   // Configures the build system to use the newly created assetPackConfig when
   // calling Google > Build and Run or Google > Build Android App Bundle.
   AssetPackConfigSerializer.SaveConfig(assetPackConfig);

   // Alternatively, use BundleTool.BuildBundle to build an App Bundle from script.
   BuildBundle(new buildPlayerOptions(), assetPackConfig);
}

Bundletool クラスの BuildBundle 静的メソッドを使用し、BuildPlayerOptionsAssetPackConfig に応じて、Android App Bundle とアセットパックを生成します。

ガイド チュートリアルについては、Unity ゲームでの Play Asset Delivery の使用に関する Codelab をご覧ください。

Play Asset Delivery Unity API と統合する

Play Asset Delivery Unity API には、アセットパックのリクエスト、ダウンロードの管理、アセットへのアクセスを行うための機能が用意されています。まずプロジェクトに Unity プラグインを追加してください。

API で使用する関数は、アセットパックの作成方法によって異なります。

プラグイン UI を使用してアセットパックを作成した場合は、プラグイン設定アセットパックを選択してください。

API(またはプラグイン UI)を使用してアセットパックを作成した場合は、API 設定アセットパックを選択してください。

API は、アクセスするアセットパックの配信タイプにかかわらず、ほぼ同じです。アセットパックにアクセスする手順を次のフローチャートに示します。

API によるアセットパックへのアクセスのフロー図

図 1. アセットパックへのアクセスのフロー図

アセットパックを取得する

ディスク上で最新バージョンのアセットパックをまだ利用できない場合は、Play Asset Delivery ライブラリをインポートし、RetrieveAssetPackAsync() メソッドを呼び出してアセットパックをダウンロードします。

using Google.Play.AssetDelivery;

// After download, the assets and/or AssetBundles contained in the asset pack
// are not loaded into memory.
PlayAssetPackRequest request = PlayAssetDelivery.RetrieveAssetPackAsync(assetPackName);

インストール時の配信

install-time として設定されたアセットパックは、アプリの起動時にすぐ利用できますが、アセットをメモリに読み込む必要があります。アセットをメモリに読み込むをご覧ください。

fast-follow 配信と on-demand 配信

以下のセクションは、fast-follow アセットパックと on-demand アセットパックに適用されます。

ステータスを確認する

各アセットパックは、アプリの内部ストレージ内の個別のフォルダに保存されます。アセットパックがすでにダウンロードされて利用可能になっているか、またはエラーが発生したかを判別するには、isDone() メソッドを使用します。

ダウンロードをモニタリングする

リクエストのステータスをモニタリングするには、PlayAssetPackRequest オブジェクトをクエリします。

// Download progress of request, between 0.0f and 1.0f. The value will always be
// 1.0 for assets delivered as install-time.
// NOTE: A value of 1.0 does not mean that the request has completed, only that
// the DOWNLOADING stage is finished.
float progress = request.DownloadProgress;

// Returns the status of the retrieval request.
// If the request completed successfully, this value should be AssetDeliveryStatus.Available.
// If an error occurred, this value should be AssetDeliveryStatus.Failed.

AssetDelivery status = request.Status;
switch(status) {
    case AssetDeliveryStatus.Pending:
        // Asset pack download is pending - N/A for install-time assets.
    case AssetDeliveryStatus.Retrieving:
        // Asset pack is being downloaded and transferred to app storage.
        // N/A for install-time assets.
    case AssetDeliveryStatus.Available:
        // Asset pack is downloaded on disk but NOT loaded into memory.
        // For PlayAssetPackRequest(), this indicates that the request is complete.
    case AssetDeliveryStatus.Failed:
        // Asset pack retrieval failed.
    case AssetDeliveryStatus.WaitingForWifi:
        // Asset pack retrieval paused until either the device connects via Wi-Fi,
        // or the user accepts the PlayAssetDelivery.ShowConfirmationDialog dialog.
    case AssetDeliveryStatus.RequiresUserConfirmation:
        // Asset pack retrieval paused until the user accepts the
        // PlayAssetDelivery.ShowConfirmationDialog dialog.
    default:
        break;
}

// Returns true if status is AssetDeliveryStatus.Available or AssetDeliveryStatus.Failed.
bool done = request.IsDone;

// If AssetDeliveryStatus.Failed, find more info about the error.
AssetDeliveryErrorCode error = request.Error;

大規模なダウンロード

200 MB を超えるアセットパックは、デバイスが Wi-Fi に接続されている場合にのみ、自動でダウンロードできます。ユーザーが Wi-Fi に接続していない場合、PlayAssetPackRequest ステータスは AssetDeliveryStatus.WaitingForWifi に設定され、ダウンロードは一時停止されます。この場合は、デバイスが Wi-Fi に接続されるのを待ってダウンロードを再開するか、またはモバイル接続でパックをダウンロードするための承認をユーザーに求めます。

ユーザー確認が必要

パックのステータスが AssetDeliveryStatus.RequiresUserConfirmation の場合、PlayAssetDelivery.ShowConfirmationDialog() とともに表示されるダイアログをユーザーが承認するまで、ダウンロードは開始されません。このステータスは、アプリが Play で認識されていない場合に発生することがあります。この場合、PlayAssetDelivery.ShowConfirmationDialog() を呼び出すとアプリが更新されます。更新後、アセットを再度リクエストします。

if(request.Status == AssetDeliveryStatus.RequiresUserConfirmation
   || request.Status == AssetDeliveryStatus.WaitingForWifi) {
    var userConfirmationOperation = PlayAssetDelivery.ShowConfirmationDialog();
    yield return userConfirmationOperation;

    switch(userConfirmationOperation.GetResult()) {
        case ConfirmationDialogResult.Unknown:
            // userConfirmationOperation finished with an error. Something went
            // wrong when displaying the prompt to the user, and they weren't
            // able to interact with the dialog.
        case ConfirmationDialogResult.Accepted:
            // User accepted the confirmation dialog--an update will start.
        case ConfirmationDialogResult.Declined:
            // User canceled or declined the dialog. It can be shown again.
        default:
            break;
    }
}

リクエストをキャンセルする(on-demand のみ)

アセットパックがダウンロードされる前にリクエストをキャンセルする必要がある場合は、PlayAssetPackRequest オブジェクトの AttemptCancel() メソッドを呼び出します。

// Will only attempt if the status is Pending, Retrieving, or Available; otherwise
// it will be a no-op.
request.AttemptCancel();

// Check to see if the request was successful by checking if the error code is Canceled.
if(request.Error == AssetDeliveryErrorCode.Canceled) {
    // Request was successfully canceled.
}

アセットをメモリに読み込む

リクエストが完了したら、次のいずれかの関数を使用してアセットをメモリに読み込みます。

  • PlayAssetPackRequest.GetAssetLocation() を使用して AssetLocation オブジェクトを取得します。このオブジェクトにより、ディスクからアセットを読み込むためのアセットのパス、オフセット、サイズが提供されます。
  • アセットが AssetBundle である場合は、PlayAssetPackRequest.LoadAssetBundleAsync(assetPath) コンビニエンス メソッドを使用できます。メソッドに渡すアセットパスは、アセットパック内の AssetBundle へのパスに対応している必要があります。これにより、AssetBundleCreateRequest が返されます。

非同期でアセットパックをリクエストする

ほとんどの場合、コルーチンを使用して非同期でアセットパックをリクエストし、進行状況をモニタリングする必要があります。以下をご覧ください。

private IEnumerator LoadAssetPackCoroutine(string assetPackName) {

    PlayAssetPackRequest request =
        PlayAssetDelivery.RetrieveAssetPackAsync(assetPackName);

    while (!request.IsDone) {
        if(request.Status == AssetDeliveryStatus.WaitingForWifi) {
            var userConfirmationOperation = PlayAssetDelivery.ShowConfirmationDialog();

            // Wait for confirmation dialog action.
            yield return userConfirmationOperation;

            if((userConfirmationOperation.Error != AssetDeliveryErrorCode.NoError) ||
               (userConfirmationOperation.GetResult() != ConfirmationDialogResult.Accepted)) {
                // The user did not accept the confirmation. Handle as needed.
            }

            // Wait for Wi-Fi connection OR confirmation dialog acceptance before moving on.
            yield return new WaitUntil(() => request.Status != AssetDeliveryStatus.WaitingForWifi);
        }

        // Use request.DownloadProgress to track download progress.
        // Use request.Status to track the status of request.

        yield return null;
    }

    if (request.Error != AssetDeliveryErrorCode.NoError) {
        // There was an error retrieving the pack. For error codes NetworkError
        // and InsufficientStorage, you may prompt the user to check their
        // connection settings or check their storage space, respectively, then
        // try again.
        yield return null;
    }

    // Request was successful. Load the asset pack into memory.
    AssetBundleCreateRequest assetBundleCreateRequest = request.LoadAssetBundleAsync(path/to/exampleBundle);
    yield return assetBundleCreateRequest;
    AssetBundle assetBundle = assetBundleCreateRequest.assetBundle;

エラー処理の詳細については、エラーコードのリストをご覧ください。

その他の Play Core API メソッド

アプリで使用できるその他の API メソッドを次にいくつか示します。

複数のアセットパックを取得する

一度に複数のアセットパックを取得するには、次の関数を使用します。

// assetPackNames is an array of strings corresponding to asset packs.
PlayAssetPackBatchRequest batchRequest = PlayAssetDelivery.RetrieveAssetPackBatchAsync(<IListstring> assetPackNames);

個別のリクエストのステータスをモニタリングするには、状態の Dictionary を調べます。

// Dictionary of AssetPackStates, with the asset pack name as the key.
Dictionary<string, PlayAssetPackRequest> requests = batchRequest.Requests;

// Returns true if all requests are complete.
bool requestComplete = batchRequest.IsDone;

ダウンロード サイズを確認する

アセットパックのサイズを確認するには、Google Play に対して非同期呼び出しを行い、オペレーションが完了したときのコールバック メソッドを設定します。

public IEnumerator GetDownloadSize() {
   PlayAsyncOperation<long> getSizeOperation =
   PlayAssetDelivery.GetDownloadSize(assetPackName);

   yield return getSizeOperation;
   if(operation.Error != AssetDeliveryErrorCode.NoError) {
       // Error while retrieving download size.
    } else {
        // Download size is given in bytes.
        long downloadSize = operation.GetResult();
    }
}

AssetBundle を削除する

メモリに現在読み込まれていない fast-follow アセットパックと on-demand アセットパックは削除できます。次の非同期呼び出しを行い、呼び出しが完了したときのコールバック メソッドを設定します。

PlayAsyncOperation<string> removeOperation = PlayAssetDelivery.RemoveAssetPack(assetBundleName);

removeOperation.Completed += (operation) =>
            {
                if(operation.Error != AssetDeliveryErrorCode.NoError) {
                    // Error while attempting to remove AssetBundles.
                } else {
                    // Files were deleted OR files did not exist to begin with.
                }
            };

次のステップ

ローカルおよび Google Play でアセット配信をテストします。