Safie Engineers' Blog!

Safieのエンジニアが書くブログです

モバイルアプリに強制アップデート機能を実装

こんにちは。Safieでモバイルアプリの開発をしている渡部です。
モバイル版Safie Viewerでは、バージョン3.11.0から、新しいバージョンがリリースされるとユーザーに向けてアップデートを知らせるアラートが表示されるようになっています。

iOS版 Safie Viewer
今回は、このアップデート機能の実装について振り返ってまとめてみました。

実装の経緯

モバイル版Safie Viewerでは現在約1ヶ月おきに定期リリースを行っています。以前は開発サイクルがもう少し長期間だったのですが、チーム体制が充実したこともありコンスタントに新しいバージョンを用意することができるようになりました。
それに伴い、ユーザーに新バージョンをアピールする必要性もより高まりました。新機能を実装したり、バグを修正するスピードが早まったものの、ユーザーに気づいてもらえない限りは意味がありません。
より安定したバージョンを使ってもらうためにも、アップデート機能を実装することになりました。

必要な要件

実装にあたって、まずはモバイルアプリのアップデート機能で求める要件を洗い出しました。

  • 立ち上げたアプリが対象バージョンより低い場合、アップデートのお知らせをアラートで表示したい
    対象バージョンとは必ずしも最新版ではなく、任意のバージョンを指定したい。

  • 強制と半強制を使い分けたい
    アプリを立ち上げてアップデートについてアラートが表示された際に、アップデートしないと先に進めないパターン(強制)と、アップデートせずともアプリを使い続けられるパターン(半強制)の2つを、バージョンによって切り替えたい。
    深刻なバグ修正の場合は強制で、それ以外の場合は半強制でお知らせしたい。

  • その他、いろいろな設定値を持ちたい
    アラート表示を開始/終了する日時、アラート表示の対象となるOSバージョンなど。

  • iOS版・Android版の設定を一括で管理したい

  • 手軽に更新したい

サービス選定

アップデート機能を実現するための仕組みはすでに色々なサービスで提供されています。
例えば、
①iTunes Search APIを使用する(iOSのみ)
②Google Play Core Libraryを使用する(Androidのみ)
③アップデート機能用の3rdパーティライブラリを使用する
④バックエンドサービスにアップデートの設定ファイルを置き、アプリ側で読み込む
など。

①や②は公式のサービスですが、カスタム性は乏しいです。③もメンテナンスのことを考えるとできれば避けたくなります。
ということで、今回は、前述した要件を満たすために④の方法で、サービスはFirebase Remote Configを活用することにしました。
④を実現するだけなら、その他のBaaSを活用するやり方もありますが、

  • すでにFirebaseを導入済みだったこと

  • コンソール上のUIのみで複数ファイルを更新できる手軽さ

以上を加味して、 Remote Configを選びました。

実装

Firebaseプロジェクトの作成については、今回は割愛します。

RemoteConfigの設定

要件をふまえて、コンソールで以下のようなjsonを設定しました。

{
  "parameters": {
    "ios_update": {
      "defaultValue": {
        "value": {
    "version":"3.19.0", 
    "is_force":true,
    "start_date":"2023-02-28",
    "support_os_version":"13.0"
    }
      },
      "valueType": "JSON"
    },
    "android_update": {
        ...
    }
  }
}

version: 対象バージョン。この数値より低いバージョンのアプリを起動したら、アップデート案内のアラートを表示する。
is_force: 強制か半強制か
start_date:アラート表示開始日
end_date: アラート表示終了日
support_os_version:アプリのサポート対象OS

アプリ側の設定

  1. プロジェクトにRemote ConfigのSDKを追加

iOS
CocoaPodsを使用しているので、Podfileに以下を追加。

pod 'Firebase/RemoteConfig'


Android
build.gradleに以下を追加。

implementation 'com.google.firebase:firebase-config-ktx:21.4.0'


2. アップデートのアラートを表示したいタイミングで、RemoteConfigからjsonを取得するように実装。

iOS
アプリを起動して最初に立ち上がるViewControllerにて

override func viewWillAppear(_ animated: Bool) {
    // ここで取得
}

通知をタップして任意の画面を開いた時

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    // ここで取得
}

フォアグラウンドからの復帰時

func applicationWillEnterForeground(_ application: UIApplication) {
    // ここで取得
}

取得の流れ

// シングルトンオブジェクトを作成
remoteConfig = RemoteConfig.remoteConfig()
// RemoteConfigから値を取得
remoteConfig.fetch() { (status, error) -> Void in
    remoteConfig.activate { changed, error in
        // RemoteConfigStruct:RemoteConfigで設定したjsonと対応するStruct
        let response = try? JSONDecoder().decode(RemoteConfigStruct.self, from: remoteConfig[“ios_update”].dataValue)
    }
}


Android
起動時、フォアグラウンド復帰時にて

class MainApp : Application() {
    override fun onCreate() {
        ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onStart(owner: LifecycleOwner) {
                // ここで取得
            }
        })
    }
}

取得の流れ

// シングルトンオブジェクトを作成
val remoteConfig = Firebase.remoteConfig
// RemoteConfigから値を取得
remoteConfig.fetchAndActivate().addOnCompleteListener { task ->
    if(task.isSuccessful) {
        val gson =   GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
        // RemoteConfigData:RemoteConfigで設定しているjsonと対応するDataクラス
        val remoteConfigData= gson.fromJson(remoteConfig.getString(”android_update”), RemoteConfigData::class.java)
    }
}


3. 取得した設定値(remoteConfigData)によって、アラートの表示/非表示、強制/半強制を出し分けるように実装。

効果

強制アップデートの仕組みを実装してから、ユーザーは以前よりも速やかに最新版に移行してくれるようになったのか、Analyticsから確認してみました。
いずれも、新バージョンをリリースしてから1ヶ月間のユーザー推移を表しています。

①強制アップデート実装前(旧バージョン3.9 → 新バージョンv3.10)

②実装して2ヶ月経過(旧バージョン3.12 → 新バージョンv3.13)

③実装して半年以上経過(旧バージョン3.18 → 新バージョンv3.19)

強制アップデート実装から時間が経過するにつれ、旧バージョン使用数の減退が早まっています。旧バージョンの使用割合も減りました。
今まで以上に多くのユーザーがより早く新バージョンを使用することに繋がり、アプリの安定化に繋がったかなと思います🙌

© Safie Inc.