はじめに
個人開発しているiOSアプリ「いいこと日記」に強制アップデートを実装する機会があり、手軽に導入できるFirebase Remote Configを使用しました。
Firebase SDK
のv10.7.0
からサポートされているRemote Configのリアルタイム更新を使うことで、起動時だけでなくアプリの利用中でも即座に強制アップデートダイアログを表示することができます。
今回はできるだけ最低限の機能での実装を紹介します。
Firebaseでの設定
Remote Config上にrequired_version
というパラメータを作成しておき、そのバージョンよりも古いバージョンだった場合に強制アップデートのダイアログを表示します。
実装
ForceUpdateManager.swift
import FirebaseRemoteConfig
import UIKit
final class ForceUpdateManager {
static let shared: ForceUpdateManager = .init()
private let remoteConfig = RemoteConfig.remoteConfig()
private let requiredVersionKey = "required_version"
private init() {}
func startObserving() {
// 初期データを取得する
remoteConfig.fetchAndActivate { [weak self] status, error in
switch status {
case .successUsingPreFetchedData, .successFetchedFromRemote:
self?.forceUpdateIfNeeded()
default:
if let error {
print(error.localizedDescription)
}
}
}
// Updateを監視する
remoteConfig.addOnConfigUpdateListener { [weak self] configUpdate, error in
guard let self else { return }
if let error {
print(error.localizedDescription)
}
// Fetchしてきたデータを有効化する
remoteConfig.activate()
// 強制アップデートを行う
if configUpdate?.updatedKeys.first == requiredVersionKey {
forceUpdateIfNeeded()
}
}
}
// バージョンを比較して強制アップデートが必要ならアラートを表示する
private func forceUpdateIfNeeded() {
guard let currentVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String,
let requiredVersion = remoteConfig.configValue(forKey: requiredVersionKey).stringValue else {
return
}
// バージョン文字列を配列に変換(例: "3.2.1" -> [3, 2, 1])
var currentVersionNums = currentVersion.split(separator: ".").compactMap { Int($0) }
var requiredVersionNums = requiredVersion.split(separator: ".").compactMap { Int($0) }
if currentVersionNums.isEmpty || requiredVersionNums.isEmpty
|| currentVersionNums.count > 3 || requiredVersionNums.count > 3 {
return
}
// 3桁まで0で埋める(例: [3, 2] -> [3, 2, 0])
currentVersionNums.append(contentsOf: repeatElement(0, count: 3 - currentVersionNums.count))
requiredVersionNums.append(contentsOf: repeatElement(0, count: 3 - requiredVersionNums.count))
// バージョンを比較する
for i in 0..<3 {
let current = currentVersionNums[i]
let required = requiredVersionNums[i]
if current == required {
continue
} else if current > required {
return
} else if required > current {
showAlert()
return
}
}
}
private func showAlert() {
// アラートを表示するViewController
guard let viewController = rootViewController else { return }
let alert = UIAlertController(title: "アップデートのお願い", message: "最新版にアップデートしてください。", preferredStyle: .alert)
let updateAction = UIAlertAction(title: "App Storeを開く", style: .default) { _ in
guard let url = URL(string: "https://apps.apple.com/app/{アプリのID}"),
UIApplication.shared.canOpenURL(url) else {
return
}
UIApplication.shared.open(url)
// ストア遷移時にアラートが閉じてしまうため再度表示する
viewController.present(alert, animated: true)
}
alert.addAction(updateAction)
viewController.present(alert, animated: true)
}
// 最前面のViewController
private var rootViewController: UIViewController? {
UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.first?
.windows
.filter { $0.isKeyWindow }
.first?
.rootViewController
}
}
後はAppDelegate
などでForceUpdateManager.shared.startObserving()
を一度呼ぶことで、Remote Configの変更をリアルタイムに取得することができます。
参考
https://firebase.google.com/docs/remote-config/get-started?platform=ios&hl=ja
https://qiita.com/Etsuwo/items/14c4698f17924923fc29
https://www.fuwamaki.com/article/258