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.

API tương tự nhau bất kể bạn muốn truy cập loại phân phối nào của gói thành phần. Các bước này được thể hiện trong sơ đồ quy trình sau đây.

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

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

Truy xuất gói thành phần

Nhập thư viện Play Asset Delivery và gọi phương thức RetrieveAssetPackAsync() để tải gói thành phần xuống nếu phiên bản mới nhất chưa có sẵn trên đĩa.

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

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

Một gói thành phần được định cấu hình install-time sẽ có sẵn ngay khi khởi chạy ứng dụng, nhưng cần tải thành phần của gói đó vào bộ nhớ. Xem Tải thành phần vào bộ nhớ.

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 isDone() để xác định xem gói nội dung đã được tải xuống và có sẵn chưa hay đã xảy ra lỗi.

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

Truy vấn đối tượng PlayAssetPackRequest để 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 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;

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ỉ khi thiết bị được kết nối với Wi-Fi. Nếu người dùng không sử dụng Wi-Fi, trạng thái PlayAssetPackRequest được đặt là AssetDeliveryStatus.WaitingForWifi và tệp 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 tải các gói thành phần xuống, hãy gọi phương thức AttemptCancel() trên đối tượng PlayAssetPackRequest:

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

Tải thành phần vào bộ nhớ

Sau khi yêu cầu hoàn tất, sử dụng một trong các hàm sau để tải nội dung vào bộ nhớ:

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

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

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.

Truy xuất nhiều gói thành phần

Để truy xuất nhiều gói thành phần cùng lúc, hãy sử dụng chức năng sau:

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

Theo dõi trạng thái của từng yêu cầu bằng cách kiểm tra Dictionary tiểu bang:

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

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

Kiểm tra kích thước một gói thành phần bằng cách thực hiện lệnh gọi không đồng bộ đến Google Play và thiết lập phương thức gọi lại khi thao tác này 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á gói thành phần theo dõi nhanh và theo yêu cầu hiện chưa tải vào 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.