호댕의 iOS 개발

[iOS] 위젯 도입기 - UserDefaults에 저장된 값 Widget Extension에 공유하기 (AppGroup) 본문

Software Engineering/iOS

[iOS] 위젯 도입기 - UserDefaults에 저장된 값 Widget Extension에 공유하기 (AppGroup)

호르댕댕댕 2023. 7. 31. 16:25

App Group은 왜 필요한 것일까?

기존 앱과 Extension의 경우 각자 서로의 데이터 컨테이너를 가지고 있으며, 이에 직접 엑세스할 순 없다. 

하지만 데이터 공유를 활성화 할 수는 있다! 바로 AppGroup을 통해서 말이다. 

 

이를 활성화하게 되는 경우  NSUserDefaults API를 사용해서 사용자의 기본 설정에 대한 값에 엑세스를 할 수 있다. 

즉 앱에서 UserDefaults로 저장해놓은 값을 Extension에서도 접근이 가능하게 되는 것이다. 

Extension Scenarios

 

App Extension Programming Guide: Handling Common Scenarios

App Extension Programming Guide

developer.apple.com

위 그림처럼 서로 다른 프로세스와 컨테이너를 갖지만 App Group을 통해 공유 가능한 Container를 가질 수 있는 것이다.

 

따라서 Widget Extension에서도 App에서 저장했던 UserDefaults 값에 접근하려면 AppGroup을 설정해야 한다.

 

그렇다면 AppGroup은 어떻게 설정할 수 있을까?

 

AppGroup은 어떻게 설정할까?

일단 Targets에서 앱을 선택한 뒤 Signing & Capabilities에 들어가 capability를 추가해주면 된다. 

여기서 App Group을 추가해주면 되고 AppGroups에 + 버튼을 누르면 group.은 자동으로 붙어있다. 

 

나는 뒤에 BundleIdentifier를 붙여서 작업을 진행했다. 

 

이렇게 하면 Apple Developer 개발자 계정으로 들어가 Identifier 쪽을 확인하면 추가한 App Group Identifier를 확인할 수 있다. 

여기서 중요한 점은 AppGroups로 공유할 Extension의 Target도 AppGroup Capability를 추가해줘야 한다는 것이다. 

생각해보면 당연한 것인데 막상 처음 다루다보니 이를 생각하지 못하고 왜 공유가 안되나 한참 고민을 했다. 

 

요걸 등록해줘야 Container를 공유해서 사용할 수 있다. 

 

 

 

App Group을 통해 공유 가능한 Container를 만드는 것은 아주 간단하다. 

var userDefaults = UserDefaults(suiteName: "{App Groups ID}")!

이렇게 선언해주면 된다.

기존 UserDefaults.standard를 사용하면 각 Container만 접근해서 사용하는데 반해, 이는 AppGroup을 Capability로 추가한 Target에선 공유가 가능한 것이다.

 

그리고 기존에 UserDefaults.standard에 저장한 값이 있다면 아래와 같은 방법을 사용해야 한다. 
나는 앱이 시작할 때 마이그레이션을 할 수 있도록 AppDelegatefunc application(_:didFinishLaunchingWithOptions:)에서 아래 코드를 호출해줬다. 

 

if !LocalDBHandler.shared.isMigrate {
    UserDefaults.standard.dictionaryRepresentation().forEach { key, value in
        LocalDBHandler.shared.userDefaults.setValue(value, forKey: key)
    }

    LocalDBHandler.shared.isMigrate = true
}

여기서 dictionaryRepresentation()을 사용하면 기존에 저장한 값들을 Key / Value 형태로 확인할 수 있다. 

그런데 여기에는 내가 넣은 적이 없던 값들도 들어있었다. 기본적으로 들어있는 값인 것 같다.

 

struct LocalDBHandler {
    static var shared = LocalDBHandler()
    private let inputKey = "input"
    private let isMigrateKey = "is_migrate"
    
    private init() { }
    
    var userDefaults = UserDefaults(suiteName: "group.com.hojoon.JTAppleCalendarExample")!
    
    var input: String {
        get {
            userDefaults.string(forKey: inputKey) ?? "입력 내용 없음"
        }
        set {
            userDefaults.setValue(newValue, forKey: inputKey)
        }
    }
    
    var isMigrate: Bool {
        get {
            userDefaults.bool(forKey: isMigrateKey)
        }
        set {
            userDefaults.setValue(newValue, forKey: isMigrateKey)
        }
    }
}

기존 UserDefaults.standard를 사용하던 부분도 UserDefaults(suiteName: "App Group ID")를 사용하도록 변경했다.

 

이렇게 한 후 LocalDBHandler의 Target을 Widget Extension에서도 사용할 수 있도록 추가해주면!

이렇게 App에서 UserDefaults로 등록해놓은 가나다라 라는 값을 위젯에서도 접근해서 확인할 수 있다. 

Comments