Hỗ trợ cập nhật trong ứng dụng (Gốc)

Stay organized with collections Save and categorize content based on your preferences.

Hướng dẫn này mô tả cách hỗ trợ các bản cập nhật trong ứng dụng trên ứng dụng của bạn sử dụng mã gốc (C hoặc C++). Chúng tôi có hướng dẫn riêng cho các trường hợp trong đó quy trình triển khai sử dụng ngôn ngữ lập trình Kotlin hoặc ngôn ngữ lập trình Java cũng như các trường hợp có quy trình triển khai sử dụng hàm Unity ,

Tổng quan về SDK gốc (native SDK)

SDK gốc của Play Core nằm trong nhóm SDK của Play Core. SDK gốc có một tệp tiêu đề C, app_update.h, gói AppUpdateManager từ Thư viện bản cập nhật trong ứng dụng của Java Play. Tệp tiêu đề này cho phép ứng dụng của bạn gọi API để cập nhật trực tiếp trong ứng dụng từ mã gốc.

Thiết lập môi trường phát triển

Download Play Core Native SDK

Before downloading, you must agree to the following terms and conditions.

Terms and Conditions

Sửa đổi lần cuối: ngày 24 tháng Chín năm 2020
  1. Bằng việc sử dụng Bộ công cụ phát triển phần mềm Play Core, bạn đồng ý với các điều khoản này ngoài Điều khoản dịch vụ API của Google ("API ToS"). Nếu các điều khoản này xung đột nhau, các điều khoản này sẽ được ưu tiên áp dụng hơn Điều khoản dịch vụ API. Vui lòng đọc kỹ các điều khoản này và Điều khoản dịch vụ API.
  2. Trong phạm vi các điều khoản này, "API" có nghĩa là API của Google, các dịch vụ dành cho nhà phát triển và phần mềm liên kết khác, gồm cả Mã có thể phân phối lại.
  3. “Mã có thể phân phối lại” có nghĩa là mã đối tượng hoặc tệp tiêu đề do Google cung cấp có gọi đến API.
  4. Theo các điều khoản này và các điều khoản của Điều khoản dịch vụ API, bạn chỉ được sao chép và phân phối Mã có thể phân phối lại để đưa vào Ứng dụng API khách của mình. Google và người cấp phép của Google sở hữu tất cả quyền, quyền sở hữu và lợi ích, bao gồm mọi tài sản sở hữu trí tuệ cũng như các quyền sở hữu riêng khác nằm trong và đối với Mã có thể phân phối lại. Bạn không được sửa đổi, dịch hoặc tạo tác phẩm phái sinh của Mã có thể phân phối lại.
  5. Google có thể thay đổi các điều khoản này bất cứ lúc nào và sẽ đưa ra thông báo, đồng thời cho phép bạn lựa chọn ngừng sử dụng Bộ công cụ phát triển phần mềm Play Core. Google sẽ đăng thông báo về các điều khoản sửa đổi tại https://developer.android.com/guide/playcore/license. Nội dung thay đổi sẽ không có hiệu lực hồi tố.
Download Play Core Native SDK

