Asset Delivery 통합(Unity)

에셋 제공을 통합할 때 Unity 게임은 Addressables 또는 AssetBundle을 사용하여 애셋 팩에 액세스할 수 있습니다. Addressables는 Unity 2019.4 및 이후 버전으로 빌드된 게임을 위한 최신 권장 애셋 제공 솔루션인 반면, AssetBundle은 Unity 2017.4 및 2018.4의 애셋 팩을 지원합니다.

Unity Addressable

Unity 2019.4 및 이후 버전으로 빌드된 게임은 Android에서 에셋 제공용으로 Addressables를 사용해야 합니다. Unity는 Addressables를 사용한 Android 애셋 팩을 처리하기 위한 Play Asset Delivery(PAD) API를 제공합니다. Addressables 사용에 관한 자세한 내용은 다음을 참고하세요.

AssetBundle 파일 사용

Unity 2017.4 및 2018.4로 빌드된 게임은 Android에서 애셋 제공용으로 AssetBundle 파일을 사용할 수 있습니다. Unity AssetBundle 파일에는 앱이 실행되는 동안 Unity 엔진에서 로드할 수 있는 직렬화된 애셋이 포함되어 있습니다. 이러한 파일은 플랫폼에 따라 다르며(예: Android용으로 빌드) 애셋 팩과 함께 사용할 수 있습니다. 가장 흔하게 하나의 AssetBundle 파일은 단일 애셋 팩으로 패키징되며, 팩은 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을 범위 지정된 레지스트리로 추가합니다.

    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를 선택하여 패키지 관리자 메뉴를 엽니다.

  4. 관리자 범위 드롭다운을 설정하여 내 레지스트리를 선택합니다.

  5. 패키지 목록에서 Unity용 Google Play 무결성 플러그인 패키지를 선택하고 설치를 누릅니다.

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 ModeInstall 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-followon-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;

대용량 다운로드

용량이 200MB를 초과하는 애셋 팩은 기기가 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;
    }
}

요청 취소(주문형만 해당)

애셋 팩이 다운로드되기 전에 요청을 취소해야 한다면 다음과 같이 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.
}

메모리에 애셋 로드

요청이 완료되면 다음 함수 중 하나를 사용하여 애셋을 메모리에 로드합니다.

비동기식으로 애셋 팩 요청

대부분의 경우 다음과 같이 코루틴을 사용하여 애셋 팩을 비동기식으로 요청하고 진행률을 모니터링해야 합니다.

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 삭제

현재 메모리에 로드되지 않은 빠른 추적 및 주문형 애셋 팩을 삭제할 수 있습니다. 다음 비동기 호출을 실행하고 완료 시의 콜백 메서드를 설정합니다.

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에서 Asset Delivery를 테스트합니다.