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.
- iOS 13+
- watchOS 6+
- tvOS 13+
- 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 signer: JWTKit.JWTSigner) throws {}
}
Generate the JWT
struct JWTProvider {
static func generate() -> String {
let signers = JWTSigners()
try signers.use(.es256(key: ECDSAKey.private(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! signers.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 configured with a JWT generating closure and optionally a language.
If you choose to use the WeatherService.shared
instance, call the following before referencing shared
:
WeatherService.configure {
$0.jwt = JWTProvider.generate
}
let weather = try await WeatherService.shared
.weather(
for: Location(
latitude: 37.541290,
longitude: -77.511429),
countryCode: "US"
)
let (dailyForecast, hourlyForecast, alerts) = try await WeatherService.shared
.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 availabilty = try await WeatherService.shared
.weather(
for: Location(
latitude: 37.541290,
longitude: -77.511429),
including: .availability
)
When the library is used on an Apple platform, the countryCode
parameter is not required. Internally the libary 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.shared.attribution
Note that this property returns a static WeatherAttribution
instance using information from WeatherKit
and is not guaranteed to be accurate or complete.