I can't fetch the weather using the WeatherKit framework inside a Widget Extension.
Here's a project I created just for this example. This widget shows the humidity of a sample location.
Here's the code:
import WidgetKit
import SwiftUI
import WeatherKit
import CoreLocation
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), humidity: 9.99) // placeholder humidity
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), humidity: 9.99) // placeholder humidity
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
Task {
let nextUpdate = Date().addingTimeInterval(3600) // 1 hour in seconds
let sampleLocation = CLLocation(latitude: 51.5072, longitude: 0.1276) // sample location (London)
let weather = try await WeatherService.shared.weather(for: sampleLocation)
let entry = SimpleEntry(date: .now, humidity: weather.currentWeather.humidity)
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
completion(timeline)
}
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let humidity: Double
}
struct WidgetWeatherTestWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
Text("\(entry.humidity)")
}
}
struct WidgetWeatherTestWidget: Widget {
let kind: String = "WidgetWeatherTest"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
WidgetWeatherTestWidgetEntryView(entry: entry)
}
.configurationDisplayName("Widget Weather Test")
.description("Testing weatherkit in a Widget")
.supportedFamilies([.systemMedium])
}
}
It works fine in the simulator:
But it doesn't work in a real device. As soon as I call WeatherService
's weather(for: CLLocation) async throws -> Weather
the widget get's "blocked":
I've tried moving the try await WeatherService.shared.weather(for: sampleLocation)
to different places, but nothing worked. As soon as I comment out this line (and create an entry with a placeholder humidity) everything works.
I added the WeatherKit capability in the main app target and in the WidgetExtension target. I also added the WeatherKit "Capability" and "App Service" in the "Certificates, Identifiers & Profiles" of the Apple Developer website.
The WeatherKit framework works fine in other parts of the main app.
I haven't tried using the WeatherKit REST API, yet.
Any ideas what could be happening?
Got it! Apple Developer portal automatically created an "Identifier" for my WidgetExtension, that's separate from the main app Identifier. I had no idea that's how this worked, I thought I had to create them manually. I added WeatherKit as an AppService there and it worked.