This package is Swift wrapper around the WeatherKit REST API. Its intention is to bring a native Swift WeatherKit alternative to platforms Apple does not currently support. The API of this package is nearly identical to Apple's WeatherKit.
Minimum Swift version of 5.9
- iOS 13+
- watchOS 6+
- tvOS 13+
- visionOS 1+
- macOS 11+
- Ubuntu 18.04+
The REST API requires a signed JWT to be sent with each request. To set this up you need:
- A paid developer account
- A Service Identifier
- A key
- Go to Identifiers
- On the top left, click the add button (+), select Services IDs, then click Continue.
- Register a Service ID.
- Make note of the Identifier (you'll need it later)
- Click Continue, review the registration information, and click Register.
- Go to Keys
- On the top left, click the add button (+)
- Give your key a name, tick the "WeatherKit" box
- Click Continue, review the registration information, and click Register.
- Make note of the Key ID (you'll need it later)
- Download the private key
The WeatherKit REST API requires a JSON Web Token (JWT) to be sent with every request. Implementing the logic necessary to generate a JWT is beyond the scope of the OpenWeatherKit project at this time. For general information on JWT please visit https://jwt.io
That being said, the recommended package to handle this task is Vapor's jwt-kit. Here is how to set that up:
Implement model conforming to JWTPayload
import JWTKit
struct Payload: JWTPayload, Equatable {
enum CodingKeys: String, CodingKey {
case expiration = "exp"
case issued = "iat"
case issuer = "iss"
case subject = "sub"
}
let expiration: ExpirationClaim
let issued: IssuedAtClaim
let issuer: IssuerClaim
let subject: SubjectClaim
func verify(using key: some JWTAlgorithm) throws {}
}Generate the JWT
struct JWTProvider {
static func generate() async throws -> String {
let keys = JWTKeyCollection()
try await keys.add(ecdsa: ES256PrivateKey(pem: PRIVATE_KEY_FROM_DEV_PORTAL))
let payload = Payload(
expiration: .init(value: .distantFuture),
issued: .init(value: .now),
issuer: TEAM_ID,
subject: SERVICE_IDENTIFIER
)
return try await keys.sign(payload, kid: KEY_ID)
}
}Note the variables:
PRIVATE_KEY_FROM_DEV_PORTAL: The contents of the private key file including
-----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----
TEAM_ID: Found in Membership Details on the developer portal
SERVICE_IDENTIFIER: The reverse-domain name noted earlier
KEY_ID: The ID of the service key
The service must be initialized with a JWT generating closure and optionally a language.
let weatherService = WeatherService(
configuration: .init(jwt: { try await JWTProvider.generate() })
)let weather = try await weatherService
.weather(
for: Location(
latitude: 37.541290,
longitude: -77.511429),
countryCode: "US"
)let (dailyForecast, hourlyForecast, alerts) = try await weatherService
.weather(
for: Location(
latitude: 37.541290,
longitude: -77.511429),
including: .daily, .hourly, .alerts(countryCode: "US")
)Note that minute forecasts and alerts are not always available in all regions. Use the .availability query check their availability.
let availability = try await weatherService
.weather(
for: Location(
latitude: 37.541290,
longitude: -77.511429),
including: .availability
)Historical weather statistics are derived from weather data recorded over the past decades. Statistics are available at daily, hourly, and monthly intervals.
Daily Statistics (30 days ago to 10 days from now by default):
let (dailyPrecipitation, dailyTemperature) = try await weatherService
.dailyStatistics(
for: Location(latitude: 37.541290, longitude: -77.511429),
including: .precipitation, .temperature
)Daily Statistics (specific day range, 1-366):
let (dailyPrecipitation, dailyTemperature) = try await weatherService
.dailyStatistics(
for: Location(latitude: 37.541290, longitude: -77.511429),
startDay: 1,
endDay: 10,
including: .precipitation, .temperature
)Hourly Statistics (24 hours of current day by default):
let hourlyTemperature = try await weatherService
.hourlyStatistics(
for: Location(latitude: 37.541290, longitude: -77.511429),
including: .temperature
)Hourly Statistics (specific hour range, 1-8784):
let hourlyTemperature = try await weatherService
.hourlyStatistics(
for: Location(latitude: 37.541290, longitude: -77.511429),
startHour: 1,
endHour: 24,
including: .temperature
)Monthly Statistics (all 12 months by default):
let (monthlyPrecipitation, monthlyTemperature) = try await weatherService
.monthlyStatistics(
for: Location(latitude: 37.541290, longitude: -77.511429),
including: .precipitation, .temperature
)Monthly Statistics (specific month range, 1-12):
let (monthlyPrecipitation, monthlyTemperature) = try await weatherService
.monthlyStatistics(
for: Location(latitude: 37.541290, longitude: -77.511429),
startMonth: 1,
endMonth: 6,
including: .precipitation, .temperature
)Weather summaries provide aggregated actual weather data (not statistics) for past dates.
Daily Summary (past 30 days by default):
let (dailyPrecipitation, dailyTemperature) = try await weatherService
.dailySummary(
for: Location(latitude: 37.541290, longitude: -77.511429),
including: .precipitation, .temperature
)Daily Summary (specific day range, 1-366):
let (dailyPrecipitation, dailyTemperature) = try await weatherService
.dailySummary(
for: Location(latitude: 37.541290, longitude: -77.511429),
startDay: 1,
endDay: 10,
including: .precipitation, .temperature
)Daily Summary (specific date interval):
let interval = DateInterval(start: startDate, end: endDate)
let (dailyPrecipitation, dailyTemperature) = try await weatherService
.dailySummary(
for: Location(latitude: 37.541290, longitude: -77.511429),
forDaysIn: interval,
including: .precipitation, .temperature
)When the library is used on an Apple platform, the countryCode and timezone parameters are not required. Internally, the library will use CoreLocation to reverse geocode the location to determine the country code. If the country cannot be determined, an error will be thrown.
Please be advised of Apple's attribution guidelines when using this package.
Attribution information can be accessed with:
let attribution = weatherService.attributionNote that this property returns a static WeatherAttribution instance using information from WeatherKit and is not guaranteed to be accurate or complete.