mcpField
W
weatherkit

weatherkit

github.com/dpearson2699开发1.2k3.5k 次安装13 周前更新
代码仓库

关于 weatherkit

weatherkit 是面向 Swift 开发者的 WeatherKit 使用指南,可通过 WeatherService 获取天气数据并展示必需的 Apple 署名。内容涵盖选择性查询、数据可用性与响应缓存。

主要功能

  1. 01获取当前天气与预报
  2. 02读取警报和历史比较
  3. 03用 WeatherQuery 选择数据集
  4. 04检查分钟预报和警报可用性
  5. 05处理署名与响应缓存

适用场景

  1. 01在应用中显示当前天气
  2. 02构建逐小时或逐日预报视图
  3. 03显示地点天气警报
  4. 04将天气与历史平均值比较

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dpearson2699/swift-ios-skills --skill weatherkit

安装后在 Claude Code 中输入/weatherkit确认已加载。

附带文件evals/evals.jsonreferences/weatherkit-patterns.md

详细介绍

WeatherKit

使用 WeatherService 获取当前天气状况、逐小时和逐日预报、天气警报以及历史统计数据。请显示 Apple Weather 要求的署名信息。

目录

设置

项目配置
  1. 在 Xcode 中启用 WeatherKit 功能(会添加相应授权)
  2. 在 Apple Developer 门户中为你的 App ID 启用 WeatherKit
  3. 如果使用设备位置,请将 NSLocationWhenInUseUsageDescription 添加到 Info.plist
  4. 使用 WeatherKit 需要有效的 Apple Developer Program 会员资格
导入
import WeatherKit
import CoreLocation
创建服务

使用共享的单例或创建一个实例。WeatherService 遵循 Sendable;请单独隔离应用缓存和界面状态。

let weatherService = WeatherService.shared
// or
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
}

// 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())")
}

天气预报

逐小时预报

默认返回从当前小时开始的连续 25 小时数据。

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)")
}
逐日预报

默认返回从当天开始的连续 10 天数据。

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)")
}
自定义日期范围

使用 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
}

// Process alerts
if let alerts = weatherAlerts {
    for alert in alerts {
        print("Alert: \(alert.summary)")
        print("Severity: \(alert.severity)")
        print("Region: \(alert.region ?? "Unknown region")")
        print("Details: \(alert.detailsURL)") // Non-optional and required for attribution
    }
}

对于警报仪表板,在讨论支持情况检查时,请明确指出 WeatherAvailability:它仅提供 alertAvailability 和 minuteAvailability,而不提供当前、逐小时或逐日天气的综合可用性矩阵。

选择性查询

仅获取所需数据集,以尽量减少 API 用量和响应大小。每种 WeatherQuery 类型都对应一个数据集。

单个数据集
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>
分钟级预报

仅在有限地区提供。返回未来一小时内按分钟粒度划分的降水预报。

let minuteForecast = try await weatherService.weather(
    for: location,
    including: .minute
)
// minuteForecast: Forecast<MinuteWeather>?  (nil if unavailable)
可用的查询类型
查询返回类型说明
.currentCurrentWeather当前观测到的天气状况
.hourlyForecast<HourWeather>从当前小时开始的 25 小时数据
.dailyForecast<DayWeather>从今天开始的 10 天数据
.minuteForecast<MinuteWeather>?未来一小时的降水预报(仅限部分地区)
.alerts[WeatherAlert]?有效天气警报
.availabilityWeatherAvailability仅提供警报和分钟级预报的可用性
.changesWeatherChanges?即将出现的重大天气变化(iOS 18+)
.historicalComparisonsHistoricalComparisons?当前天气与历史平均值的对比(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
    )

    // Check specific dataset availability
    if availability.alertAvailability == .available {
        // Safe to fetch alerts
    }

    if availability.minuteAvailability == .available {
        // Minute forecast available for this region
    }
}

常见错误

不要:未显示 Apple Weather 署名就发布

凡是显示 WeatherKit 数据的地方,都应显示适当的 Apple Weather 标志并链接到 legalPageURL;只有在无法显示法律页面时,才使用 legalAttributionText。

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

每次数据集查询都会占用 API 配额。请使用选择性查询中所示的查询,仅获取 UI 会显示的数据。

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

在不支持的地区,分钟级预报可能不可用。请检查其可用性,并处理 nil 结果,而不要对其强制解包。

不要:忘记 WeatherKit 权限

如果未启用相应功能,WeatherService 调用会在运行时抛出错误。

// 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
不要:重复请求却不进行缓存

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() 按区域设置格式化温度和测量值

参考资料

评论

支持 Markdown