[iOS] 위젯 도입기 - UserDefaults에 저장된 값 Widget Extension에 공유하기 (AppGroup)
App Group은 왜 필요한 것일까?
기존 앱과 Extension의 경우 각자 서로의 데이터 컨테이너를 가지고 있으며, 이에 직접 엑세스할 순 없다.
하지만 데이터 공유를 활성화 할 수는 있다! 바로 AppGroup을 통해서 말이다.
이를 활성화하게 되는 경우 NSUserDefaults API를 사용해서 사용자의 기본 설정에 대한 값에 엑세스를 할 수 있다.
즉 앱에서 UserDefaults로 저장해놓은 값을 Extension에서도 접근이 가능하게 되는 것이다.
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에 저장한 값이 있다면 아래와 같은 방법을 사용해야 한다.
나는 앱이 시작할 때 마이그레이션을 할 수 있도록 AppDelegate의 func 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로 등록해놓은 가나다라 라는 값을 위젯에서도 접근해서 확인할 수 있다.