weatherkit

weatherkit

热门

获取 WeatherKit 的当前天气、分钟级、小时级和每日预报;天气警报;iOS 18+ 的变化、历史对比、摘要和统计信息;以及必需的 Apple Weather 署名。在集成天气数据、显示预报或警报、缓存 WeatherKit 响应、显示署名或审查 iOS 应用中的 WeatherKit 查询限制时使用。

940Star
47Fork
更新于 2026/7/15
SKILL.md
只读
名称
weatherkit
描述

获取 WeatherKit 的当前天气、分钟级、小时级和每日预报;天气警报;iOS 18+ 的变化、历史对比、摘要和统计信息;以及必需的 Apple Weather 署名。在集成天气数据、显示预报或警报、缓存 WeatherKit 响应、显示署名或审查 iOS 应用中的 WeatherKit 查询限制时使用。

WeatherKit

使用 WeatherService 获取当前天气状况、小时级和每日预报、天气警报以及历史统计数据。显示必需的 Apple Weather 署名。

目录

设置

项目配置

  1. 在 Xcode 中启用 WeatherKit 能力(添加授权)
  2. 在 Apple Developer 门户中为你的 App ID 启用 WeatherKit
  3. 如果使用设备位置,在 Info.plist 中添加 NSLocationWhenInUseUsageDescription
  4. WeatherKit 需要有效的 Apple Developer Program 会员资格

导入

import WeatherKit
import CoreLocation

创建服务

使用共享单例或创建实例。WeatherService 符合 Sendable;将应用缓存和 UI 状态单独隔离。

let weatherService = WeatherService.shared
// 或
let weatherService = WeatherService()

获取当前天气

获取某个位置的当前天气状况。返回一个包含所有可用数据集的 Weather 对象。

WeatherKit 温度是 Measurement<UnitTemperature> 值;使用 .formatted() 显示它们,以便单位和数字格式遵循用户的语言环境。

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 请求特定日期范围的预报。

每日和小时级日期范围查询使用包含的 startDate 和不包含的 endDate。它们可以包含自 2021 年 8 月 1 日以来的历史数据。预报最多可提供未来 10 天;每次请求最多返回 10 天的每日预报或约 240 小时的小时级预报。

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 fetchTomorrowForecast(for location: CLLocation) async throws -> Forecast<DayWeather> {
    let calendar = Calendar.current
    let tomorrow = calendar.startOfDay(
        for: calendar.date(byAdding: .day, value: 1, to: .now)!
    )
    let dayAfterTomorrow = calendar.date(byAdding: .day, value: 1, to: tomorrow)!

    return try await weatherService.weather(
        for: location,
        including: .daily(startDate: tomorrow, endDate: dayAfterTomorrow)
    )
}

天气警报

获取某个位置的活跃天气警报。警报包括严重程度、摘要和受影响区域。

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 ?? "未知区域")")
        print("详情: \(alert.detailsURL)") // 非可选,署名必需
    }
}

对于警报仪表板,在讨论支持检查时明确命名 WeatherAvailability:它只暴露 alertAvailabilityminuteAvailability,而不是当前、小时级或每日天气的广泛可用性矩阵。

选择性查询

只获取所需的数据集,以最小化 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 仅警报和分钟级预报可用性
.changes WeatherChanges? 即将到来的显著天气变化 (iOS 18+)
.historicalComparisons HistoricalComparisons? 当前天气与历史平均值对比 (iOS 18+)

上下文查询

对于 iOS 18+ 上的“明天异常”或“正在变化”功能,一起请求可选的 .changes.historicalComparisons 结果:前者报告即将到来的显著变化,后者提供历史背景。

let (changes, comparisons) = try await weatherService.weather(
    for: location,
    including: .changes, .historicalComparisons
)

历史摘要和统计信息使用 WeatherService 方法,而不是 WeatherQuery。加载 references/weatherkit-patterns.md 以了解它们的元组顺序、API 和统计特定属性。

署名

Apple 要求使用 WeatherKit 的应用显示署名。这是法律要求。

获取署名

func fetchAttribution() async throws -> WeatherAttribution {
    return try await weatherService.attribution
}

加载 references/weatherkit-patterns.md 以获取完整的 SwiftUI 署名视图和缓存集成。

署名属性

属性 用途
combinedMarkLightURL 浅色背景的 Apple Weather 标志
combinedMarkDarkURL 深色背景的 Apple Weather 标志
squareMarkURL 方形 Apple Weather 标志
legalPageURL 法律署名网页的 URL
legalAttributionText 当无法显示网页视图时的文本替代
serviceName 天气数据提供商名称

可用性

检查某个位置的天气警报或分钟级预报数据是否可用。WeatherAvailability 仅报告警报和分钟级可用性;其他数据集(如当前天气)预计在地理位置上都受支持。

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 {
        // 该区域分钟级预报可用
    }
}

常见错误

不要:发布时没有 Apple Weather 署名

在显示 WeatherKit 数据的任何地方显示适当的 Apple Weather 标志并链接 legalPageURL;仅在无法显示法律页面时使用 legalAttributionText

不要:只需要当前天气状况时获取所有数据集

每个数据集查询都会计入你的 API 配额。使用选择性查询中显示的选择性查询,只获取 UI 显示所需的数据。

不要:忽略分钟级预报的不可用性

分钟级预报在不支持的区域是可选的。检查可用性并处理 nil 结果,而不是强制解包。

不要:忘记 WeatherKit 授权

如果没有启用该能力,WeatherService 调用会在运行时抛出错误。

// 错误:未配置 WeatherKit 能力
let weather = try await weatherService.weather(for: location) // 抛出错误

// 正确:在 Xcode 的 Signing & Capabilities 中启用 WeatherKit
// 并在 Apple Developer 门户中为你的 App ID 启用

不要:不缓存就重复请求

WeatherKit 模型包含 metadata.expirationDate。将响应缓存到该过期时间,而不是自行设定固定间隔或在每次视图出现时获取。让模型或缓存拥有 loadIfNeeded;完整的 actor 模式在 references/weatherkit-patterns.md 中。

审查清单

  • [ ] 在 Xcode 和 Apple Developer 门户中启用了 WeatherKit 能力
  • [ ] 有效的 Apple Developer Program 会员资格(WeatherKit 必需)
  • [ ] 在显示天气数据的任何地方显示了 Apple Weather 署名
  • [ ] 署名标志使用了正确的配色方案变体(浅色/深色)
  • [ ] 链接了法律署名页面或显示了 legalAttributionText
  • [ ] 只获取了所需的 WeatherQuery 数据集(不需要时不要使用完整的 weather(for:)
  • [ ] 分钟级预报作为可选处理(在不支持的区域为 nil)
  • [ ] 在遍历前检查天气警报是否为 nil
  • [ ] 警报详情链接使用非可选的 detailsURL;可选的 region 是 nil 安全的
  • [ ] 响应缓存到每个模型的 metadata.expirationDate
  • [ ] WeatherAvailability 用于警报/分钟级可用性,而不是作为广泛的支持矩阵
  • [ ] 在将 CLLocation 传递给服务之前请求了位置权限
  • [ ] 温度和测量值使用 Measurement.formatted() 进行格式化以适配语言环境

参考资料