'WidgetKit not work for an Intent Handler to Provide Dynamic Values
I am trying to implement a widget where the user can choose a city dynamically via an intent.
I followed the step by step guide provided by apple here: https://developer.apple.com/documentation/widgetkit/making-a-configurable-widget
I think I have done everything correctly but the result I have is always this:
I can see the list of cities but when I select one the screen goes black, as seen in the video and the debug crashes. Both on simulator and device.
My goal is to have the city selected within the widget's getTimeline
Here is the code I use:
IntentHandler.swift in SiriIntent's target:
import Intents
class IntentHandler: INExtension, DynamicCitySelectionIntentHandling {
func provideCity_paramOptionsCollection(for intent: DynamicCitySelectionIntent, with completion: @escaping (INObjectCollection<City>?, Error?) -> Void) {
let dataSource = PersistenceController.shared.getAllForecastDataCoreData()
let coreDataCities: [City] = dataSource.map { cityCoreData in
let city = City(identifier: "\(cityCoreData.cityID ?? -1)", display: cityCoreData.cityName ?? "")
return city
}
let collection = INObjectCollection(items: coreDataCities)
completion(collection, nil)
}
override func handler(for intent: INIntent) -> Any {
return self
}
}
Part of code in Widget class:
import WidgetKit
import SwiftUI
import Combine
import MapKit
typealias Entry = ForecastEntry
struct Provider: IntentTimelineProvider {
let snapshotEntry = Entry(date: Date(), forecastViewModel: .initForPlaceholder())
func placeholder(in context: Context) -> ForecastEntry {
snapshotEntry
}
public func getSnapshot(
for configuration: DynamicCitySelectionIntent,
in context: Context,
completion: @escaping (Entry) -> Void
) {
let entry = snapshotEntry
completion(entry)
}
public func getTimeline(
for configuration: DynamicCitySelectionIntent,
in context: Context,
completion: @escaping (Timeline<Entry>) -> Void
) {
let currentDate = Date()
let correctDate = Calendar.current.date(byAdding: .second, value: 150, to: currentDate)
WidgetServiceManager.shared.fetchWeather(forCityId: configuration.city_param?.identifier ?? "") { data in
guard let _data = data else { return }
let entry = Entry(date: currentDate,
forecastViewModel: ForecastCardViewModel(weatherModel: _data,
isForUserPosition: false))
let timeline = Timeline(entries: [entry],
policy: .after(correctDate ?? Date()))
completion(timeline)
}
}
}
@main
struct WeatherAppWidget: Widget {
let kind: String = "WeatherAppWidget"
init() {
}
var body: some WidgetConfiguration {
IntentConfiguration(
kind: kind,
intent: DynamicCitySelectionIntent.self,
provider: Provider()
) { entry in
WeatherAppWidgetEntryView(entry: entry)
}
.configurationDisplayName("Weather Widget")
.description("Forecasts in your location.")
.supportedFamilies([.systemMedium, .systemSmall])
}
}
.intentdefinition file:
Solution 1:[1]
struct LargeWidgetEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationIntent
}
Use configuration
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Sanket Shah |