我正在参与「启航计划」
在 WWDC 2022,Apple 推出了全新的气候数据服务 WeatherKit ,供给了丰富的气候数据供开发者运用。
只要你现已购买了Apple的开发者账号,就可以运用它。
和大多数气候服务相同,WeatherKit 也是按央求次数收费的,价格如下:
- 50 万次调用/月:会员资格已包含
- 100 万次调用/月:49.99 美元
- 200 万次调用/月:99.99 美元
- 500 万次调用/月:249.99 美元
- 1,000 万次调用/月:499.99 美元
- 2,000 万次调用/月:999.99 美元
概况见 Apple官网:初步运用 WeatherKit – Apple Developer
可以看到,开发者默许每月有 50万次调用的额度可以运用,不用额定付费,只有超越这个数量才需求其他付费。
苹果供给了两种方法调用 WeatherKit:
-
系统原生库 WeatherKit(仅支撑Apple途径,
iOS 16.0+
,iPadOS 16.0+
,macOS 13.0+
,Mac Catalyst 16.0+
,tvOS 16.0+
,watchOS 9.0+
) - Weather KIT REST API(全途径支撑)
根据苹果一贯的习气,WeatherKit系统库从 iOS 16 初步支撑,并不支撑老版其他系统。而且只支撑 Swift,不支撑OC。
所以,在现阶段,关于要支撑老版别系统的APP并没有实用价值。
但是 REST API 就不相同了,由于它是网络央求接口,它可以支撑全部版其他系统,甚至非苹果生态的 web 和 Windows等途径也可以运用。
所以,我们今日来看看,怎么初步运用WeatherKit REST API。
一、初步之前
1、创建APP ID 并添加WeatherKit 权限
初步之前需求一些准备工作,翻开苹果的开发者网站。在 Certificates, Identifiers, and Profiles 页面选择 Identifiers,创建一个新 App ID ,假如你不需求创建新的,你也可以选择已有的 APP ID。然后翻开后在 App Services 一栏勾选 WeatherKit 选项。或许需求等候30分钟让苹果同步权限之后才可以进行API央求。
这儿需求记载一下 AppID Prefix 和 Bundle ID 以及你账户的 Team ID。等一下会用到。
2、创建WeatherKit 的密钥
在 Certificates, Identifiers, and Profiles 页面选择 Keys 选项,然后新建一个Key。勾选WeatherKit 选项。
系统会提示你下载一个密钥文件,这是你调用WeatherKit服务的签名用的私钥,只能下载一次,一定要妥善保管到安全的位置,不能走漏。
然后记载一下 生成的Key的 ID。稍后会用到。
二、初步Weather Kit REST API之旅
Weather Kit REST API 运用标准的 JWT( JSON Web Token )进行授权,首要我们要生成授权的 JWT,一般这一步应该在后端服务器上完成。JWT 标准文档:JWT specification
简单来说,JWT 是一个字符串,由三段base64编码的字符串组成,用英文的句号“.”分隔。
例如: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
榜首段和第二段都是JSON经过urlBase64编码后的字符串,这儿运用的base64和一般的有一点差异,是专门为url传递优化过的,详细改变如下:
1、去掉了结束的等号“=”
2、将加号“+”替换成短线“-”
3、将斜杠“/”替换成下划线“_”
榜首段称为头部(Header),记载了一些JWT的格式和签名方法等,详细可以参看 JWT标准文档。
第二段称为负载(Payload),是JWT的主体部分,记载了JWT的要害信息。
第三段是前两段的数字签名,是为了避免JWT被假造和篡改。
WeatherKit 对前两段的内容和签名方法都有要求。
1、Header部分
{
"alg": "ES256",
"kid": "ABC123DEFG",
"id": "DEF123GHIJ.com.example.weatherkit-client"
}
其间:
alg :是签名方法,Apple要求,有必要为“ES256”,它标明我们应该运用 SHA256算法对内容进行哈希后运用P-256曲线的椭圆曲线数字签名算法(ECDSA)对其进行签名。
详细签名方法后门再阐明。
kid :是刚才榜首步中我们创建的Key的ID。
id :是Team ID和bundle ID 的拼接。
Header的json结构完成后运用 urlBase64对其进行编码,得到了JWT的榜首部分:
eyJhbGciOiJFUzI1NiIsImtpZCI6IkFCQzEyM0RFRkciLCJpZCI6IkRFRjEyM0dISUouY29tLmV4YW1wbGUud2VhdGhlcmtpdC1jbGllbnQifQ
2、Payload部分
{
"iss": "DEF123GHIJ",
"iat": 1437179036,
"exp": 1493298100,
"sub": "com.example.weatherkit-client"
}
iss:JWT签发者,值为你的Team ID。
iat:JWT签发时间,Unix时间戳,单位秒,整数。
exp:JWT过期时间,Unix时间戳,单位秒,整数。
sub:你app的 bundle ID
Payload的json结构完成后相同运用 urlBase64对其进行编码,得到了JWT的第二部分:
eyJpc3MiOiJERUYxMjNHSElKIiwiaWF0IjoxNDM3MTc5MDM2LCJleHAiOjE0OTMyOTgxMDAsInN1YiI6ImNvbS5leGFtcGxlLndlYXRoZXJraXQtY2xpZW50In0
3、签名
下一步,将header和payload的base64字符串用“.”拼接在一起,然后对拼接后的字符串进行 ECDSA 签名。
拼接后的字符串为:eyJhbGciOiJFUzI1NiIsImtpZCI6IkFCQzEyM0RFRkciLCJpZCI6IkRFRjEyM0dISUouY29tLmV4YW1wbGUud2VhdGhlcmtpdC1jbGllbnQifQ.eyJpc3MiOiJERUYxMjNHSElKIiwiaWF0IjoxNDM3MTc5MDM2LCJleHAiOjE0OTMyOTgxMDAsInN1YiI6ImNvbS5leGFtcGxlLndlYXRoZXJraXQtY2xpZW50In0
JWT的签发应该放在后端进行,所以这儿以 go 语言为示例:
package main
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"os"
)
func main() {
sign := EccSignature("eyJhbGciOiJFUzI1NiIsImtpZCI6IkFCQzEyM0RFRkciLCJpZCI6IkRFRjEyM0dISUouY29tLmV4YW1wbGUud2VhdGhlcmtpdC1jbGllbnQifQ.eyJpc3MiOiJERUYxMjNHSElKIiwiaWF0IjoxNDM3MTc5MDM2LCJleHAiOjE0OTMyOTgxMDAsInN1YiI6ImNvbS5leGFtcGxlLndlYXRoZXJraXQtY2xpZW50In0",
"./test.p8")
fmt.Printf("sign: %s", sign)
}
// textToSign 等候签名的字符串,privateKeyPath 私钥文件的途径
// return: 签名
func EccSignature(textToSign string, privateKeyPath string) (sign string) {
//------1.获取私匙------
//Step1:翻开文件获取原始私匙
file, err := os.Open(privateKeyPath)
if err != nil {
panic(err)
}
defer file.Close()
fileinfo, err := file.Stat()
if err != nil {
panic(err)
}
buf := make([]byte, fileinfo.Size())
file.Read(buf)
//Step2:私匙的反pem编码化
block, _ := pem.Decode(buf)
//Step3:私匙的反x509序列化, 关于不同格式的私钥文件可以能需求运用不同的 Parse方法,关于WeatherKit供给的.p8文件,这儿运用ParsePKCS8PrivateKey
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
panic(err)
}
// 转化类型
privKey := key.(*ecdsa.PrivateKey)
//------求取明文的散列值------
//Step1:创建根据sha256哈希函数的hash接口
myHash := sha256.New()
//Step2:写入数据
myHash.Write([]byte(textToSign))
//Step:求出明文的散列值
hashText := myHash.Sum(nil)
//------对明文的散列值进行数字签名
r, s, err := ecdsa.Sign(rand.Reader, privKey, hashText)
if err != nil {
panic(err)
}
//Step2:得到 r和s 的字节编码
rText := r.Bytes()
if err != nil {
panic(err)
}
sText := s.Bytes()
if err != nil {
panic(err)
}
// 运用 r||s 格式输出
signBytes := append(rText, sText...)
// 编码成 base64
sign = base64.RawURLEncoding.EncodeToString(signBytes)
return sign
}
例如得到签名字符串:f2SAjBpBGyidryrlGyVaso2yLPRufYULjdhI0zcqxB07iN9OI9rvQaHo1xxoTfTD9A6DVpb96sE8leGyTo0dYg
将签名后得到的base64字符串相同运用“.”拼接在刚才的字符串后门,就完成了JWT的签发。
得到毕竟的JWT:
eyJhbGciOiJFUzI1NiIsImtpZCI6IkFCQzEyM0RFRkciLCJpZCI6IkRFRjEyM0dISUouY29tLmV4YW1wbGUud2VhdGhlcmtpdC1jbGllbnQifQ.eyJpc3MiOiJERUYxMjNHSElKIiwiaWF0IjoxNDM3MTc5MDM2LCJleHAiOjE0OTMyOTgxMDAsInN1YiI6ImNvbS5leGFtcGxlLndlYXRoZXJraXQtY2xpZW50In0.f2SAjBpBGyidryrlGyVaso2yLPRufYULjdhI0zcqxB07iN9OI9rvQaHo1xxoTfTD9A6DVpb96sE8leGyTo0dYg
毕竟得到的JWT格式应该是header
.payload
.sign
这样的三段结构,你可在 JWT.io 中选择ES256然后运用他的证书进行签名后对自己的签名方法进行验证(注意:为了安全起见,请不要将自己的私钥随便复制到网页中)。
将它回来给APP或许前端等需求央求WeatherKit REST API 的地方。
4、主张央求
总算,经过前面的准备,我们现已具有了央求Weather Kit REST API的全部前提条件。
主张央求很简单,就是正常的GET央求,仅仅需求在HTTP HEADER中参加一个字段:
Authorization: Bearer [developer token]
将 [developer token] 替换为你签发的 JWT。
然后根据Weather Kit REST API 文档所描绘的途径和参数主张央求,就能正常得到气候数据了。
这儿以Postman为例
在 Authorization一栏选择 Bearer Token 将JWT填入右边的Token输入框就可以主动添加到Header中。
你也可以自己手动在 Header参数中添加 Authorization 字段。
主张央求:
三、最终
个人 感觉WeatherKit REST API仍是很不错的,不需求额定付费就能有50万次每月的访问量,关于小体量的个人开发者完全够用了。
还有一点值得注意的是,依照苹果的要求,假如你运用了WeatherKit,你应该在APP中标明数据来历:
参看:
-
官方接口文档:Weather Kit REST API
-
WWDC 2022 WeatherKit 视频: Meet WeatherKit – WWDC22 – Videos – Apple Developer
-
官方中文简介:初步运用 WeatherKit – Apple Developer
-
JWT 官方标准: JWT specification
-
JWT 验证东西:JWT.io