play-core-native-sdk-1.11.0.zip

  1. Thực hiện một trong hai cách sau:

    • Cài đặt Android Studio phiên bản 4.0 trở lên. Sử dụng giao diện người dùng Trình quản lý SDK để cài đặt Nền tảng SDK Android phiên bản 10.0 (API cấp độ 29).
    • Cài đặt các công cụ dòng lệnh của SDK Android và sử dụng sdkmanager để cài đặt Nền tảng SDK Android phiên bản 10.0 (API cấp độ 29).
  2. Chuẩn bị Android Studio cho phát triển gốc bằng cách sử dụng Trình quản lý SDK để cài đặt CMake và Công cụ phát triển gốc Android (NDK) mới nhất. Để biết thêm thông tin về việc tạo hoặc nhập các dự án gốc, xem Bắt đầu với NDK.

  3. Tải tệp zip xuống và giải nén cùng dự án của bạn.

    Đường liên kết để tải xuống Kích thước Giá trị tổng kiểm SHA-256
    55.6 MB 058b4069f09714da938656d43b6dc28d3bc6f821c9d406e9c96a1c3af014dc45
  4. Cập nhật tệp build.gradle của ứng dụng như minh họa dưới đây:

    Groovy

        // App build.gradle
    
        plugins {
          id 'com.android.application'
        }
    
        // Define a path to the extracted Play Core SDK files.
        // If using a relative path, wrap it with file() since CMake requires absolute paths.
        def playcoreDir = file('../path/to/playcore-native-sdk')
    
        android {
            defaultConfig {
                ...
                externalNativeBuild {
                    cmake {
                        // Define the PLAYCORE_LOCATION directive.
                        arguments "-DANDROID_STL=c++_static",
                                  "-DPLAYCORE_LOCATION=$playcoreDir"
                    }
                }
                ndk {
                    // Skip deprecated ABIs. Only required when using NDK 16 or earlier.
                    abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
                }
            }
            buildTypes {
                release {
                    // Include Play Core Library proguard config files to strip unused code while retaining the Java symbols needed for JNI.
                    proguardFile "$playcoreDir/proguard/common.pgcfg"
                    proguardFile "$playcoreDir/proguard/per-feature-proguard-files"
                    ...
                }
                debug {
                    ...
                }
            }
            externalNativeBuild {
                cmake {
                    path 'src/main/CMakeLists.txt'
                }
            }
        }
    
        dependencies {
            // Use the Play Core AAR included with the SDK.
            implementation files("$playcoreDir/playcore.aar")
    
            // Use the following dependency for the Play Integrity API.
            implementation("com.google.android.play:integrity:1.0.0")
            ...
        }
        

    Kotlin

    // App build.gradle
    
    plugins {
        id("com.android.application")
    }
    
    // Define a path to the extracted Play Core SDK files.
    // If using a relative path, wrap it with file() since CMake requires absolute paths.
    val playcoreDir = file("../path/to/playcore-native-sdk")
    
    android {
        defaultConfig {
            ...
            externalNativeBuild {
                cmake {
                    // Define the PLAYCORE_LOCATION directive.
                    arguments += listOf("-DANDROID_STL=c++_static", "-DPLAYCORE_LOCATION=$playcoreDir")
                }
            }
            ndk {
                // Skip deprecated ABIs. Only required when using NDK 16 or earlier.
                abiFilters.clear()
                abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
            }
        }
        buildTypes {
            release {
                // Include Play Core Library proguard config files to strip unused code while retaining the Java symbols needed for JNI.
                proguardFile("$playcoreDir/proguard/common.pgcfg")
                proguardFile("$playcoreDir/proguard/per-feature-proguard-files")
                ...
            }
            debug {
                ...
            }
        }
        externalNativeBuild {
            cmake {
                path = "src/main/CMakeLists.txt"
            }
        }
    }
    
    dependencies {
        // Use the Play Core AAR included with the SDK.
        implementation(files("$playcoreDir/playcore.aar"))
        ...
    }
    
  5. Cập nhật các tệp CMakeLists.txt của ứng dụng như hình ảnh bên dưới:

    cmake_minimum_required(VERSION 3.6)
    
    ...
    
    # Add a static library called “playcore” built with the c++_static STL.
    include(${PLAYCORE_LOCATION}/playcore.cmake)
    add_playcore_static_library()
    
    // In this example “main” is your native code library, i.e. libmain.so.
    add_library(main SHARED
            ...)
    
    target_include_directories(main PRIVATE
            ${PLAYCORE_LOCATION}/include
            ...)
    
    target_link_libraries(main
            android
            playcore
            ...)
    

Sau khi bạn tích hợp SDK Gốc của Play Core vào dự án của mình, hãy đưa dòng sau vào các tệp chứa lệnh gọi API:

#include "play/app_update.h"

Khởi chạy cập nhật API trong ứng dụng

Bất cứ khi nào bạn sử dụng API cập nhật trong ứng dụng, trước tiên hãy khởi chạy API bằng cách gọi hàm AppUpdateManager_init() như hiển thị trong ví dụ sau được tạo bằng android_native_app_glue.h

void android_main(android_app* app) {
  app->onInputEvent = HandleInputEvent;

  AppUpdateErrorCode error_code =
    AppUpdateManager_init(app->activity->vm, app->activity->clazz);
  if (error_code == APP_UPDATE_NO_ERROR) {
    // You can use the API.
  }
}

Kiểm tra xem có bản cập nhật chưa

Trước khi yêu cầu cập nhật, hãy kiểm tra xem có bản cập nhật cho ứng dụng của bạn hay không. AppUpdateManager_requestInfo() sẽ bắt đầu một yêu cầu không đồng bộ, thu thập thông tin cần thiết để khởi chạy quy trình (flow) cập nhật trong ứng dụng vào lúc khác. Hàm trả về APP_UPDATE_NO_ERROR nếu yêu cầu khởi chạy thành công.

AppUpdateErrorCode error_code = AppUpdateManager_requestInfo()

if (error_code == APP_UPDATE_NO_ERROR) {
    // The request has successfully started, check the result using
    // AppUpdateManager_getInfo.
}

