アプリ内アップデートをサポートする(ネイティブ)

このガイドでは、ネイティブ コード(C または C++)を使用してアプリでのアプリ内アップデートをサポートする方法について説明します。実装に Kotlin プログラミング言語または Java プログラミング言語を使用する場合と、Unity を使用する場合について、個別のガイドで説明しています。

ネイティブ SDK の概要

Play Core Native SDK は Play Core SDK ファミリーの一部です。Native SDK には、Java Play In-App Update Library の AppUpdateManager をラップする C ヘッダー ファイル app_update.h が含まれています。このヘッダー ファイルを使用すると、ネイティブ コードから直接アプリ内アップデート用の API を呼び出すことができます。

開発環境をセットアップする

ダウンロード: Play Core Native SDK

ダウンロードする前に、次の利用規約に同意する必要があります。

利用規約

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.
ダウンロード Play Core Native SDK

play-core-native-sdk-1.14.0.zip

  1. 次のいずれかの操作を行います。

    • Android Studio バージョン 4.0 以降をインストールし、SDK Manager UI を使用して Android SDK Platform バージョン 10.0(API レベル 29)をインストールする。
    • Android SDK コマンドライン ツールをインストールし、sdkmanager を使用して Android SDK Platform バージョン 10.0(API レベル 29)をインストールする。
  2. Android Studio をネイティブ開発で使用できるようにするため、SDK Manager を使用して最新の CMake と Android Native Development Kit(NDK)をインストールします。ネイティブ プロジェクトの作成やインポートの詳細については、NDK のスタートガイドをご覧ください。

  3. zip ファイルをダウンロードして、プロジェクトと同じ場所に展開します。

    ダウンロード リンク サイズ SHA-256 チェックサム
    36 MiB 782a8522d937848c83a715c9a258b95a3ff2879a7cd71855d137b41c00786a5e
  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.0.0'
            implementation 'com.google.android.play:asset-delivery:2.0.0'
            implementation 'com.google.android.play:integrity:1.0.1'
            implementation 'com.google.android.play:review:2.0.0'
    
            // 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.0.0")
        implementation("com.google.android.play:asset-delivery:2.0.0")
        implementation("com.google.android.play:integrity:1.0.1")
        implementation("com.google.android.play:review:2.0.0")
    
        // 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 のバージョン

このデータは、アプリ パッケージを Google Play Console にアップロードする際に収集されます。データ収集のプロセスを無効にするには、build.gradle ファイル内の $playcoreDir/playcore-native-metadata.jar インポートを削除します。

Play Core Native SDK の使用に関連するこのデータ収集と Google によるこの収集データの使用は、Google Play Console にアプリ パッケージをアップロードする際に Gradle で宣言されるライブラリ依存関係の Google のデータ収集とは別のものであり、相互の関係はありません。

Play Core Native SDK をプロジェクトに統合したら、API 呼び出しを含むファイルに次の行を含めます。

#include "play/app_update.h"

アプリ内アップデートの API を初期化する

アプリ内アップデートの 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 に対して null 以外の結果が返されるまで、すべてのゲームループでこの関数を呼び出すことができます。

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

アップデートの新しさの確認

アップデートが適用可能であるかどうかを確認するだけでなく、ユーザーが Google Play ストアからアップデートの通知を受信してから経過した期間を確認することもできます。これは、フレキシブル アップデートと即時アップデートのどちらを開始したらよいかを判断する際に有用です。たとえば、ユーザーにフレキシブル アップデートを通知するまで数日待ち、その後、即時アップデートを要求するまでさらに数日待つこともできます。

AppUpdateInfo_getClientVersionStalenessDays() を使用して、Google Play ストアからのアップデートの入手が可能になった時点から経過した日数を確認します。

int32_t staleness_days = AppUpdateInfo_getClientVersionStalenessDays(info);

アップデートの優先度を確認する

Google Play Developer API では、各アップデートの優先度を設定できます。 これにより、アプリはユーザーにアップデートを推奨する度合いを決定できるようになります。たとえば、アップデートの優先度を設定するための次のような戦略を考えてみます。

  • UI の細かな改善: 優先度が低いアップデート。フレキシブル アップデートも即時アップデートもリクエストしません。ユーザーがアプリを操作していないときにのみ更新します。
  • パフォーマンスの改善: 優先度が中程度のアップデート。フレキシブル アップデートをリクエストします。
  • 重要なセキュリティ アップデート: 優先度が高いアップデート。即時アップデートをリクエストします。

Google Play は優先度の指定に 0~5 の整数値を使用します。0 はデフォルトの値、5 は優先度が最も高い値です。アップデートの優先度を設定するには、Google Play Developer API の Edits.tracks.releases の下にある inAppUpdatePriority フィールドを使用します。リリースに新たに追加されたすべてのバージョンの優先度は、リリースと同じと見なされます。優先度は新しいリリースの公開時にのみ設定できます。後から変更することはできません。

Google Play Developer API を使用した優先度の設定については、Play Developer API のドキュメントをご覧ください。Edit.tracks: update メソッドで渡される Edit.tracks リソースでアプリ内アップデートの優先度を指定します。次の例に、アプリ(バージョン コード 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 のアクティビティ jobject で渡します。

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

リソースを解放するには、不要になった AppUpdateInfoAppUpdateOptions のインスタンスを、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.
    }
}

アプリで API の使用が終了したら、AppUpdateManager_destroy() 関数を呼び出してリソースを解放します。

エラー処理

このセクションでは、特定の AppUpdateErrorCode 値で示される一般的なエラーの解決策について説明します。

  • エラーコード -110, APP_UPDATE_INITIALIZATION_NEEDED は、API が正常に初期化されていないことを示します。AppUpdateManager_init() を呼び出して API を初期化します。
  • エラーコード -4, APP_UPDATE_INVALID_REQUEST は、アップデート フロー リクエストの一部のパラメータの形式が正しくないことを示します。AppUpdateInfo オブジェクトと AppUpdateOptions オブジェクトが null ではなく、正しくフォーマットされていることを確認してください。
  • エラーコード -5, APP_UPDATE_UNAVAILABLE は、適用可能なアップデートがないことを示します。対象のバージョンに同じパッケージ名アプリケーション ID署名鍵があることを確認します。利用可能なアップデートがある場合は、アプリのキャッシュを消去し、もう一度 AppUpdateManager_requestAppUpdateInfo() を呼び出して AppUpdateInfo を更新します。
  • エラーコード -6, APP_UPDATE_NOT_ALLOWED は、AppUpdateOption オブジェクトによって指定されたアップデート タイプが許可されていないことを示します。アップデート フローを開始する前に、AppUpdateInfo オブジェクトでアップデート タイプが許可されているかどうかを確認してください。

次のステップ

アプリ内アップデートをテストして、統合が正しく機能していることを確認する。