iOS 14 WidgetKit Pt 3 | Building COVID-19 API Stats | Widget Bundle & Deeplink URL
extension UserDefaults {
static var shared: UserDefaults {
UserDefaults(suiteName: "group.junyeongPark.Covid19Stats") ?? .standard
}
}
capabilities
내 앱 그룹을 설정suiteName
으로 사용한 공유용 유저 디폴트 설정@Published private(set) var watchlist: [Country] = [] {
didSet {
save(countries: watchlist)
WidgetCenter.shared.reloadTimelines(ofKind: "WatchlistStatsWidget")
}
}
ObservableObject
로 선언한 뷰 모델 내 watchlist
퍼블리셔 값이 업데이트될 때마다 해당 값을 유저 디폴트 내에 저장 및 위젯 업데이트 private func loadCountriesFromUserDefaults() -> [Country]? {
let userDefaults = UserDefaults.shared
guard
let watchlist = userDefaults.object(forKey: "watchlist") as? Data,
let countries = try? decoder.decode([Country].self, from: watchlist) else {
return nil
}
return countries
}
loadCountriesFromUserDefaults
함수var url: URL {
let urlString = "stats://watchlist?id=\(id)&name=\(name)&iso=\(iso)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
guard
let urlString = urlString,
let url = URL(string: urlString) else { fatalError() }
return url
}
Country
자료 구조의 연산 프로퍼티로 추가된 url
프로퍼티Country
데이터를 구성하는 프로퍼티를 쿼리로 가지고 있기 때문에 해당 URL 쿼리 아이템을 통해 해당 데이터 구성 가능 var body: some View {
ZStack {
if entry.countryCases.isEmpty {
Link(destination: url) {
Text("Add countries to watchlist from the App")
.foregroundColor(.blue)
.padding()
}
} else {
VStack(spacing: 0) {
HStack {
Spacer()
Text("Watchlist")
Spacer()
Text(entry.date, style: .date)
Text(entry.date, style: .time)
Spacer()
}
.font(.system(size: 12, weight: .semibold))
.padding(.vertical, 4)
.padding(.horizontal)
Divider()
ForEach(entry.countryCases.prefix(family == .systemMedium ? 2 : 4), id: \.country) { countryCase in
Link(destination: countryCase.country.url) {
if let caseStats = countryCase.caseStats {
WatchlistWidgetRowView(country: countryCase.country, caseStats: caseStats)
} else {
Text(countryCase.country.displayName)
} }
}
}
}
}
.redacted(reason: entry.isPlaceholder ? .placeholder : .init())
}
WatchlistStatsWidgetEntryView
의 특정 아이템을 클릭할 때 해당 Country
아이템이 가지고 있는 URL 정보를 통해 딥링크 연결 .sheet(item: $selectedCountry, onDismiss: {
selectedCountry = nil
}) { country in
CountryDetailView(country: country)
}
.onOpenURL { url in
selection = url.host ?? "summary"
guard let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems else {
self.selectedCountry = nil
return
}
var dict = [String: String]()
queryItems.forEach { item in
dict[item.name] = item.value
}
guard
let id = dict["id"],
let name = dict["name"],
let iso = dict["iso"]
else {
selectedCountry = nil
return
}
self.selectedCountry = Country(id: id, name: name, iso: iso)
}
selectedCountry
를 구성@State
변수 값이 옵셔널이 아닐 때 곧바로 해당 값을 통해 파라미터로 넘겨준 디테일 뷰를 모달 시트로 띄우기위젯을 통한 실제 뷰 링크 연결은 위젯의 편의성을 극대화한다!