Bạn có thể theo dõi tiến trình và kết quả của yêu cầu bằng cách sử dụng AppUpdateManager_getInfo(). Ngoài mã lỗi, hàm này còn trả về một cấu trúc mờ AppUpdateInfo mà bạn có thể sử dụng để truy xuất thông tin về yêu cầu cập nhật. Ví dụ: bạn có thể muốn gọi hàm này trong mọi vòng lặp trò chơi cho đến khi hàm trả về kết quả không rỗng cho info:

AppUpdateInfo* info;
GameUpdate() {

   // Keep calling this in every game loop until info != nullptr
   AppUpdateErrorCode error_code = AppUpdateManager_getInfo(&info);

   if (error_code == APP_UPDATE_NO_ERROR && info != nullptr) {
       // Successfully started, check the result in the following functions
   }
...
}

Kiểm tra tình trạng lỗi thời của bản cập nhật

Ngoài việc kiểm tra xem có bản cập nhật hay chưa, bạn cũng nên kiểm tra thời gian đã trôi qua kể từ khi người dùng nhận được thông báo gần nhất về bản cập nhật thông qua Cửa hàng Play. Điều này có thể giúp bạn quyết định xem nên tiến hành cập nhật linh hoạt hay cập nhật ngay. Ví dụ: bạn có thể chờ một vài ngày trước khi thông báo cho người dùng về bản cập nhật linh hoạt và vài ngày sau đó mới yêu cầu cập nhật ngay.

Sử dụng AppUpdateInfo_getClientVersionStalenessDays() để kiểm tra số ngày kể từ khi bản cập nhật có trên Cửa hàng Play:

int32_t staleness_days = AppUpdateInfo_getClientVersionStalenessDays(info);

Kiểm tra mức độ ưu tiên của bản cập nhật

API Nhà phát triển Google Play cho phép bạn thiết lập mức độ ưu tiên của mỗi bản cập nhật. Điều này cho phép ứng dụng của bạn quyết định mức độ đề xuất bản cập nhật cho người dùng. Ví dụ: hãy xem xét chiến lược đặt mức độ ưu tiên cập nhật sau đây:

  • Cải tiến nhỏ về giao diện người dùng: Bản cập nhật ưu tiên thấp; không yêu cầu cập nhật linh hoạt cũng như cập nhật tức thì. Chỉ cập nhật khi người dùng không tương tác với ứng dụng.
  • Cải thiện hiệu suất: Cập nhật có mức độ ưu tiên trung bình; yêu cầu cập nhật linh hoạt.
  • Cập nhật bảo mật quan trọng: Cập nhật có mức độ ưu tiên cao; yêu cầu cập nhật ngay.

Để xác định mức độ ưu tiên, Google Play sử dụng giá trị số nguyên từ 0 đến 5, trong đó 0 là giá trị mặc định và 5 là mức độ ưu tiên cao nhất. Để đặt mức độ ưu tiên cho một bản cập nhật, hãy sử dụng trường inAppUpdatePriority trong Edits.tracks.releases trong API nhà phát triển Google Play. Tất cả các phiên bản mới thêm trong bản phát hành này đều có cùng mức độ ưu tiên với bản phát hành. Bạn chỉ có thể đặt mức độ ưu tiên khi ra mắt bản phát hành mới và không thể thay đổi sau này.

Đặt mức độ ưu tiên bằng cách sử dụng API Nhà phát triển Google Play như mô tả trong tài liệu về API Nhà phát triển Play. Chỉ định mức độ ưu tiên của bản cập nhật ứng dụng trong tài nguyên Edit.tracksđược chuyển trong phương thức Edit.tracks: update. Ví dụ sau minh họa việc phát hành một ứng dụng có mã phiên bản 88 và inAppUpdatePriority 5:

{
  "releases": [{
      "versionCodes": ["88"],
      "inAppUpdatePriority": 5,
      "status": "completed"
  }]
}

Trong mã của ứng dụng, bạn có thể kiểm tra mức độ ưu tiên của một bản cập nhật cụ thể bằng cách sử dụng AppUpdateInfo_getPriority():

int32_t priority = AppUpdateInfo_getPriority(info);

Bắt đầu cập nhật

Sau khi xác nhận đã có bản cập nhật, bạn có thể yêu cầu cập nhật bằng AppUpdateManager_requestStartUpdate(): Trước khi yêu cầu cập nhật, hãy lấy đối tượng AppUpdateInfo mới nhất và tạo đối tượng AppUpdateOptions để định cấu hình quy trình cập nhật. Đối tượng AppUpdateOptions xác định các tùy chọn cho quy trình cập nhật trong ứng dụng, bao gồm cả việc nên cập nhật linh hoạt hay ngay lập tức.

