Как использовать структуру WeatherKit Swift для получения информации о погоде внутри расширения виджета?
Я не могу получить данные о погоде с помощью фреймворка WeatherKit внутри расширения виджета.
Вот проект, который я создал только для этого примера. Этот виджет показывает влажность места образца.
Вот код:
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])
}
}
В симуляторе работает нормально:
Но это не работает в реальном устройстве. Как только я позвонюWeatherService
хweather(for: CLLocation) async throws -> Weather
виджет "заблокирован".
&lt;img alt="заблокированный виджет" src="https://i.stack.imgur.com/bxJOy.jpg"/&gt;
Я попытался переместитьtry await WeatherService.shared.weather(for: sampleLocation)
в разные места, но ничего не получалось. Как только я закомментирую эту строку (и создам запись с заполнителем влажности), все заработает.
Я добавил возможность WeatherKit в цель основного приложения и в цель WidgetExtension. Я также добавил WeatherKit «Возможности» и «Служба приложений» в «Сертификаты, идентификаторы и профили» веб-сайта Apple Developer.
Фреймворк WeatherKit отлично работает в других частях основного приложения.
Я еще не пробовал использовать REST API WeatherKit.
Любые идеи, что может происходить?
1 ответ
Вы должны установить свою запись для использованияResult
, таким образом вы можете визуализировать любые возникающие ошибки.
struct SimpleEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationIntent
let result: Result<any CurrentWeatherProtocol, Error>
}
Затем в представлении вы можете либо представить ошибку, либо представление погоды.
struct PWCWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
Text(entry.date, style: .time)
switch entry.result{
case .success(let weather):
Image(systemName: weather.symbolName)
case .failure(let error):
Text(error.localizedDescription)
let nserror = error as NSError
Text(nserror.userInfo.description)
Text("\(error)")
}
}
}
Вся моя кодовая база является частью гораздо более сложного проекта, но это то, чтоgetTimeline
выглядит как.
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
Task{
let now = Date.now
let inHr = Calendar.current.date(byAdding: .hour, value: 1, to: now)!
do{
let location = try await locSvc.requestSingleLocation()
let wSvc = try await CDWeatherService().currentWeather(for: WeatherEntry(location: .init(location: location)))
//Return a successful result
let entry = SimpleEntry(date: now, configuration: configuration, result: .success(wSvc))
let timeline = Timeline(entries: [entry], policy: .after(inHr))
completion(timeline)
}catch{
//Return a failure result
let entry = SimpleEntry(date: now, configuration: configuration, result: .failure(error))
let timeline = Timeline(entries: [entry], policy: .after(inHr))
completion(timeline)
}
}
}
2 вещи, которые, как я обнаружил, являются моими проблемами, — это расширения виджетов для macOS и iOS, вы должны убедиться, что выбрали правильный.
Кроме того, убедитесь, что вы добавили «WeatherKit» в «Подписание и возможности» расширения виджета.
WeatherDaemon.WDSJWTAuthenticatorServiceListener.Errors ошибка 2.
Было связано с тем, что Weather Kit не был включен в «Службы приложений» в AppStore Connect, он должен быть включен в App Store Connect — Идентификатор виджета — Возможности
App Store Connect — идентификатор виджета — AppServices
Подписание и возможности в Xcode для приложения и/или виджета