Mendukung update dalam aplikasi (Native)

Panduan ini menjelaskan cara mendukung update dalam aplikasi di aplikasi Anda menggunakan kode native (C atau C++). Ada panduan terpisah untuk kasus saat implementasi Anda menggunakan bahasa pemrograman Kotlin atau Java, dan saat implementasi Anda menggunakan Unity.

Ringkasan Native SDK

Play Core Native SDK adalah bagian dari kelompok Play Core SDK. Native SDK mencakup file header C, app_update.h, yang menggabungkan AppUpdateManager dari Java Play In-App Update Library. File header ini memungkinkan aplikasi Anda memanggil API untuk update dalam aplikasi langsung dari kode native.

Menyiapkan lingkungan pengembangan

Download Play Core Native SDK

Sebelum mendownload, Anda harus menyetujui persyaratan dan ketentuan berikut.

Persyaratan dan Ketentuan

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. Lakukan salah satu hal berikut:

    • Instal Android Studio versi 4.0 atau yang lebih tinggi. Gunakan UI SDK Manager untuk menginstal Android SDK Platform versi 10.0 (level API 29).
    • Instal alat command line Android SDK dan gunakan sdkmanager untuk menginstal Android SDK Platform versi 10.0 (level API 29).
  2. Siapkan Android Studio untuk pengembangan native dengan menggunakan SDK Manager untuk menginstal CMake dan Android Native Development Kit (NDK) terbaru. Untuk informasi selengkapnya tentang membuat atau mengimpor project native, lihat Mulai Menggunakan NDK.

  3. Download file zip dan ekstrak bersama project Anda.

    Link Download Ukuran SHA-256 Checksum
    37,8 MiB 9db60185185342f28d2c278b60222333608c67bc022e458a25224eaea8c4c4b7
  4. Update file build.gradle aplikasi Anda seperti yang ditunjukkan di bawah ini:

    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. Update file CMakeLists.txt aplikasi Anda seperti yang ditunjukkan di bawah ini:

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

Pengumpulan Data

Play Core Native SDK dapat mengumpulkan data terkait versi untuk memungkinkan Google meningkatkan produk, termasuk:

  • Nama paket aplikasi
  • Versi paket aplikasi
  • Versi Play Core Native SDK

Data ini akan dikumpulkan saat Anda mengupload paket aplikasi ke Konsol Play. Untuk memilih tidak ikut dalam proses pengumpulan data ini, hapus impor $playcoreDir/playcore-native-metadata.jar di file build.gradle.

Perhatikan bahwa pengumpulan data ini yang terkait dengan penggunaan Play Core Native SDK oleh Anda dan penggunaan data yang dikumpulkan oleh Google terpisah dan tidak bergantung pada pengumpulan dependensi library Google yang dideklarasikan di Gradle saat Anda mengupload paket aplikasi ke Konsol Play.

Setelah Anda mengintegrasikan Play Core Native SDK ke dalam project, sertakan baris berikut di file yang berisi panggilan API:

#include "play/app_update.h"

Melakukan inisialisasi API update dalam aplikasi

Setiap Anda menggunakan API update dalam aplikasi, inisialisasi API tersebut terlebih dahulu dengan memanggil fungsi AppUpdateManager_init(), seperti yang ditunjukkan dalam contoh berikut yang dibangun dengan 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.
  }
}

Memeriksa ketersediaan update

Sebelum Anda meminta update, periksa apakah ada update yang tersedia untuk aplikasi Anda. AppUpdateManager_requestInfo() memulai konten asinkron yang mengumpulkan informasi yang diperlukan untuk meluncurkan alur update dalam aplikasi nanti. Fungsi ini menampilkan APP_UPDATE_NO_ERROR jika permintaan berhasil dimulai.

AppUpdateErrorCode error_code = AppUpdateManager_requestInfo()

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

Anda dapat melacak proses yang sedang berlangsung dan hasil permintaan menggunakan AppUpdateManager_getInfo(). Selain kode error, fungsi ini menampilkan struktur buram AppUpdateInfo, yang dapat Anda gunakan untuk mengambil informasi tentang permintaan update. Misalnya, Anda mungkin ingin memanggil fungsi ini di setiap game loop hingga menampilkan hasil non-null untuk 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
   }
...
}

Memeriksa penghentian update

Selain memeriksa apakah update tersedia, Anda juga perlu memeriksa jumlah waktu yang telah berlalu sejak pengguna terakhir kali diberi tahu tentang update melalui Play Store. Hal ini dapat membantu Anda menentukan apakah harus melakukan inisialisasi update fleksibel atau update langsung. Misalnya, Anda mungkin menunggu beberapa hari sebelum memberi tahu pengguna dengan update fleksibel, dan beberapa hari setelahnya sebelum meminta update langsung.

Gunakan AppUpdateInfo_getClientVersionStalenessDays() untuk memeriksa jumlah hari sejak update tersedia di Play Store:

int32_t staleness_days = AppUpdateInfo_getClientVersionStalenessDays(info);

Memeriksa prioritas update

Dengan Google Play Developer API, Anda dapat menyetel prioritas setiap update. Hal ini memungkinkan aplikasi Anda menentukan seberapa kuat rekomendasi update kepada pengguna. Sebagai contoh, pertimbangkan strategi berikut untuk menyetel prioritas update:

  • Peningkatan kecil pada UI: Update prioritas rendah; tidak meminta update fleksibel atau update langsung. Mengupdate hanya saat pengguna tidak berinteraksi dengan aplikasi Anda.
  • Peningkatan performa: Update prioritas sedang; meminta update fleksibel.
  • Update keamanan penting: Update prioritas tinggi; meminta update langsung.

