รองรับการอัปเดตในแอป (เนทีฟ)

คู่มือนี้อธิบายวิธีรองรับการอัปเดตในแอปในแอปโดยใช้โค้ดเนทีฟ (C หรือ C++) เรามีคู่มือแยกต่างหากสำหรับกรณีที่การใช้งานใช้ภาษาโปรแกรม Kotlin หรือภาษาโปรแกรม Java และกรณีที่การใช้งานใช้ Unity

ภาพรวมของ Native SDK

Play Core Native SDK เป็นส่วนหนึ่งของครอบครัว Play Core SDK SDK แบบเนทีฟมีไฟล์ส่วนหัว C ชื่อ app_update.h ที่รวมAppUpdateManagerจากไลบรารีการอัปเดตในแอปของ Java Play ไฟล์ส่วนหัวนี้ช่วยให้แอปเรียก API สําหรับการอัปเดตในแอปได้โดยตรงจากโค้ดเนทีฟ

ตั้งค่าสภาพแวดล้อมการพัฒนา

Download Play Core Native SDK

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

Terms and Conditions

Last modified: September 24, 2020
  1. By using the Play Core Software Development Kit, you agree to these terms in addition to the Google APIs Terms of Service ("API ToS"). If these terms are ever in conflict, these terms will take precedence over the API ToS. Please read these terms and the API ToS carefully.
  2. For purposes of these terms, "APIs" means Google's APIs, other developer services, and associated software, including any Redistributable Code.
  3. “Redistributable Code” means Google-provided object code or header files that call the APIs.
  4. Subject to these terms and the terms of the API ToS, you may copy and distribute Redistributable Code solely for inclusion as part of your API Client. Google and its licensors own all right, title and interest, including any and all intellectual property and other proprietary rights, in and to Redistributable Code. You will not modify, translate, or create derivative works of Redistributable Code.
  5. Google may make changes to these terms at any time with notice and the opportunity to decline further use of the Play Core Software Development Kit. Google will post notice of modifications to the terms at https://developer.android.com/guide/playcore/license. Changes will not be retroactive.
Download Play Core Native SDK

play-core-native-sdk-1.15.3.zip

  1. เลือกดำเนินการอย่างหนึ่งดังต่อไปนี้

  2. เตรียม Android Studio สําหรับการพัฒนาแบบเนทีฟโดยใช้ SDK Manager เพื่อติดตั้ง CMake และ Android Native Development Kit (NDK) เวอร์ชันล่าสุด ดูข้อมูลเพิ่มเติมเกี่ยวกับการสร้างหรือนําเข้าโปรเจ็กต์เนทีฟได้ที่การเริ่มต้นใช้งาน NDK

  3. ดาวน์โหลดไฟล์ ZIP และแตกไฟล์ข้างโปรเจ็กต์

    ลิงก์ดาวน์โหลด ขนาด ผลรวมตรวจสอบ SHA-256
    37.8 MiB 9db60185185342f28d2c278b60222333608c67bc022e458a25224eaea8c4c4b7
  4. อัปเดตไฟล์ build.gradle ของแอปดังที่แสดงด้านล่าง

    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/gms_task.pgcfg'
                    proguardFile '$playcoreDir/proguard/per-feature-proguard-files'
                    ...
                }
                debug {
                    ...
                }
            }
            externalNativeBuild {
                cmake {
                    path 'src/main/CMakeLists.txt'
                }
            }
        }
    
        dependencies {
            // Import these feature-specific AARs for each Google Play Core library.
            implementation 'com.google.android.play:app-update:2.1.0'
            implementation 'com.google.android.play:asset-delivery:2.2.2'
            implementation 'com.google.android.play:integrity:1.4.0'
            implementation 'com.google.android.play:review:2.0.2'
    
            // Import these common dependencies.
            implementation 'com.google.android.gms:play-services-tasks:18.0.2'
            implementation files("$playcoreDir/playcore-native-metadata.jar")
            ...
        }
        

    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/gms_task.pgcfg")
                proguardFile("$playcoreDir/proguard/per-feature-proguard-files")
                ...
            }
            debug {
                ...
            }
        }
        externalNativeBuild {
            cmake {
                path = "src/main/CMakeLists.txt"
            }
        }
    }
    
    dependencies {
        // Import these feature-specific AARs for each Google Play Core library.
        implementation("com.google.android.play:app-update:2.1.0")
        implementation("com.google.android.play:asset-delivery:2.2.2")
        implementation("com.google.android.play:integrity:1.4.0")
        implementation("com.google.android.play:review:2.0.2")
    
        // Import these common dependencies.
        implementation("com.google.android.gms:play-services-tasks:18.0.2")
        implementation(files("$playcoreDir/playcore-native-metadata.jar"))
        ...
    }
  5. อัปเดตไฟล์ CMakeLists.txt ของแอปตามที่แสดงด้านล่าง

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

