microCMS

アプリの強制アップデート設定情報をmicroCMSで配信する

ひまらつ

この記事は公開後、1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちはひまらつです。

この記事ではアプリの強制アップデート機能を実装していきます。

互換性のない変更がバックエンドで発生した時など、アプリのサポートバージョンを制限したい時に使われるのが強制アップデートです。
対象バージョンや期間などが書かれた設定ファイルをサーバーに置く必要がありますが、それを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をよろしくお願いいたします!

まずは、無料で試してみましょう。

APIベースの日本製ヘッドレスCMS「microCMS」を使えば、 ものの数分でAPIの作成ができます。

microCMSを無料で始める

microCMSについてお問い合わせ

初期費用無料・14日間の無料トライアル付き。ご不明な点はお気軽にお問い合わせください。

お問い合わせ

microCMS公式アカウント

microCMSは各公式アカウントで最新情報をお届けしています。
フォローよろしくお願いします。

  • X
  • Discord
  • github

ABOUT ME

ひまらつ
SwiftやPythonやスプラトゥーンを楽しんでます