티스토리 뷰
iOS13+ 사용가능
과거엔 Today Extension 으로 존재했다. (iOS 12까지만 사용가능) - 새롭게 추가 X , 엑스코드에서 사라짐
업데이트 기능
iOS 16 → 잠금화면에 추가 가능
iOS 17 → MacDesktop, iPad잠금화면, StandBy, Watch Smart Stack ...
containerBackground(.fill.tertiary, for: .widget) : 잠금화면에서 위젯 띄울 때 컬러 자연스럽게 변화되는 기능
위젯 특징
- 업데이트 주기가 불명확하다. 하루에 업데이트 40~70번 제한 (1시간마다 업데이트하겠다고 선택해도 대략 한 시간임)
데이터 변화 시 강제로 위젯을 업데이트하는 방법이 존재하긴 함(아래 참고) - 메모리 제한. 30MB
- .systemSmall, .systemMedium, . systemLarge 사이즈 선택 가능
- small 사이즈는 버튼 제약이 있음
Widget Configuration
Static - 위젯을 꾹 눌렀을 때 Edit Widget 불가능
Intent - 위젯을 꾹 눌렀을 때 Edit Widget 가능
구성
Provider (위젯 디스플레이 업데이트 시기를 WidgetKit에게 알려주기 위한 용도)
Entry
EntryView
Widget
AppGroup
위젯도 또 하나의 타겟이기 때문에 데이터를 같이 쓰고 싶다면, 다른 타겟에 대해 데이터를 공유해야한다.
ex) 앱과 위젯에서 같은 키로 UserDefault를 저장해도 저장 공간이 달라서 공유가 안 됨 → Optional Shared
앱과 위젯의 App Groups를 동일하게 설정
✔️ UserDefaults 의 경우
extension UserDefaults {
static var groupShared: UserDefaults {
let appGroupID = "group.com.dailydrops" // 만든 앱 그룹
return UserDefaults(suiteName: appGroupID)!
}
}
UserDefaults.groupShared.set("", forKey: "key")
UserDefaults.groupShared.string(forKey: "key")
✔️ Realm 공유할 경우
// MARK: Migration
let defaultURL = Realm.Configuration.defaultConfiguration.fileURL!
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.dailydrops") // 만든 앱 그룹
let realmURL = containerURL?.appendingPathComponent("default.realm")
if FileManager.default.fileExists(atPath: defaultURL.path) {
do {
_ = try FileManager.default.replaceItemAt(realmURL!, withItemAt: defaultURL)
configuration = Realm.Configuration(fileURL: realmURL, schemaVersion: 1)
} catch {
print("Error: \(error)")
}
} else {
configuration = Realm.Configuration(fileURL: realmURL, schemaVersion: 1)
}
Realm.Configuration.defaultConfiguration = configuration
기존 Container에 저장되어있는 데이터들을 옮겨야해서 Migration 코드 필요
private var realm: Realm {
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.dailydrops") // 만든 앱 그룹
let realmURL = containerURL?.appendingPathComponent("default.realm")
let config = Realm.Configuration(fileURL: realmURL, schemaVersion: 1)
return try! Realm(configuration: config)
}
private let realm = try! Realm()
으로 사용했던 것을 위에 코드로 변경해서 공유할 수 있는 Container에 저장하도록 변경
Target Membership 체크해줘야 위젯에서도, 내 앱에서도 접근 가능하다.
데이터 변화 시 Widget도 업데이트하기
import Foundation
import WidgetKit
protocol WidgetUpdate { }
extension WidgetUpdate {
func widgetUpdate() {
WidgetCenter.shared.reloadTimelines(ofKind: "WaterWidget") // WidgetID
}
}
Widget reload 하는 메서드를 가지고 있는 protocol 생성하여
업데이트를 하고 싶은 곳에 protocol을 채택하여 widgetUpdate() 메서드를 실행해준다
(그냥 업데이트하고 싶은 곳에서 WidgetCenter.shared.reloadTimelines(ofKind: "WaterWidget") 해주면 되지만 WidgetKit을 import 해야해서 protocol로 분리)
(WidgetID는 Widget struct에 kind 상수값)
물 섭취 시 realm 데이터 저장 -> 데이터 공유 -> Widget Reload