การรวบรวมข้อมูล

Play Core Native SDK อาจรวบรวมข้อมูลที่เกี่ยวข้องกับเวอร์ชันเพื่อให้ Google ปรับปรุงผลิตภัณฑ์ได้ ซึ่งรวมถึงข้อมูลต่อไปนี้

  • ชื่อแพ็กเกจของแอป
  • เวอร์ชันแพ็กเกจของแอป
  • เวอร์ชันของ Play Core Native SDK

ระบบจะรวบรวมข้อมูลนี้เมื่อคุณอัปโหลดแพ็กเกจแอปไปยัง Play Console หากต้องการเลือกไม่ใช้กระบวนการรวบรวมข้อมูลนี้ ให้นําการนําเข้า $playcoreDir/playcore-native-metadata.jar ออกในไฟล์ build.gradle

โปรดทราบว่าการเก็บรวบรวมข้อมูลนี้เกี่ยวข้องกับการใช้ Play Core Native SDK และการใช้ข้อมูลที่เก็บรวบรวมของ Google นั้นแยกจากกันและไม่ได้ขึ้นอยู่กับการเก็บรวบรวมทรัพยากร Dependency ของไลบรารีที่ Google ประกาศไว้ใน Gradle เมื่อคุณอัปโหลดแพ็กเกจแอปไปยัง Play Console

หลังจากผสานรวม Play Core Native SDK เข้ากับโปรเจ็กต์แล้ว ให้ใส่บรรทัดต่อไปนี้ในไฟล์ที่มีการเรียก API

#include "play/app_update.h"

เริ่มต้นการอัปเดตในแอป API

เมื่อใดก็ตามที่คุณใช้ In-App Update API ให้เริ่มต้นใช้งานก่อนโดยเรียกใช้ฟังก์ชัน AppUpdateManager_init() ดังที่แสดงในตัวอย่างต่อไปนี้ซึ่งสร้างขึ้นด้วย 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.
  }
}

ตรวจสอบความพร้อมในการอัปเดต

ก่อนขออัปเดต ให้ตรวจสอบว่าแอปของคุณมีอัปเดตให้หรือไม่ AppUpdateManager_requestInfo() จะเริ่มคําขอแบบไม่พร้อมกันซึ่งจะรวบรวมข้อมูลที่จําเป็นเพื่อเปิดใช้ขั้นตอนอัปเดตในแอปในภายหลัง ฟังก์ชันจะแสดงผล APP_UPDATE_NO_ERROR หากคำขอเริ่มสําเร็จ

AppUpdateErrorCode error_code = AppUpdateManager_requestInfo()

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

คุณติดตามกระบวนการและผลลัพธ์ของคำขอได้โดยใช้ AppUpdateManager_getInfo() นอกจากรหัสข้อผิดพลาดแล้ว ฟังก์ชันนี้จะแสดงผลAppUpdateInfo โครงสร้างแบบทึบ ซึ่งคุณใช้เพื่อดึงข้อมูลเกี่ยวกับคำขออัปเดตได้ เช่น คุณอาจต้องการเรียกใช้ฟังก์ชันนี้ในลูปเกมทุกลูปจนกว่าจะให้ผลลัพธ์ที่ไม่ใช่ค่าว่างสำหรับ 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
   }
...
}

ตรวจสอบความล้าสมัยของการอัปเดต

นอกจากการตรวจสอบว่ามีการอัปเดตหรือไม่แล้ว คุณอาจต้องตรวจสอบด้วยว่าเวลาผ่านไปนานเท่าใดนับตั้งแต่ที่ผู้ใช้ได้รับการแจ้งเตือนการอัปเดตครั้งล่าสุดผ่าน Play Store ซึ่งจะช่วยให้คุณตัดสินใจได้ว่าจะเริ่มต้นการอัปเดตแบบยืดหยุ่นหรือการอัปเดตทันที เช่น คุณอาจรอ 2-3 วันก่อนแจ้งให้ผู้ใช้อัปเดตแบบยืดหยุ่น และรออีก 2-3 วันหลังจากนั้นก่อนกำหนดให้อัปเดตทันที

ใช้ AppUpdateInfo_getClientVersionStalenessDays() เพื่อตรวจสอบจำนวนวันที่นับตั้งแต่การอัปเดตพร้อมให้บริการผ่าน Play Store

