Tích hợp phân phối thành phần (Unity)

Khi tích hợp tính năng phân phối thành phần, trò chơi Unity có thể truy cập vào các gói thành phần bằng cách sử dụng Addressable hoặc AssetBundle. Addressable là giải pháp phân phối thành phần mới và được đề xuất cho trò chơi được xây dựng bằng Unity 2019.4 trở lên, trong khi đó AssetBundle hỗ trợ các gói thành phần trong Unity 2017.4 và 2018.4.

Addressable của Unity

Các trò chơi được xây dựng bằng Unity 2019.4 trở lên nên sử dụng Addressable để phân phối thành phần trên Android. Unity cung cấp Play Asset Delivery (PAD) API để xử lý các gói thành phần Android bằng Addressable. Để biết thông tin về cách sử dụng Addressable, hãy xem:

Sử dụng tệp AssetBundle

Các trò chơi được xây dựng bằng Unity 2017.4 và 2018.4 có thể sử dụng các tệp AssetBundle để phân phối thành phần trên Android. Các tệp AssetBundle chứa thành phần nối tiếp được tải bằng công cụ Unity khi ứng dụng đang chạy. Các tệp này dành riêng cho nền tảng (ví dụ: được tạo dành cho Android) và có thể sử dụng kết hợp với gói thành phần. Trường hợp phổ biến nhất là một tệp AssetBundle được đóng gói thành gói thành phần duy nhất, đồng thời cũng lấy tên là AssetBundle. Nếu muốn linh hoạt hơn trong việc tạo gói thành phần, hãy định cấu hình gói thành phần đó bằng cách sử dụng API.

Khi chạy, hãy sử dụng lớp Play Asset Delivery cho Unity để truy xuất gói AssetBundle đã đóng trong gói thành phần.

Điều kiện tiên quyết

  1. Tải bản phát hành mới nhất của Play Asset Delivery Unity Plugin từ các gói Google dành cho Unity.

  2. Tạo AssetBundles trong Unity.

Sử dụng giao diện người dùng để định cấu hình AssetBundle

  1. Định cấu hình từng AssetBundle trong gói thành phần:

    1. Chọn Google > Android App Bundle > Cài đặt phân phối nội dung.
    2. Để chọn thư mục chứa trực tiếp tệp AssetBundle, nhấp vào Thêm thư mục.

  2. Đối với mỗi gói, hãy thay đổi Chế độ phân phối thành Thời gian cài đặt, Theo dõi nhanh hoặc Theo yêu cầu. Giải quyết lỗi hoặc phần phụ thuộc và đóng cửa sổ.

  3. Chọn Google > Tạo Android App Bundle để tạo gói ứng dụng.

  4. (Không bắt buộc) Định cấu hình gói ứng dụng để hỗ trợ nhiều định dạng nén kết cấu.

Định cấu hình gói thành phần bằng API

Có thể định cấu hình phân phối nội dung qua tập lệnh trình chỉnh sửa. Tập lệnh này chạy như một phần của hệ thống xây dựng tự động.

Sử dụng lớp AssetPackConfig để xác định những thành phần cần đưa vào bản dựng Android App Bundle cũng như chế độ phân phối của thành phần đó. Các gói thành phần này không cần chứa 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);
}

Ngoài ra, bạn còn có thể sử dụng phương thức tĩnh BuildBundle trong lớp Bundletool để tạo Android App Bundle với gói thành phần, BuildPlayerOptionsAssetPackConfig.

Để tham khảo hướng dẫn từng bước, hãy xem nội dung Sử dụng Play Asset Delivery trong Lớp học lập trình trò chơi Unity.

Tích hợp với API Unity Play Asset Delivery

API Unity Play Asset Delivery cung cấp chức năng yêu cầu gói thành phần, quản lý tài nguyên tải xuống và truy cập thành phần. Trước tiên, hãy nhớ Thêm trình bổ trợ Unity vào dự án.

Hàm sử dụng trong API tuỳ thuộc vào cách bạn tạo các gói thành phần.

Nếu bạn đã sử dụng trình bổ trợ giao diện người dùng tạo gói thành phần, hãy chọn Gói thành phần được định cấu hình trình bổ trợ.

Nếu bạn đã dùng API (hoặc trình bổ trợ giao diện người dùng) để tạo gói thành phần, hãy chọn Gói thành phần được định cấu hình API.

Bạn triển khai API này theo loại hình phân phối của gói thành phần mà bạn muốn truy cập. Các bước này được thể hiện trong sơ đồ quy trình sau.

Sơ đồ quy trình gói thành phần cho trình bổ trợ

Hình 1. Sơ đồ quy trình truy cập gói thành phần

Truy xuất AssetBundle

Nhập thư viện Play Asset Delivery và gọi phương thức RetrieveAssetBundleAsync() để truy xuất AssetBundle.

using Google.Play.AssetDelivery;

// Loads the AssetBundle from disk, downloading the asset pack containing it if necessary.
PlayAssetBundleRequest bundleRequest = PlayAssetDelivery.RetrieveAssetBundleAsync(asset-bundle-name);

