Swift & iOS

[Swift & iOS] 앱 업데이트 알림 기능 구현 관련

jkkooooooo 2022. 4. 7. 16:23
반응형

최근 개인 프로젝트를 앱스토어에 출시하였습니다. 앱스토어에 등록 한 뒤 이것저것 피드백들을 받아 앱을 업데이트 하였는데요

사용자들 한테는 앱 업데이트를 어떻게 알려야 할까요??

보통 아이폰 설정을 보면 자동 다운로드 설정이 있습니다. 자동 다운로드를 설정해 놓으면 새벽시간에 자동으로 업데이트를 해줍니다.

하지만 이 기능을 꺼놨다면 앱 업데이트 관련해서 앱을 실행해야만 알 수 있습니다. 앱을 실행 시켰을 때 업데이트 유무를 판단해서 사용자에게 알림을 보여줘야합니다.

 

그래서 처음에 업데이트 알림 관련한 기능을 필수적으로 설계해야 한다고 생각합니다.

 

업데이트 방식

업데이트이 방식에는 강제 , 선택이 있습니다. 

강제 업데이트 경우 버그나 호환 관련해서 앱 사용이 어려울 때 앱의 사용자 모두 필수적으로 업데이트를 할 수 있게 하는 방식이며,

선택 업데이트 경우 새로운 버전의 앱이 올라왔지만 굳이 업데이트를 안해도 앱을 사용 할 수 있을때 선택적으로 업데이트를 할 수있게 하는 방식입니다. 

 

업데이트 로직

이번 저의 프로젝트에서는 사용자가 앱을 실행하게 되면 현재 버전최소 지원 버전을 비교하게 됩니다.

 

1. 현재 버전 < 최소 지원 버전

현재 버전이 최소 지원 버전 보다 낮다면 강제 업데이트 방식으로 버전을 올리게 했습니다.

 

2. 현재 버전 > 최소 지원 버전 && 현재 버전 < 최신 버전 

현재 버전이 최소 지원 버전 보단느 높고 최신 버전 보다는 낮을 때 선택 업데이트 방식으로 지금 바로 업데이트를 할 지 아니면 추후에 할 지 선택하는 방식으로 했습니다.

 

업데이트 기능 코드

먼저 나의 최신 앱 버전을 받아 옵니다.

url에 appleID는 앱 출시 후 자동으로 생성 되는 앱의 고유 ID입니다. 

 guard let url = URL(string: "http://itunes.apple.com/lookup?id=\(appleID)"),
       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

아래 코드는 현재 설치된 앱의 버전을 가져옵니다.

static let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String

 

앱의 최소 지원 버전의 경우 아래 이미지와 같이 서버 따로 저장을 해두었습니다.

 

 

이렇게 3가지 정보 현재 버전, 최소 지원 버전, 최신 버전을 가지고 비교를 하게 됩니다.

compareVersion 함수는 두개의 버전을 받아 비교를 하는 함수 입니다. 

(ComparisonResult는 다음에 포스팅 하도록 하겠습니다.)

 

현재 저의 버전 형식은 "1.0", "1.1" 과 같은 String 타입으로 사용합니다. Swift에서 제공하는 compare함수를 사용하면 문자열이라도 비교가 가능하지만 단순 숫자를 비교하는 것이 아닌 ASCII 값으로 비교를 하게 되어 따로 Int로 형변환하여 비교하는 함수를 만들었습니다.

 

현재 버전 : "1.1"

최소 지원 버전: "1.0"  

 

일 때 먼저 "." 을 기준으로 하여 split 하여 [1 , 1] , [1, 0] 과 같이 만들어 두 버전의 0번째 인덱스 끼리의 값과 1번째 인덱스 끼리 비교를 하게 하여  < > = 값을 return 하게 됩니다.

 

return받을 값을 바탕으로 최소 지원 버전보다 작은지와 같은 조건을 사용하여 강제 업데이트 대상인지 선택 업데이트 대상인지 판단하게 됩니다.

  if self.compareVersion(versionA: currentVersion, versionB: minimumVersion) == ComparisonResult.orderedAscending {
            // 강제 업데이트 방식
            let alert = UIAlertController(title: "업데이트 필수", message: "필수 업데이트가 있습니다. \(latestVersion)버전으로 업데이트 하세요.", preferredStyle: .alert)
            alert.addAction(.init(title: "업데이트", style: .default, handler: {_ in
            	// 앱스토어로 이동
                CheckAppVersion.openAppStore(urlStr: CheckAppVersion.url)
            }))
            DispatchQueue.main.async {
                if let vc = UIApplication.shared.windows.filter({$0.isKeyWindow}).first {
                    let ds = vc.visibleViewController
                      ds!.present(alert, animated: true, completion: nil)
                  }
            }

        } else if self.compareVersion(versionA: currentVersion, versionB: minimumVersion) == ComparisonResult.orderedDescending &&
            self.compareVaersion(versionA: currentVersion, versionB: latestVersion) == ComparisonResult.orderedAscending {
            // 최소 업데이트 방식
                let alert = UIAlertController(title: "업데이트 가능", message: "캠토리지의 새로운 버전이 있습니다. \(latestVersion)버전으로 업데이트 할 수 있습니다.", preferredStyle: .alert)
                alert.addAction(.init(title: "업데이트", style: .default, handler: {_ in
	                // 앱스토어로 이동
                    CheckAppVersion.openAppStore(urlStr: CheckAppVersion.url)
                }))
                alert.addAction(.init(title: "다음에", style: .default, handler: {_ in
                    emitter.onNext(())
                    emitter.onCompleted()
                }))
                DispatchQueue.main.async {
                    if let vc = UIApplication.shared.windows.filter({$0.isKeyWindow}).first {
                        let ds = vc.visibleViewController
                          ds!.present(alert, animated: true, completion: nil)
                      }
                }
            } else {
            	// 업데이트 알림 안하고 메인 화면으로 이동	
            }

private func compareVersion(versionA:String, versionB:String) -> ComparisonResult {
        
        let majorA = versionA.split(separator: ".").map{Int($0)!}[0]
        let majorB = versionB.split(separator: ".").map{Int($0)!}[0]

        if majorA < majorB {
            return ComparisonResult.orderedAscending
        } else if majorB < majorA {
            return ComparisonResult.orderedDescending
        }
        
        let minorA = versionA.split(separator: ".").map{Int($0)!}[1]
        let minorB = versionB.split(separator: ".").map{Int($0)!}[1]
        
        if minorA < minorB {
            return ComparisonResult.orderedAscending
        } else if minorB < minorA {
            return ComparisonResult.orderedDescending
        }
        
        return ComparisonResult.orderedSame
    }

 

코드를 적용하고 나면 버전을 체크하여 Alert가 뜨게 됩니다. 

강제 업데이트의 경우 업데이트를 해야만 앱을 사용 할 수 있게됩니다.

강제 업데이트 화면

 

선택 업데이트는 다음에를 누르게 되면 다음 화면으로 넘어가서 정삭적으로 앱을 사용할 수 있습니다.

선택 업데이트

 

 

 

오늘은 업데이트 기능에 대해 작성해봤습니다. 

처음 배포를 하면서 역시 설계가 잘 되어있어야하는구나를 느꼈습니다. 더 공부해야지,,

반응형