int32_t staleness_days = AppUpdateInfo_getClientVersionStalenessDays(info);

ตรวจสอบลำดับความสำคัญของการอัปเดต

Google Play Developer API ช่วยให้คุณกำหนดลำดับความสำคัญของการอัปเดตแต่ละรายการได้ ซึ่งจะช่วยให้แอปตัดสินใจได้ว่าควรแนะนำให้ผู้ใช้อัปเดตมากน้อยเพียงใด ตัวอย่างเช่น ลองพิจารณากลยุทธ์ต่อไปนี้ในการตั้งค่าลำดับความสำคัญของการอัปเดต

  • การปรับปรุง UI เล็กน้อย: การอัปเดตสำคัญน้อย ไม่ขอการอัปเดตแบบยืดหยุ่นหรือการอัปเดตทันที อัปเดตเฉพาะเมื่อผู้ใช้ไม่ได้โต้ตอบกับแอป
  • การปรับปรุงประสิทธิภาพ: การอัปเดตสำคัญปานกลาง ขอการอัปเดตแบบยืดหยุ่น
  • การอัปเดตความปลอดภัยที่สำคัญ: การอัปเดตสำคัญสูง ขอการอัปเดตทันที

Google Play ใช้ค่าจำนวนเต็มระหว่าง 0 ถึง 5 เพื่อกำหนดลำดับความสำคัญ โดย 0 จะเป็นค่าเริ่มต้นและ 5 จะเป็นลำดับความสำคัญสูงสุด หากต้องการตั้งค่าลำดับความสำคัญของการอัปเดต ให้ใช้ช่อง inAppUpdatePriority ในส่วน Edits.tracks.releases ใน Google Play Developer API ระบบจะถือว่าเวอร์ชันที่เพิ่มเข้ามาใหม่ทั้งหมดในรุ่นมีลำดับความสำคัญเท่ากับรุ่นนั้น คุณจะกำหนดลำดับความสำคัญได้เมื่อเปิดตัวรุ่นใหม่เท่านั้น และจะเปลี่ยนแปลงในภายหลังไม่ได้

ตั้งค่าลําดับความสําคัญโดยใช้ Google Play Developer API ตามที่อธิบายไว้ในเอกสารประกอบของ Play Developer API ระบุลําดับความสําคัญของการอัปเดตในแอปในแหล่งข้อมูล Edit.tracks ที่ส่งในเมธอด Edit.tracks: update ตัวอย่างต่อไปนี้แสดงการเผยแพร่แอปที่มีรหัสเวอร์ชัน 88 และ inAppUpdatePriority 5

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

ในโค้ดของแอป คุณสามารถตรวจสอบระดับความสำคัญของการอัปเดตหนึ่งๆ โดยใช้ AppUpdateInfo_getPriority() ดังนี้

int32_t priority = AppUpdateInfo_getPriority(info);

เริ่มอัปเดต

หลังจากยืนยันว่ามีอัปเดตพร้อมให้ใช้งานแล้ว คุณจะขออัปเดตได้โดยใช้ AppUpdateManager_requestStartUpdate() ก่อนขอการอัปเดต ให้รับออบเจ็กต์ AppUpdateInfo เวอร์ชันล่าสุดและสร้างออบเจ็กต์ AppUpdateOptions เพื่อกําหนดค่าขั้นตอนการอัปเดต ออบเจ็กต์ AppUpdateOptions จะกำหนดตัวเลือกสำหรับขั้นตอนอัปเดตในแอป รวมถึงกำหนดว่าควรอัปเดตแบบยืดหยุ่นหรือแบบทันที

ตัวอย่างต่อไปนี้สร้างออบเจ็กต์ AppUpdateOptions สําหรับขั้นตอนการอัปเดตที่ยืดหยุ่น

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

ตัวอย่างต่อไปนี้สร้างออบเจ็กต์ AppUpdateOptions สำหรับขั้นตอนการอัปเดตทันที

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

ออบเจ็กต์ AppUpdateOptions ยังมีช่อง AllowAssetPackDeletion ด้วย ซึ่งจะกำหนดว่าอนุญาตให้การอัปเดตล้างแพ็กเกจชิ้นงานหรือไม่ในกรณีที่พื้นที่เก็บข้อมูลของอุปกรณ์มีจำกัด ช่องนี้จะตั้งค่าเป็น false โดยค่าเริ่มต้น แต่คุณใช้วิธี AppUpdateOptions_setAssetPackDeletionAllowed() เพื่อตั้งค่าเป็น true แทนได้ ดังนี้

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

