【Kotlin/Android】強制アップデートの実装方法!in-app updates API

この記事からわかること
- Kotlin/Androidアプリで強制アップデートを実装する方法
- in-app updates APIのAppUpdateManagerの使い方
- テスト(動作確認)するには?
index
[open]
\ アプリをリリースしました /
環境
- Android Studio:Koala
- Kotlin:1.9.0
強制アップデートの仕組み
モバイルアプリ開発でよくある「強制アップデート」の仕組みはユーザーが使用しているアプリのバージョンと最新のアプリバージョンを比較し異なる場合にダイアログなどを表示させることで強制または半強制的にアップデートを促す方法です。
これによりユーザーには常に最新のアプリバージョンでの使用を徹底することもできるので、メジャーバージョンが変わった時や致命的なバグが見つかった際に速やかにアップデートをさせることができます。
最新バージョンを取得する方法
アプリが比較対象とする最新のバージョンを管理/取得する方法はいくつかあります。
- Firebase Remote Config
- 自前のサーバー
- in-app updates API
要はサーバー側に最新のアプリバージョンを設置してそれをアプリからAPIなどで取得できる仕組みを構築すれば良いだけなので方法はいくつかあります。ただ「Firebase Remote Config」や「自前のサーバー」などでは更新するごとに手動でサーバー側の値を変更する必要があります。そこでおすすめなのが「in-app updates API」です。
in-app updates APIとは?
「in-app updates API」はストアのアプリバージョンとユーザーのアプリのバージョンを比較し、ストアに新しいバージョンがある場合にアプリのアップデートを促すための機能を提供するAPIです。このAPIを使用することでアプリのアップデート通知だけでなく実際にアップデートまですることも可能になっています。
アップデート対象と比較しているのはversionCode
の値のようです。
注意点
このAPIで機能を実装してもデバック環境だと正しく動作しません。「in-app updates API」はGoogle Play Storeアプリからインストールされたアプリでしか機能を使用することができない仕様になっています。
そのためAndroid Studioからエミューターなどにビルドしたり、apkファイルに置き換えてからインスールをしても以下のようなエラーを吐いて正しくアップデートのチェックが行われないようになっています。
com.google.android.play.core.appupdate.internal.zzy: Failed to bind to the service.
com.google.android.play.core.install.InstallException: -10: Install Error(-10): The app is not owned by any user on this device. An app is "owned" if it has been acquired from Play. (https://developer.android.com/reference/com/google/android/play/core/install/model/InstallErrorCode#ERROR_APP_NOT_OWNED)
Flexible / Immediate
アップデート関連は「in-app updates API」のAppUpdateManager
を使用して実装します。実際にアップデートが必要だった場合の流れとして2つのパターンが用意されています。
Flexible Update(柔軟なアップデート)
「Flexible Update」はユーザーに対して即座にアップデートするか否かを選択できるダイアログを表示するパターンです。このパターンの場合はユーザーが簡単にキャンセルできるようにハーフモーダルで表示されます。

Immediate Update(即時アップデート)
「Immediate Update」はアプリの最新バージョンを強制的にインストールさせるダイアログを表示するパターンです。このパターンの場合はユーザーが画面を覆うようなモーダルで表示されますが「×」ボタンもあるので一応キャンセルも可能なようです。

実際に更新ボタンを押下するとそのままアプリのアップデートが開始され、完了すると自動的にアプリに戻ります。

強制アップデートを実装してみる
まずは「in-app updates API」が利用できるようにライブラリを導入します。「build.gradle」に以下を追加しておきます。
implementation 'com.google.android.play:app-update:2.1.0'
強制アップデートの実装は簡単で以下のような感じになります。updateAvailability
の値がUPDATE_AVAILABLE
になればアップデート対象がストアに存在することになります。あとはその中でstartUpdateFlowForResult
を呼び出すことで専用のアップデートダイアログを表示させることが可能です。(この仕組みを利用してアプリ独自にアップデート促しUIを表示することも可能だと思います。)
private val UPDATE_REQUEST_CODE = 1001
private fun checkForUpdate(activity: Activity) {
val appUpdateManager = AppUpdateManagerFactory.create(activity)
val appUpdateInfoTask: Task<AppUpdateInfo> = appUpdateManager.appUpdateInfo
Toast.makeText(this, "checkForUpdate", Toast.LENGTH_SHORT).show()
// アップデートチェック成功
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
Toast.makeText(this, "成功:${appUpdateInfo}", Toast.LENGTH_SHORT).show()
// アップデートが必要か検証
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE &&
appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
// アップデートダイアログを表示
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
activity,
UPDATE_REQUEST_CODE
)
}
}
// アップデートチェック失敗
appUpdateInfoTask.addOnFailureListener {
Toast.makeText(this, "ERROR:${it}", Toast.LENGTH_SHORT).show()
}
}
あとはcheckForUpdate
を任意のタイミングで呼び出すだけでバージョンチェックが実行され、新しいバージョンがストアにあればアップデートダイアログが表示されるようになります。
FLEXIBLEに変更したい場合はAppUpdateType.FLEXIBLE
を指定すればOKです。
動作確認(テスト)方法
「in-app updates API」はGoogle Play Storeからインストールしたものでないと正しく動作しないため動作確認を行うためにはGoogle Play Consoleの内部テストの機能を利用する必要があります。
動作確認のステップ
- 強制アップデートの実装
- releaseのaabファイルをビルドして内部テストで配布
- 内部テストでインストール※
- アプリのバージョンを更新
- 再度releaseのaabファイルをビルドして内部テストで配布
- アプリを起動させてアップデート通知が出るか確認
※ この際にストアの右上の「…」から「自動更新の有効化」のチェックを外しておいてください。
iOSアプリの強制アップデートはこちら
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。