Untuk menentukan prioritas, Google Play menggunakan nilai bilangan bulat antara 0 dan 5, dengan 0 adalah nilai default dan 5 adalah prioritas tertinggi. Guna menyetel prioritas untuk update, gunakan kolom inAppUpdatePriority di bawah Edits.tracks.releases di Google Play Developer API. Semua versi yang baru ditambahkan dalam rilis dianggap sebagai prioritas yang sama dengan rilis tersebut. Prioritas hanya dapat disetel saat meluncurkan rilis baru, dan tidak dapat diubah setelahnya.

Tetapkan prioritas menggunakan Google Play Developer API, seperti yang dijelaskan di dokumentasi Play Developer API. Tentukan prioritas update dalam aplikasi di resource Edit.tracks yang diteruskan ke metode Edit.tracks: update. Contoh berikut menunjukkan perilisan aplikasi dengan kode versi 88 dan inAppUpdatePriority 5:

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

Dalam kode aplikasi, Anda dapat memeriksa tingkat prioritas untuk update tertentu menggunakan AppUpdateInfo_getPriority():

int32_t priority = AppUpdateInfo_getPriority(info);

Memulai update

Setelah memastikan bahwa update tersedia, Anda dapat meminta update menggunakan AppUpdateManager_requestStartUpdate(). Sebelum Anda meminta update, dapatkan objek AppUpdateInfo terbaru dan buat objek AppUpdateOptions untuk mengonfigurasi alur update. Objek AppUpdateOptions menentukan opsi untuk alur update dalam aplikasi, termasuk apakah update tersebut harus fleksibel atau langsung.

Contoh berikut akan membuat objek AppUpdateOptions untuk alur update fleksibel:

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

Contoh berikut membuat objek AppUpdateOptions untuk alur update langsung:

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

Objek AppUpdateOptions juga berisi kolom AllowAssetPackDeletion yang menentukan apakah update diizinkan untuk menghapus paket aset jika penyimpanan perangkat terbatas. Kolom ini ditetapkan ke false secara default, tetapi Anda dapat menggunakan metode AppUpdateOptions_setAssetPackDeletionAllowed() untuk menetapkannya ke true:

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

Setelah Anda memiliki objek AppUpdateInfo terbaru dan objek AppUpdateOptions yang dikonfigurasi dengan benar, panggil AppUpdateManager_requestStartUpdate() untuk meminta alur update secara asinkron, yang meneruskan jobject Aktivitas Android untuk parameter akhir.

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

Untuk mengosongkan resource, rilis instance AppUpdateInfo dan AppUpdateOptions yang tidak lagi Anda perlukan dengan memanggil masing-masing AppUpdateInfo_destroy() dan AppUpdateOptions_destroy().

AppUpdateInfo_destroy(info);
AppUpdateOptions_destroy(options);

Untuk alur update langsung, Google Play menampilkan halaman konfirmasi pengguna. Saat pengguna menyetujui permintaan, Google Play otomatis mendownload dan menginstal update di latar depan, lalu memulai ulang aplikasi ke versi yang diupdate jika penginstalan berhasil.

Untuk alur update fleksibel, Anda dapat terus meminta objek AppUpdateInfo terbaru untuk melacak status update saat ini saat pengguna terus berinteraksi dengan aplikasi. Setelah berhasil didownload, Anda harus memicu penyelesaian update dengan memanggil AppUpdateManager_requestCompleteUpdate(), seperti yang ditampilkan di contoh berikut:

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

Kosongkan resource dengan memanggil fungsi AppUpdateManager_destroy() setelah aplikasi Anda selesai menggunakan API.

Penanganan error

Bagian ini menjelaskan solusi untuk kesalahan umum yang ditunjukkan oleh nilai AppUpdateErrorCode tertentu:

  • Kode error -110, APP_UPDATE_INITIALIZATION_NEEDED menunjukkan bahwa API belum berhasil diinisialisasi. Panggil AppUpdateManager_init() untuk melakukan inisialisasi API.
  • Kode error -4, APP_UPDATE_INVALID_REQUEST menunjukkan bahwa format beberapa parameter permintaan alur update salah. Periksa untuk memastikan bahwa objek AppUpdateInfo dan AppUpdateOptions bukan null serta telah diformat dengan benar.
  • Kode error -5, APP_UPDATE_UNAVAILABLE menunjukkan bahwa tidak ada update yang tersedia dan dapat diterapkan. Pastikan versi target memiliki nama paket, ID aplikasi, dan kunci penandatanganan yang sama. Jika ada update yang tersedia, hapus cache aplikasi dan panggil AppUpdateManager_requestAppUpdateInfo() lagi untuk memuat ulang AppUpdateInfo.
  • Kode error -6, APP_UPDATE_NOT_ALLOWED menunjukkan bahwa jenis update yang ditunjukkan oleh objek AppUpdateOption tidak diizinkan. Periksa apakah objek AppUpdateInfo menunjukkan bahwa jenis update diizinkan sebelum memulai alur update.

Langkah berikutnya

Uji update dalam aplikasi pada aplikasi Anda untuk memastikan bahwa integrasi berfungsi dengan benar.