weatherkit by dpearson2699/swift-ios-skills
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill weatherkit使用 WeatherService 获取当前天气状况、小时和每日预报、天气警报以及历史统计数据。必须显示 Apple Weather 的归属信息。目标平台:Swift 6.2 / iOS 26+。
NSLocationWhenInUseUsageDescriptionimport WeatherKit
import CoreLocation
使用共享的单例或创建一个实例。该服务是 Sendable 且线程安全的。
let weatherService = WeatherService.shared
// 或者
let weatherService = WeatherService()
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
获取某个位置的当前天气状况。返回一个包含所有可用数据集的 Weather 对象。
func fetchCurrentWeather(for location: CLLocation) async throws -> CurrentWeather {
let weather = try await weatherService.weather(for: location)
return weather.currentWeather
}
// 使用结果
func displayCurrent(_ current: CurrentWeather) {
let temp = current.temperature // Measurement<UnitTemperature>
let condition = current.condition // WeatherCondition 枚举
let symbol = current.symbolName // SF Symbol 名称
let humidity = current.humidity // Double (0-1)
let wind = current.wind // Wind (速度, 方向, 阵风)
let uvIndex = current.uvIndex // UVIndex
print("\(condition): \(temp.formatted())")
}
默认返回从当前小时开始的连续 25 小时预报。
func fetchHourlyForecast(for location: CLLocation) async throws -> Forecast<HourWeather> {
let weather = try await weatherService.weather(for: location)
return weather.hourlyForecast
}
// 遍历小时
for hour in hourlyForecast {
print("\(hour.date): \(hour.temperature.formatted()), \(hour.condition)")
}
默认返回从今天开始的连续 10 天预报。
func fetchDailyForecast(for location: CLLocation) async throws -> Forecast<DayWeather> {
let weather = try await weatherService.weather(for: location)
return weather.dailyForecast
}
// 遍历天数
for day in dailyForecast {
print("\(day.date): \(day.lowTemperature.formatted()) - \(day.highTemperature.formatted())")
print(" 状况: \(day.condition), 降水概率: \(day.precipitationChance)")
}
使用 WeatherQuery 请求特定日期范围的预报。
func fetchExtendedForecast(for location: CLLocation) async throws -> Forecast<DayWeather> {
let startDate = Date.now
let endDate = Calendar.current.date(byAdding: .day, value: 10, to: startDate)!
let forecast = try await weatherService.weather(
for: location,
including: .daily(startDate: startDate, endDate: endDate)
)
return forecast
}
获取某个位置的活跃天气警报。警报包括严重程度、摘要和受影响区域。
func fetchAlerts(for location: CLLocation) async throws -> [WeatherAlert]? {
let weather = try await weatherService.weather(for: location)
return weather.weatherAlerts
}
// 处理警报
if let alerts = weatherAlerts {
for alert in alerts {
print("警报: \(alert.summary)")
print("严重程度: \(alert.severity)")
print("区域: \(alert.region)")
if let detailsURL = alert.detailsURL {
// 链接到完整的警报详情
}
}
}
仅获取你需要的数据集,以最小化 API 使用量和响应大小。每个 WeatherQuery 类型对应一个数据集。
let current = try await weatherService.weather(
for: location,
including: .current
)
// current 是 CurrentWeather
let (current, hourly, daily) = try await weatherService.weather(
for: location,
including: .current, .hourly, .daily
)
// current: CurrentWeather, hourly: Forecast<HourWeather>, daily: Forecast<DayWeather>
仅在有限区域可用。返回未来一小时内分钟级降水预报。
let minuteForecast = try await weatherService.weather(
for: location,
including: .minute
)
// minuteForecast: Forecast<MinuteWeather>? (如果不可用则为 nil)
| 查询 | 返回类型 | 描述 |
|---|---|---|
.current | CurrentWeather | 当前观测到的状况 |
.hourly | Forecast<HourWeather> | 从当前小时开始的 25 小时 |
.daily | Forecast<DayWeather> | 从今天开始的 10 天 |
.minute | Forecast<MinuteWeather>? | 未来一小时的降水预报(有限区域) |
.alerts | [WeatherAlert]? | 活跃的天气警报 |
.availability | WeatherAvailability | 该位置数据集的可用性 |
Apple 要求使用 WeatherKit 的应用显示归属信息。这是一项法律要求。
func fetchAttribution() async throws -> WeatherAttribution {
return try await weatherService.attribution
}
import SwiftUI
import WeatherKit
struct WeatherAttributionView: View {
let attribution: WeatherAttribution
@Environment(\.colorScheme) private var colorScheme
var body: some View {
VStack(spacing: 8) {
// 显示 Apple Weather 标志
AsyncImage(url: markURL) { image in
image
.resizable()
.scaledToFit()
.frame(height: 20)
} placeholder: {
EmptyView()
}
// 链接到法律归属页面
Link("天气数据来源", destination: attribution.legalPageURL)
.font(.caption2)
.foregroundStyle(.secondary)
}
}
private var markURL: URL {
colorScheme == .dark
? attribution.combinedMarkDarkURL
: attribution.combinedMarkLightURL
}
}
| 属性 | 用途 |
|---|---|
combinedMarkLightURL | 用于浅色背景的 Apple Weather 标志 |
combinedMarkDarkURL | 用于深色背景的 Apple Weather 标志 |
squareMarkURL | 方形 Apple Weather 标志 |
legalPageURL | 法律归属网页的 URL |
legalAttributionText | 无法使用网页视图时的文本替代方案 |
serviceName | 天气数据提供商名称 |
检查给定位置有哪些天气数据集可用。并非所有数据集在所有国家/地区都可用。
func checkAvailability(for location: CLLocation) async throws {
let availability = try await weatherService.weather(
for: location,
including: .availability
)
// 检查特定数据集的可用性
if availability.alertAvailability == .available {
// 可以安全地获取警报
}
if availability.minuteAvailability == .available {
// 该区域提供分钟级预报
}
}
省略归属信息违反了 WeatherKit 服务条款,并可能导致 App Review 被拒。
// 错误:显示天气数据但不包含归属信息
VStack {
Text("72F, Sunny")
}
// 正确:始终包含归属信息
VStack {
Text("72F, Sunny")
WeatherAttributionView(attribution: attribution)
}
每个数据集查询都会计入你的 API 配额。只获取你需要显示的数据。
// 错误:获取所有数据
let weather = try await weatherService.weather(for: location)
let temp = weather.currentWeather.temperature
// 正确:仅获取当前天气状况
let current = try await weatherService.weather(
for: location,
including: .current
)
let temp = current.temperature
在不支持的区域,分钟级预报会返回 nil。强制解包会导致崩溃。
// 错误:强制解包分钟级预报
let minutes = try await weatherService.weather(for: location, including: .minute)
for m in minutes! { ... } // 在不支持的区域会崩溃
// 正确:处理 nil 值
if let minutes = try await weatherService.weather(for: location, including: .minute) {
for m in minutes { ... }
} else {
// 该区域不提供分钟级预报
}
如果没有启用该能力,WeatherService 调用会在运行时抛出错误。
// 错误:未配置 WeatherKit 能力
let weather = try await weatherService.weather(for: location) // 抛出错误
// 正确:在 Xcode 的 Signing & Capabilities 中启用 WeatherKit
// 并在 Apple Developer 门户中为你的 App ID 启用
天气数据每隔几分钟更新一次,而不是每秒更新。缓存响应以保持在 API 配额内并提高性能。
// 错误:每次视图出现时都获取
.task {
let weather = try? await fetchWeather()
}
// 正确:使用过期时间间隔进行缓存
actor WeatherCache {
private var cached: CurrentWeather?
private var lastFetch: Date?
func current(for location: CLLocation) async throws -> CurrentWeather {
if let cached, let lastFetch,
Date.now.timeIntervalSince(lastFetch) < 600 {
return cached
}
let fresh = try await WeatherService.shared.weather(
for: location, including: .current
)
cached = fresh
lastFetch = .now
return fresh
}
}
legalAttributionTextWeatherQuery 数据集(不必要时不使用完整的 weather(for:))WeatherAvailabilityCLLocation 传递给服务之前请求了位置权限Measurement.formatted() 根据地区格式化温度和测量值references/weatherkit-patterns.md每周安装量
329
代码仓库
GitHub 星标数
269
首次出现
2026年3月8日
安全审计
安装于
codex326
opencode323
github-copilot323
amp323
cline323
kimi-cli323
Fetch current conditions, hourly and daily forecasts, weather alerts, and historical statistics using WeatherService. Display required Apple Weather attribution. Targets Swift 6.2 / iOS 26+.
NSLocationWhenInUseUsageDescription to Info.plist if using device locationimport WeatherKit
import CoreLocation
Use the shared singleton or create an instance. The service is Sendable and thread-safe.
let weatherService = WeatherService.shared
// or
let weatherService = WeatherService()
Fetch current conditions for a location. Returns a Weather object with all available datasets.
func fetchCurrentWeather(for location: CLLocation) async throws -> CurrentWeather {
let weather = try await weatherService.weather(for: location)
return weather.currentWeather
}
// Using the result
func displayCurrent(_ current: CurrentWeather) {
let temp = current.temperature // Measurement<UnitTemperature>
let condition = current.condition // WeatherCondition enum
let symbol = current.symbolName // SF Symbol name
let humidity = current.humidity // Double (0-1)
let wind = current.wind // Wind (speed, direction, gust)
let uvIndex = current.uvIndex // UVIndex
print("\(condition): \(temp.formatted())")
}
Returns 25 contiguous hours starting from the current hour by default.
func fetchHourlyForecast(for location: CLLocation) async throws -> Forecast<HourWeather> {
let weather = try await weatherService.weather(for: location)
return weather.hourlyForecast
}
// Iterate hours
for hour in hourlyForecast {
print("\(hour.date): \(hour.temperature.formatted()), \(hour.condition)")
}
Returns 10 contiguous days starting from the current day by default.
func fetchDailyForecast(for location: CLLocation) async throws -> Forecast<DayWeather> {
let weather = try await weatherService.weather(for: location)
return weather.dailyForecast
}
// Iterate days
for day in dailyForecast {
print("\(day.date): \(day.lowTemperature.formatted()) - \(day.highTemperature.formatted())")
print(" Condition: \(day.condition), Precipitation: \(day.precipitationChance)")
}
Request forecasts for specific date ranges using WeatherQuery.
func fetchExtendedForecast(for location: CLLocation) async throws -> Forecast<DayWeather> {
let startDate = Date.now
let endDate = Calendar.current.date(byAdding: .day, value: 10, to: startDate)!
let forecast = try await weatherService.weather(
for: location,
including: .daily(startDate: startDate, endDate: endDate)
)
return forecast
}
Fetch active weather alerts for a location. Alerts include severity, summary, and affected regions.
func fetchAlerts(for location: CLLocation) async throws -> [WeatherAlert]? {
let weather = try await weatherService.weather(for: location)
return weather.weatherAlerts
}
// Process alerts
if let alerts = weatherAlerts {
for alert in alerts {
print("Alert: \(alert.summary)")
print("Severity: \(alert.severity)")
print("Region: \(alert.region)")
if let detailsURL = alert.detailsURL {
// Link to full alert details
}
}
}
Fetch only the datasets you need to minimize API usage and response size. Each WeatherQuery type maps to one dataset.
let current = try await weatherService.weather(
for: location,
including: .current
)
// current is CurrentWeather
let (current, hourly, daily) = try await weatherService.weather(
for: location,
including: .current, .hourly, .daily
)
// current: CurrentWeather, hourly: Forecast<HourWeather>, daily: Forecast<DayWeather>
Available in limited regions. Returns precipitation forecasts at minute granularity for the next hour.
let minuteForecast = try await weatherService.weather(
for: location,
including: .minute
)
// minuteForecast: Forecast<MinuteWeather>? (nil if unavailable)
| Query | Return Type | Description |
|---|---|---|
.current | CurrentWeather | Current observed conditions |
.hourly | Forecast<HourWeather> | 25 hours from current hour |
.daily | Forecast<DayWeather> | 10 days from today |
.minute |
Apple requires apps using WeatherKit to display attribution. This is a legal requirement.
func fetchAttribution() async throws -> WeatherAttribution {
return try await weatherService.attribution
}
import SwiftUI
import WeatherKit
struct WeatherAttributionView: View {
let attribution: WeatherAttribution
@Environment(\.colorScheme) private var colorScheme
var body: some View {
VStack(spacing: 8) {
// Display the Apple Weather mark
AsyncImage(url: markURL) { image in
image
.resizable()
.scaledToFit()
.frame(height: 20)
} placeholder: {
EmptyView()
}
// Link to the legal attribution page
Link("Weather data sources", destination: attribution.legalPageURL)
.font(.caption2)
.foregroundStyle(.secondary)
}
}
private var markURL: URL {
colorScheme == .dark
? attribution.combinedMarkDarkURL
: attribution.combinedMarkLightURL
}
}
| Property | Use |
|---|---|
combinedMarkLightURL | Apple Weather mark for light backgrounds |
combinedMarkDarkURL | Apple Weather mark for dark backgrounds |
squareMarkURL | Square Apple Weather logo |
legalPageURL | URL to the legal attribution web page |
legalAttributionText | Text alternative when a web view is not feasible |
serviceName |
Check which weather datasets are available for a given location. Not all datasets are available in all countries.
func checkAvailability(for location: CLLocation) async throws {
let availability = try await weatherService.weather(
for: location,
including: .availability
)
// Check specific dataset availability
if availability.alertAvailability == .available {
// Safe to fetch alerts
}
if availability.minuteAvailability == .available {
// Minute forecast available for this region
}
}
Omitting attribution violates the WeatherKit terms of service and risks App Review rejection.
// WRONG: Show weather data without attribution
VStack {
Text("72F, Sunny")
}
// CORRECT: Always include attribution
VStack {
Text("72F, Sunny")
WeatherAttributionView(attribution: attribution)
}
Each dataset query counts against your API quota. Fetch only what you display.
// WRONG: Fetches everything
let weather = try await weatherService.weather(for: location)
let temp = weather.currentWeather.temperature
// CORRECT: Fetch only current conditions
let current = try await weatherService.weather(
for: location,
including: .current
)
let temp = current.temperature
Minute forecasts return nil in unsupported regions. Force-unwrapping crashes.
// WRONG: Force-unwrap minute forecast
let minutes = try await weatherService.weather(for: location, including: .minute)
for m in minutes! { ... } // Crash in unsupported regions
// CORRECT: Handle nil
if let minutes = try await weatherService.weather(for: location, including: .minute) {
for m in minutes { ... }
} else {
// Minute forecast not available for this region
}
Without the capability enabled, WeatherService calls throw at runtime.
// WRONG: No WeatherKit capability configured
let weather = try await weatherService.weather(for: location) // Throws
// CORRECT: Enable WeatherKit in Xcode Signing & Capabilities
// and in the Apple Developer portal for your App ID
Weather data updates every few minutes, not every second. Cache responses to stay within API quotas and improve performance.
// WRONG: Fetch on every view appearance
.task {
let weather = try? await fetchWeather()
}
// CORRECT: Cache with a staleness interval
actor WeatherCache {
private var cached: CurrentWeather?
private var lastFetch: Date?
func current(for location: CLLocation) async throws -> CurrentWeather {
if let cached, let lastFetch,
Date.now.timeIntervalSince(lastFetch) < 600 {
return cached
}
let fresh = try await WeatherService.shared.weather(
for: location, including: .current
)
cached = fresh
lastFetch = .now
return fresh
}
}
legalAttributionText displayedWeatherQuery datasets fetched (not full weather(for:) when unnecessary)WeatherAvailability checked before fetching region-limited datasetsCLLocation to serviceMeasurement.formatted() for localereferences/weatherkit-patterns.mdWeekly Installs
329
Repository
GitHub Stars
269
First Seen
Mar 8, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex326
opencode323
github-copilot323
amp323
cline323
kimi-cli323
飞书OpenAPI Explorer:探索和调用未封装的飞书原生API接口
7,500 周安装
Forecast<MinuteWeather>? |
| Next-hour precipitation (limited regions) |
.alerts | [WeatherAlert]? | Active weather alerts |
.availability | WeatherAvailability | Dataset availability for location |
| Weather data provider name |