Phân phối khi cài đặt

Các gói thành phần được định cấu hình là install-time sẽ có sẵn ngay khi khởi chạy ứng dụng. Bạn có thể sử dụng các nội dung sau để tải một cảnh trích từ AssetBundle:

AssetBundle assetBundle = bundleRequest.AssetBundle;

// You may choose to load scenes from the AssetBundle. For example:
string[] scenePaths = assetBundle.GetAllScenePaths();
SceneManager.LoadScene(scenePaths[path-index]);

Phân phối tiếp nối nhanh và theo yêu cầu

Phần này áp dụng cho các gói thành phần fast-followon-demand.

Kiểm tra trạng thái

Mỗi gói thành phần được lưu trữ trong một thư mục riêng ở bộ nhớ trong của ứng dụng. Sử dụng phương thức isDownloaded() để xác định xem gói thành phần đã được tải xuống hay chưa.

Theo dõi việc tải xuống

Truy vấn đối tượng PlayAssetBundleRequest để theo dõi trạng thái của yêu cầu:

// 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 will only signify the download is complete. It will still need to be loaded.
float progress = bundleRequest.DownloadProgress;

// Returns true if:
//   * it had either completed the download, installing, and loading of the AssetBundle,
//   * OR if it has encountered an error.
bool done = bundleRequest.IsDone;

// Returns status of retrieval request.
AssetDeliveryStatus status = bundleRequest.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.Loading:
        // Asset pack is being loaded.
    case AssetDeliveryStatus.Loaded:
        // Asset pack has finished loading, assets can now be loaded.
        // For PlayAssetBundleRequest(), this indicates that the request is complete.
    case AssetDeliveryStatus.Failed:
        // Asset pack retrieval has 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;
}

Tài nguyên tải xuống kích thước lớn

Gói tài sản lớn hơn 200 MB có thể tự động tải xuống, nhưng chỉ qua Wi-Fi. Nếu người dùng không sử dụng Wi-Fi, trạng thái PlayAssetBundleRequest sẽ được đặt thành AssetDeliveryStatus.WaitingForWifi và tải xuống sẽ bị tạm dừng. Trong trường hợp đó, hãy đợi đến khi thiết bị kết nối với Wi-Fi, tiếp tục tải xuống hoặc nhắc người dùng chấp thuận để tải gói xuống qua một kết nối di động.

Người dùng cần xác nhận

Nếu một gói có trạng thái AssetDeliveryStatus.RequiresUserConfirmation, thì quá trình tải xuống sẽ không tiếp tục cho đến khi người dùng chấp nhận hộp thoại hiển thị bằng PlayAssetDelivery.ShowConfirmationDialog(). Trạng thái này có thể xuất hiện nếu Play không nhận dạng được ứng dụng. Lưu ý rằng trong trường hợp này, việc gọi PlayAssetDelivery.ShowConfirmationDialog() sẽ khiến ứng dụng được cập nhật. Sau khi cập nhật, hãy yêu cầu lại thành phần.

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;
    }
}

Huỷ yêu cầu (chỉ theo yêu cầu)

Nếu bạn cần huỷ yêu cầu trước khi AssetBundles được tải vào bộ nhớ, hãy gọi phương thức AttemptCancel() trên đối tượng PlayAssetBundleRequest

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

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

Yêu cầu gói thành phần theo cách không đồng bộ

Trong hầu hết trường hợp, bạn nên sử dụng Coroutine để yêu cầu gói thành phần theo cách không đồng bộ và theo dõi tiến trình như sau:

private IEnumerator LoadAssetBundleCoroutine(string assetBundleName) {

    PlayAssetBundleRequest bundleRequest =
        PlayAssetDelivery.RetrieveAssetBundleAsync(assetBundleName);

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

            // 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(() => bundleRequest.Status != AssetDeliveryStatus.WaitingForWifi);
        }

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

        yield return null;
    }

    if (bundleRequest.Error != AssetDeliveryErrorCode.NoError) {
        // There was an error retrieving the bundle. 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. Retrieve AssetBundle from request.AssetBundle.
    AssetBundle assetBundle = bundleRequest.AssetBundle;

Để biết thêm thông tin về cách xử lý lỗi, hãy xem danh sách AssetDeliveryErrorCodes.

Các phương thức Play Core API khác

Sau đây là một số phương thức API khác mà có thể bạn muốn sử dụng trong ứng dụng.

Kiểm tra kích thước tải xuống

Kiểm tra kích thước của AssetBundle bằng cách thực hiện lệnh gọi không đồng bộ đến Google Play và đặt phương thức gọi lại khi hoạt động hoàn tất:

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();
    }
}

Xoá AssetBundle

Bạn có thể xoá các AssetBundles theo dõi nhanh và theo yêu cầu hiện không tải trong bộ nhớ. Hãy thực hiện lệnh gọi không đồng bộ sau và đặt phương thức gọi lại khi hoàn tất:

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.
                }
            };

Các bước tiếp theo

Thử nghiệm việc phân phối thành phần trên thiết bị và trên Google Play.