1
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

iOS 新規アップデートを自動でユーザーに知らせる

Last updated at Posted at 2025-04-05

最新バージョンのアップデートがあることをユーザーに知らせ、アップデートに誘導したい。
毎回手動でアプリ内にハードコーディングしたり、Firebase Remote Configで制御するのは運用コストが上がりバグの原因にもなる。
この操作を完全に自動化する。

はじめに

具体的にはAppStoreのAPIを利用して最新バージョンを取得する。
https://itunes.apple.com/lookup?id={APP ID}&country=JP
このAPIを叩くとAppStoreに乗っている様々な情報を取得できる。例えば、最新バージョン、最小のOS、リリースノート、ファイルサイズなどAppStoreに表示されているほとんどの情報が取得できる。ただ、国ごとにLocalizeしている場合Queryでcountry=JPなどと指定する必要がある。
今回はこのうち必要な情報だけパースすることにする。

以下を取得する

public import Foundation

public struct AppStoreAppInfoResponse: Sendable, Codable {
  public let results: [AppStoreAppInfo]
  public init(results: [AppStoreAppInfo]) {
    self.results = results
  }
}

public struct AppStoreAppInfo: Sendable, Codable, Hashable {
  public let version: String
  public let minimumOsVersion: String
  public let trackViewUrl: URL
  public let releaseNotes: String
  public let description: String
  public let fileSizeBytes: String
  public init(version: String, minimumOsVersion: String, trackViewUrl: URL, releaseNotes: String, description: String, fileSizeBytes: String) {
    self.version = version
    self.minimumOsVersion = minimumOsVersion
    self.trackViewUrl = trackViewUrl
    self.releaseNotes = releaseNotes
    self.description = description
    self.fileSizeBytes = fileSizeBytes
  }
}

次に取得したバージョンと現在のバージョンを比較するためComparableに準拠したStructを定義する。

import Foundation

public struct AppSemanticVersion: Sendable, Codable, Hashable {
  public struct VersionError: Error {}

  let major: Int
  let minor: Int
  let patch: Int

  public init(major: Int, minor: Int, patch: Int) {
    self.major = major
    self.minor = minor
    self.patch = patch
  }

  public init(from versionString: String) throws {
    let versionNumbers = versionString.split(separator: ".").compactMap { Int($0) }
    guard versionNumbers.count == 3 else {
      throw VersionError()
    }

    self.major = versionNumbers[0]
    self.minor = versionNumbers[1]
    self.patch = versionNumbers[2]
  }

  public func versionString() -> String {
    "\(major).\(minor).\(patch)"
  }
}

// MARK: Protocol Conformance

extension AppSemanticVersion: Comparable {
  public static func < (lhs: AppSemanticVersion, rhs: AppSemanticVersion) -> Bool {
    if lhs.major != rhs.major {
      return lhs.major < rhs.major
    } else if lhs.minor != rhs.minor {
      return lhs.minor < rhs.minor
    } else {
      return lhs.patch < rhs.patch
    }
  }
}

extension AppSemanticVersion: Equatable {
  public static func == (lhs: AppSemanticVersion, rhs: AppSemanticVersion) -> Bool {
    return lhs.major == rhs.major &&
    lhs.minor == rhs.minor &&
    lhs.patch == rhs.patch
  }
}

これで準備が整ったので実際に最新バージョンを取得するためのAPIを叩く


  /// AppStoreから最新のバージョン情報を取得.
  func getLatestVersionInfo() async -> AppStoreAppInfo? {
    guard let url = URL(string: "https://itunes.apple.com/lookup?id={Apple ID}&country=JP") else { return nil }
    let request = URLRequest(url: url)
    guard let (data, _) = try? await URLSession.shared.data(for: request) else { return nil }
    let response = try? JSONDecoder().decode(AppStoreAppInfoResponse.self, from: data)
    return response?.results.first
  }

また、現在のアプリのバージョンをBundle.mainから取得

let currentVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")

取得したバージョンが最新か調べる

/// AppStoreから取得したAppStoreAppInfoから現在のバージョンが最新であるか確認する
/// フォーマットが不正なことはまず起こり得ないが、起こった場合はtrueを返す.
func isLatestVersion(currentVersion: String, appInfo: AppStoreAppInfo) -> Bool {
    guard let currentAppVersion = try? AppSemanticVersion(from: currentVersion) else { return true }
    guard let newAppVersion = try? AppSemanticVersion(from: appInfo.version) else { return true }
    return currentAppVersion >= newAppVersion
}

以上で最新バージョンを自動で取得でき、最新バージョンがAppStoreに上がっていれば自動でユーザーに知らせることができる

guard let latestVersionInfo = await getLatestVersionInfo(),
      let currentVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String else {
      return 
}
if !isLatestVersion(currentVersion: currentVersion, appInfo: latestVersionInfo) {
    /// アラートなどでユーザーに知らせる
    /// AppStoreAppInfoで最新バージョンのリリースノートもパースしているのでこれを直接表示するなど
}
1
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?