こんにちはひまらつです。
この記事ではアプリの強制アップデート機能を実装していきます。
互換性のない変更がバックエンドで発生した時など、アプリのサポートバージョンを制限したい時に使われるのが強制アップデートです。
対象バージョンや期間などが書かれた設定ファイルをサーバーに置く必要がありますが、それをmicroCMSで管理することで簡単に編集・配信できます。
起動時に設定ファイルをリクエストし、強制アップデートの対象であれば以下のようなアラートを出す機能を実装します。
強制アップデート情報のAPIを作成する
APIスキーマを以下のように設定します。
実際のケースでは要件に従うことになると思いますが、今回は以下を定義しました。
- 強制アップデートの対象となるバージョン
- 発動させる期間
- タイトルやメッセージなどのアラートに表示する要素
- ボタンタップ時の遷移先(ストアのURL)
強制アップデートはひとつだけ入稿することが多いと思うので今回は「オブジェクト形式」で作成しています。
開始日や終了日など日時を表すフィールドには「日時」の種類を選んでおくと設定が簡単です。
APIプレビューからレスポンスを確認してみると、以下のようになっています。
{
"createdAt": "2021-09-08T06:29:33.252Z",
"updatedAt": "2021-09-08T08:43:48.956Z",
"publishedAt": "2021-09-08T06:29:33.252Z",
"revisedAt": "2021-09-08T08:43:48.956Z",
"title": "アップデートのお願い",
"message": "現在のバージョンではご利用いただけません。\nストアより最新版のアプリへのアップデートをお願いします。",
"startDate": "2021-09-08T01:00:00.000Z",
"endDate": "2021-10-30T15:00:00.000Z",
"minAppVersion": "1.0.0",
"maxAppVersion": "2.9.9",
"buttonTitle": "アップデートする",
"url": "https://blog.microcms.io/"
}
このAPIを利用し、アプリ側のバージョンや日時と比較して強制アップデートが必要を判断します。
アプリで強制アップデートを実装する
今回はiOSアプリでの実装例を紹介します。
まず初めに microCMS iOS SDK をセットアップします。
SDKはSwift Package Managerで提供されているので、以下のGitHubのURLから入手できます。
詳しい手順は以下のドキュメントを参考にしてください。
https://document.microcms.io/tutorial/ios/ios-top
構造体の準備
先ほど定義した強制アップデートの情報を格納するクラスを作りましょう。
import Foundation
struct ForceUpdate {
let title: String
let message: String
let startDate: Date
let endDate: Date
let minAppVersion: String
let maxAppVersion: String
let buttonTitle: String
let url: URL
init?(dict: [String: Any]) {
if let title = dict["title"] as? String,
let message = dict["message"] as? String,
let startDateString = dict["startDate"] as? String,
let startDate = formatter.date(from: startDateString),
let endDateString = dict["endDate"] as? String,
let endDate = formatter.date(from: endDateString),
let minAppVersion = dict["minAppVersion"] as? String,
let maxAppVersion = dict["maxAppVersion"] as? String,
let buttonTitle = dict["buttonTitle"] as? String,
let urlString = dict["url"] as? String,
let url = URL(string: urlString) {
self.title = title
self.message = message
self.startDate = startDate
self.endDate = endDate
self.minAppVersion = minAppVersion
self.maxAppVersion = maxAppVersion
self.buttonTitle = buttonTitle
self.url = url
} else {
return nil
}
}
}
SDKを使って強制アップデート情報を取得する
ForceUpdateView
というViewを用意して、表示時に強制アップデートの判定を行います。
まずはAPIから設定情報を取得してみましょう。
import SwiftUI
import MicrocmsSDK
struct ForceUpdateView: View {
let client: MicrocmsClient
init() {
self.client = MicrocmsClient(
serviceDomain: "<YOUR_SERVICE_DOMAIN>",
apiKey: "<YOUR_API_KEY>"
)
}
var body: some View {
Text("強制アップデートを確認")
.padding(12)
.navigationTitle("強制アップデート")
.navigationBarTitleDisplayMode(.inline)
.onAppear {
// 画面表示時にリクエスト
fetchForceUpdate()
}
}
private func fetchForceUpdate() {
client.get(
endpoint: "force_update") { result in
switch result {
case .success(let object):
if let object = object as? [String: Any],
let forceUpdate = ForceUpdate(dict: object) {
// 設定情報を表示
print(forceUpdate)
}
case .failure(let error):
print("[ERROR]: \(error)")
}
}
}
}
画面を表示すると強制アップデートの情報が取得され、コンソールに内容が出力されるはずです。
ForceUpdate(title: "アップデートのお願い", message: "現在のバージョンではご利用いただけません。\nストアより最新版のアプリへのアップデートをお願いします。", startDate: 2021-09-08 01:00:00 +0000, endDate: 2021-10-30 15:00:00 +0000, minAppVersion: "1.0.0", maxAppVersion: "2.9.9", buttonTitle: "アップデートする", url: https://blog.microcms.io/)
管理画面で入稿した通りのものを受け取れていますね。この情報を使って強制アップデートを出すかどうか判断しましょう。
以下のように実装を変更します。
import SwiftUI
import MicrocmsSDK
struct ForceUpdateView: View {
let client: MicrocmsClient
init() {
self.client = MicrocmsClient(
serviceDomain: "<YOUR_SERVICE_DOMAIN>",
apiKey: "<YOUR_API_KEY>"
)
}
@State var forceUpdate: ForceUpdate?
@State var showingAlert: Bool = false
var body: some View {
VStack(alignment: .leading) {
if forceUpdate != nil {
Text("強制アップデート取得済み")
} else {
ProgressView("強制アップデートの情報を取得中...")
}
Spacer()
}
.padding(12)
.navigationTitle("強制アップデート")
.navigationBarTitleDisplayMode(.inline)
.alert(isPresented: $showingAlert, content: {
Alert(title: Text(forceUpdate!.title),
message: Text(forceUpdate!.message),
dismissButton: Alert.Button.default(Text(forceUpdate!.buttonTitle), action: {
UIApplication.shared.open(forceUpdate!.url, options: [:], completionHandler: nil)
}))
})
.onAppear {
fetchForceUpdate()
}
}
private func fetchForceUpdate() {
client.get(
endpoint: "force_update") { result in
switch result {
case .success(let object):
if let object = object as? [String: Any],
let forceUpdate = ForceUpdate(dict: object) {
self.forceUpdate = forceUpdate
self.showingAlert = shouldShowDialog()
}
case .failure(let error):
print("[ERROR]: \(error)")
}
}
}
private func shouldShowDialog() -> Bool {
guard let forceUpdate = forceUpdate else { return false }
let date = Date()
if forceUpdate.startDate <= date && date <= forceUpdate.endDate {
let currentVersionString = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
guard let currentVersionString = currentVersionString else {
return false
}
let currentVersion = Version(currentVersionString)
let minVersion = Version(forceUpdate.minAppVersion)
let maxVersion = Version(forceUpdate.maxAppVersion)
return minVersion <= currentVersion && currentVersion <= maxVersion
}
return false
}
}
バージョン比較のためのクラス Version
は以下のように定義しています。
struct Version: Equatable, Comparable {
public let numbers: [Int]
init(_ version: String) {
self.numbers = version.components(separatedBy: ".").compactMap { Int($0) }
}
static func < (lhs: Version, rhs: Version) -> Bool {
let length = max(lhs.numbers.count, rhs.numbers.count)
for index in (0...length) {
let left = lhs.numbers.count > index ? lhs.numbers[index] : 0
let right = rhs.numbers.count > index ? rhs.numbers[index] : 0
if left != right {
return left < right
}
}
return false
}
}
強制アップデートの条件に合致した場合、以下のようなアップデートを促すアラートが表示されます。
管理画面から強制アップデートの対象バージョンや期間を変更し、条件によって発動の有無が変更することを確認してみてください。
環境
本記事は以下のバージョンで確認しています。バージョンの差異によって若干機能が異なる可能性があります。
- Xcode 12.5
- Swift 5.4
おわりに
強制アップデートを実装する方法を紹介しました。microCMSを利用することで対象となる期間やバージョンの管理が簡単になり、また承認プロセスなどのワークフローも組みやすくなります。この記事がご参考になれば嬉しいです。
-----
microCMSは日々改善を進めています。
ご意見・ご要望は管理画面右下のチャット、公式Twitter、メールからお気軽にご連絡ください!
引き続きmicroCMSをよろしくお願いいたします!