Ví dụ sau đây sẽ tạo một đối tượng AppUpdateOptions cho quy trình cập nhật linh hoạt:

// Creates an AppUpdateOptions configuring a flexible in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_FLEXIBLE, &options);

Ví dụ sau đây sẽ tạo một đối tượng AppUpdateOptions cho quy trình cập nhật ngay:

// Creates an AppUpdateOptions configuring an immediate in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_IMMEDIATE, &options);

Đối tượng AppUpdateOptions cũng chứa trường AllowAssetPackDeletion xác định liệu quá trình cập nhật có được phép xóa các gói tài sản trong trường hợp bộ nhớ thiết bị hạn chế hay không. Trường này được đặt thành false theo mặc định, nhưng bạn có thể sử dụng phương thức AppUpdateOptions_setAssetPackDeletionAllowed()để đặt thành true:

bool allow = true;
AppUpdateErrorCode error_code = AppUpdateOptions_setAssetPackDeletionAllowed(options, allow);

Sau khi có đối tượng AppUpdateInfo cập nhật và đối tượng AppUpdateOptions được định cấu hình đúng cách, hãy gọi AppUpdateManager_requestStartUpdate() để yêu cầu không đồng bộ quy trình cập nhật, chuyển vào Hoạt động Android jobject để có thông số cuối cùng.

AppUpdateErrorCode request_error_code =
AppUpdateManager_requestStartUpdate(info, options, app->activity->clazz);

Để giải phóng tài nguyên, hãy hủy bỏ các bản sao của AppUpdateInfoAppUpdateOptions mà bạn không cần nữa bằng cách gọi lần lượt AppUpdateInfo_destroy()AppUpdateOptions_destroy().

AppUpdateInfo_destroy(info);
AppUpdateOptions_destroy(options);

Đối với quy trình cập nhật ngay, Google Play sẽ hiện trang yêu cầu người dùng xác nhận. Khi người dùng chấp nhận yêu cầu, Google Play sẽ tự động tải xuống và cài đặt bản cập nhật ở nền trước, sau đó khởi động lại ứng dụng với phiên bản đã cập nhật nếu quá trình cài đặt thành công.

Để có quy trình cập nhật linh hoạt, bạn có thể tiếp tục yêu cầu đối tượng AppUpdateInfo cập nhật để theo dõi trạng thái cập nhật hiện tại trong khi người dùng tiếp tục tương tác với ứng dụng. Sau khi tải xuống thành công, bạn phải kích hoạt việc hoàn tất cập nhật bằng cách gọi AppUpdateManager_requestCompleteUpdate() như trong ví dụ sau:

AppUpdateStatus status = AppUpdateInfo_getStatus(info);
if (status == APP_UPDATE_DOWNLOADED) {
    AppUpdateErrorCode error_code = AppUpdateManager_requestCompleteUpdate();
    if (error_code != APP_UPDATE_NO_ERROR)
    {
      // There was an error while completing the update flow.
    }
}

Giải phóng tài nguyên bằng cách gọi hàm AppUpdateManager_destroy() sau khi ứng dụng của bạn sử dụng xong API.

Xử lý lỗi

Phần này mô tả giải pháp cho các lỗi phổ biến được biểu thị bằng các giá trị AppUpdateErrorCode cụ thể:

  • Mã lỗi -110, APP_UPDATE_INITIALIZATION_NEEDED cho biết API chưa được khởi chạy thành công. Gọi AppUpdateManager_init() để khởi chạy API.
  • Mã lỗi -4, APP_UPDATE_INVALID_REQUEST đã chỉ ra một số tham số của yêu cầu luồng cập nhật không đúng định dạng. Kiểm tra để đảm bảo các đối tượng AppUpdateInfoAppUpdateOptions không rỗng và được định dạng đúng.
  • Mã lỗi -5, APP_UPDATE_UNAVAILABLE cho biết không có bản cập nhật hiện hành nào. Đảm bảo phiên bản đích có cùng tên gói, ID ứng dụngkhóa ký. Nếu có bản cập nhật, hãy xóa bộ nhớ đệm của ứng dụng và gọi lại AppUpdateManager_requestAppUpdateInfo() để làm mới AppUpdateInfo.
  • Mã lỗi -6, APP_UPDATE_NOT_ALLOWED cho biết loại cập nhật do đối tượng AppUpdateOption biểu thị là không được phép. Kiểm tra xem đối tượng AppUpdateInfo có cho biết liệu loại cập nhật có được cho phép hay không trước khi bắt đầu quy trình cập nhật.

Các bước tiếp theo

Kiểm thử bản cập nhật trong ứng dụng của ứng dụng để xác minh quá trình tích hợp của bạn đang hoạt động chính xác.