프로젝트 작업 중 아찔한 이슈를 발견했었다... 그러나 이미 배포된 상태...
지금이야 괜찮지만 나중에 유저가 많아지게 된다면 아찔에 아찔에 아찔을 더해서..
때문에 강제 업데이트 알럿을 설정해주기로 했다. 그 전에, 앱스토어에 올라갈 앱이 App Store Connect에 등록이 되어 있어야 하고, AppID를 알고 있어야만 해당 사항을 처리할 수 있다.
우선 버전 체크를 위해서 AppStoreCheck.swift 파일을 만들어주었다.
// AppStoreCheck.swift
import UIKit
class AppStoreCheck {
// 앱 자체의 버전 정보를 확인한다.
static let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
// 앱스토어 링크
static let appStoreOpenUrlString = "itms-apps://itunes.apple.com/app/apple-store/(여기에AppID)"
// 앱스토어에 올라와있는 버전 정보
func latestVersion() -> String? {
let appleID = "(여기에AppID)"
guard let url = URL(string: "http://itunes.apple.com/lookup?id=\(appleID)&country=kr"),
let data = try? Data(contentsOf: url),
let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any],
let results = json["results"] as? [[String: Any]],
let appStoreVersion = results[0]["version"] as? String else {
return nil
}
return appStoreVersion
}
// 앱스토어로 이동
func openAppStore() {
guard let url = URL(string: AppStoreCheck.appStoreOpenUrlString) else { return }
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
}
이렇게 구성을 해주었다.
원래는 해당 내용을 스플래시 화면에서 진입 전에 띄워주려고 하였으나, 스플래시 화면이 빠르게 사라진다는 이슈를 발견하였고, 서비스 특성 상 경우에 따라 rootViewController가 다양하게 달라지기 때문에 ViewController에서 설정하는 것이 어려웠다.
또한 백그라운드에서 포그라운드로 진입 시에도 버전을 체크하여 업데이트 알럿을 띄워야 했기 때문에 SceneDelegate에서 설정해주었다.
// SceneDelegate.swift
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
...
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: windowScene)
...
let viewController = ViewController()
window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
self.checkAndUpdateIfNeeded() //모든 makeKeyAndVisible뒤에 설정
...
}
// 백그라운드에서 포그라운드가 될 때 거치는 함수에도 넣어줌
func sceneWillEnterForeground(_ scene: UIScene) {
checkAndUpdateIfNeeded()
}
...
// 업데이트가 필요한지 확인하는 함수
func checkAndUpdateIfNeeded() {
// 현재 앱스토어에 있는 버전
let marketingVersion = AppStoreCheck().latestVersion() ?? ""
// 현재 프로젝트의 버전
let currentProjectVersion = AppStoreCheck.appVersion ?? ""
// 앱스토어에 있는 버전을 .마다 나눈 것 (예: 1.2.1 버전이라면 [1, 2, 1])
let splitMarketingVersion = marketingVersion.split(separator: ".").map { $0 }
// 현재 프로젝트 버전을 .마다 나눈 것
let splitCurrentProjectVersion = currentProjectVersion.split(separator: ".").map { $0 }
// [Major].[Minor].[Patch] 중 [Major]을 비교하여 앱스토어에 있는 버전이 높을 경우 알럿 띄우기
if splitCurrentProjectVersion[0] < splitMarketingVersion[0] {
showUpdateAlert(version: marketingVersion)
// [Major].[Minor].[Patch] 중 [Minor]을 비교하여 앱스토어에 있는 버전이 높을 경우 알럿 띄우기
} else if splitCurrentProjectVersion[1] < splitMarketingVersion[1] {
showUpdateAlert(version: marketingVersion)
// 나머지 상황에서는 업데이트 알럿을 띄우지 않음
} else {
print("현재 최신 버젼입니다.")
}
}
// 알럿을 띄우는 함수
func showUpdateAlert(version: String) {
let alert = UIAlertController(
title: "업데이트 알림",
message: "\(version)으로의 업데이트 사항이 있습니다. 앱스토어에서 앱을 업데이트 해주세요.",
preferredStyle: .alert
)
// 업데이트 버튼을 누르면 앱스토어로 이동
let updateAction = UIAlertAction(title: "업데이트", style: .default) { _ in
AppStoreCheck().openAppStore()
}
alert.addAction(updateAction)
window?.rootViewController?.present(alert, animated: true, completion: nil)
}
}
이렇게 Major와 Minor이 차이가 날 때만 처리를 해주었다. 때문에 강제 업데이트 관련하여 컨벤션과 어떤 경우에 강제 업데이트를 시킬 것인지 정하는 것도 중요할 것 같다~!!
이렇게 하면 백그라운드 -> 포그라운드 진입 시에도 업데이트가 필요하다면 알럿을 띄우기 때문에 업데이트를 하지 않고 앱을 사용할 수 없게 된다. 이 부분까지 신경써줘야 하는 게 개발자의 할 일인 것 같다... 파이팅