หลังจากมีออบเจ็กต์ AppUpdateInfo ที่อัปเดตล่าสุดและออบเจ็กต์ AppUpdateOptions ที่กําหนดค่าอย่างถูกต้องแล้ว ให้เรียกใช้ AppUpdateManager_requestStartUpdate() เพื่อส่งคําขอขั้นตอนการอัปเดตแบบไม่สอดคล้องกัน โดยส่ง Android Activity jobject เป็นสําหรับพารามิเตอร์สุดท้าย

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

หากต้องการเพิ่มพื้นที่ว่าง ให้ปล่อยอินสแตนซ์ของ AppUpdateInfo และ AppUpdateOptions ที่คุณไม่ต้องการแล้วโดยเรียกใช้ AppUpdateInfo_destroy() และ AppUpdateOptions_destroy() ตามลำดับ

AppUpdateInfo_destroy(info);
AppUpdateOptions_destroy(options);

สำหรับขั้นตอนการอัปเดตทันที Google Play จะแสดงหน้ายืนยันผู้ใช้ เมื่อผู้ใช้ยอมรับคำขอ Google Play จะดาวน์โหลดและติดตั้งการอัปเดตในเบื้องหน้าโดยอัตโนมัติ จากนั้นจึงรีสตาร์ทแอปเป็นเวอร์ชันที่อัปเดตแล้วหากการติดตั้งสำเร็จ

หากต้องการใช้ขั้นตอนการอัปเดตที่ยืดหยุ่น คุณสามารถขอออบเจ็กต์ AppUpdateInfo ที่อัปเดตล่าสุดอยู่เรื่อยๆ เพื่อติดตามสถานะการอัปเดตปัจจุบันขณะที่ผู้ใช้โต้ตอบกับแอปต่อไป หลังจากดาวน์โหลดเสร็จเรียบร้อยแล้ว คุณต้องทริกเกอร์การอัปเดตให้เสร็จสมบูรณ์โดยเรียกใช้ AppUpdateManager_requestCompleteUpdate() ดังที่แสดงในตัวอย่างต่อไปนี้

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

เพิ่มพื้นที่ว่างในทรัพยากรโดยเรียกใช้ฟังก์ชัน AppUpdateManager_destroy() หลังจากที่แอปของคุณใช้ API เสร็จแล้ว

การจัดการข้อผิดพลาด

ส่วนนี้จะอธิบายวิธีแก้ปัญหาสำหรับข้อผิดพลาดที่พบบ่อยซึ่งระบุโดยค่า AppUpdateErrorCode ที่เฉพาะเจาะจง

  • รหัสข้อผิดพลาด -110, APP_UPDATE_INITIALIZATION_NEEDED บ่งบอกว่า API เริ่มต้นไม่สำเร็จ เรียก AppUpdateManager_init() เพื่อเริ่มต้น API
  • รหัสข้อผิดพลาด -4, APP_UPDATE_INVALID_REQUEST บ่งชี้ว่าพารามิเตอร์บางอย่างของคำขอขั้นตอนการอัปเดตมีรูปแบบไม่ถูกต้อง ตรวจสอบว่าออบเจ็กต์ AppUpdateInfo และ AppUpdateOptions ไม่ได้เป็นค่า Null และมีการจัดรูปแบบอย่างถูกต้อง
  • รหัสข้อผิดพลาด -5, APP_UPDATE_UNAVAILABLE บ่งบอกว่าไม่มีอัปเดตที่เกี่ยวข้อง ตรวจสอบว่าเวอร์ชันเป้าหมายมีชื่อแพ็กเกจ รหัสแอปพลิเคชัน และคีย์การรับรองเดียวกัน หากมีการอัปเดต ให้ล้างแคชของแอปแล้วเรียกใช้ AppUpdateManager_requestAppUpdateInfo() อีกครั้งเพื่อรีเฟรช AppUpdateInfo
  • รหัสข้อผิดพลาด -6, APP_UPDATE_NOT_ALLOWED บ่งบอกว่าระบบไม่อนุญาตให้อัปเดตประเภทที่ระบุโดยออบเจ็กต์ AppUpdateOption ตรวจสอบว่าออบเจ็กต์ AppUpdateInfo ระบุว่าอนุญาตให้อัปเดตประเภทนั้นหรือไม่ก่อนที่จะเริ่มขั้นตอนการอัปเดต

ขั้นตอนถัดไป

ทดสอบการอัปเดตในแอปของแอปเพื่อยืนยันว่าการผสานรวมทํางานอย่างถูกต้อง