服务器端Swift:制作机盖(5/6)
上次我谈到了部署和维护Linux服务器。 这次我们正在谈论如何与APNs通信门户进行通信。
什么是天篷?
Canopy具有适用于macOS和iOS的应用程序,可在此处使用。
APN
苹果推送通知服务。 为什么“ s”是小写的? 没人知道。
该服务是Internet上的黑匣子。 您的服务器安全地连接到该服务器,并发送小型JSON负载,每个负载均用于特定设备。 苹果然后将其发送到设备。 如果设备没有通电,它们将“保持”一会儿,如果有电,它将立即到达。
该连接是一个持久的HTTP2连接,HTTP2仍然是一个很新的东西,并且没有多少Internet使用它。 URLSession严格支持它,但它不会保持连接打开。 尽管有些人确实将URLSession用于APN,但您应注意:Apple承诺他们(连续打开和关闭许多连接)将其视为文字攻击,并会禁止您这样做。
实施APN
首先,请转到Apple供应门户,并获取一个APNs密钥。 它作为文件提供,将其传输到您的服务器。 确保它不以某种方式暴露在网络上,如果有人收到了,他们可以将用户通知作为您的应用发送给您,这可能会让您感到尴尬。
其次,您需要向服务器发送Apple为其客户端应用程序用户提供的设备令牌。 您之前已经看过此代码,现在您可以更好地了解其用途。
但是,除非计划将相同的通知发送给每个人,否则还需要某种方式将该令牌与您在服务器上使用的用户ID系统相关联。 因此也发送此信息。 不要忘记,您可以在两端使用相同的Codable
结构! (请参阅第1部分)
完美的通知
Perfect提供了Perfect-Notifications,因此首先我使用了它。 易于设置和使用:
导入PerfectNotifications
让configurationName =“ configurationName”
让apnsKeyIdentifier =“ AB90CD56XY” //来自供应门户
让apnsTeamIdentifier =“ YX65DC09BA” //来自供应门户
让apnsPrivateKeyFilePath =“ ./APNsAuthKey_AB90CD56XY.p8”
NotificationPusher.addConfigurationAPNS(
名称:configurationName,
production:false,//上线时设置为“ true”!
keyId:apnsKeyIdentifier,
teamId:apnsTeamIdentifier,
privateKeyPath:apnsPrivateKeyFilePath)
然后,您可以发送通知:
NotificationPusher(apnsTopic:“ your.bundle.id”)。pushAPNS(
configurationName:配置名称,
deviceTokens:[deviceToken],
notificationItems:[.alertBody(“ Hello!”),.sound(“ default”)]){
在回应
打印(“ \(响应)”)
}
如果这是一项测试,请通过打印声明从电话应用程序中获取令牌并对其进行硬编码。 经过测试之后,您将需要开始存储和从数据库中获取令牌。 您将需要向服务器添加路由(请参阅第2部分),并将令牌发送到该端点,然后将该端点的该令牌存储在数据库中(请参阅第4部分)。
烦恼
几周后,我注意到,如果GitHub上连续发生许多事件,那么Perfect通知引擎将连续不断地发送推送通知,而我将不得不终止服务器。
我报告了该错误,Perfect维护人员提交修复程序的速度非常快,很遗憾,它不是完整的修复程序,我仍然可以体验到。 之后,维护人员停止与我交谈。 我本人想自己解决这个问题,但找出原因不在我自己之外,所以我开始研究其他选择。
蒸气具有APNs层,但使用它意味着将大部分蒸气拉入。 至此,我知道了与APN的通信如何很好地工作,并且我意识到我可以自己编写,因为我只需要实现全部需求的一部分。 例如,APN支持在同一个HTTP2连接中包含多个“管道”,此数目是有限的,您必须支持知道一次使用多少个管道。 Canopy尚不需要此通知,并且可能一段时间不会,相反,我一次只能发送一个通知,但是我的测试表明,我仍然可以这种方式每秒发送近600条通知。 (Apple声称,如果您的代码有效运行,您每秒可以发送5,000多个)。 同样,先进的APNs引擎将根据需要与Apple建立新的连接,我只需要一个。
重新发明轮子
RtW还不错。 自己动手时学到的东西最多。
首先,我需要一个HTTP2库。 完美自己做。 蒸气使用libcurl。 尽管我需要的libcurl是比Ubuntu 16.04随附的更新的版本,所以我必须自己configure
, make install
,并将其make install
到/usr/local
。
Perfect已经将libcurl用于其他用途,因此导入此新版本实际上是自动的(也是因为Linux没有rpath
所以它将首先使用库路径中的任何一个库,并使用/usr/local
)。
这是我们准备连接的方法:
让curlHandle:UnsafeMutableRawPointer
var url:字符串
如果生产{
url =“ https://api.push.apple.com/3/device/”
}其他{
url =“ https://api.sandbox.push.apple.com/3/device/”
}
curlHandle = curl_easy_init()
url.withCString {
var str = UnsafeMutablePointer(变异:$ 0)
curlHelperSetOptString(curlHandle,CURLOPT_URL,str)
}
curlHelperSetOptInt(curlHandle,CURLOPT_HTTP_VERSION,
CURL_HTTP_VERSION_2_0)
curlHelperSetOptInt(curlHandle,CURLOPT_PORT,443)
curlHelperSetOptBool(curlHandle,CURLOPT_FOLLOWLOCATION,CURL_TRUE)
curlHelperSetOptBool(curlHandle,CURLOPT_POST,CURL_TRUE)
curlHelperSetOptBool(curlHandle,CURLOPT_HEADER,CURL_TRUE)
然后发送一些东西:
var json:[String:Any] = // ...
json.append(0)
json.withUnsafeMutableBytes {
_ = curlHelperSetOptString(curlHandle,CURLOPT_POSTFIELDS,$ 0)
}
curlHelperSetOptInt(curlHandle,CURLOPT_POSTFIELDSIZE,json.count-1)
//标头
var curlHeaders:UnsafeMutablePointer ?
curlHeaders = curl_slist_append(curlHeaders,“授权:不记名\(jwt)”)
curlHeaders = curl_slist_append(curlHeaders,“ User-Agent:Canopy,Codebase LLC”)
curlHeaders = curl_slist_append(curlHeaders,“ apns-topic:\(topic)”)
curlHeaders = curl_slist_append(curlHeaders,“ Accept:application / json”)
curlHeaders = curl_slist_append(curlHeaders,“ Content-Type:application / json; charset = utf-8”)
curlHelperSetOptHeaders(curlHandle,curlHeaders)
推迟{
curlHeaders.map(curl_slist_free_all)
}
//发送
curl_easy_perform(curlHandle)
kes。 不仅如此。 topic
是您的应用程序的捆绑软件ID,对于Canopy而言,捆绑软件ID有所不同(macOS和iOS),但如果有,您可能可以对其进行硬编码。 json
很奇怪,但已记录在案。 jwt
是唯一的密钥,您必须每小时生成一次。 这是我的代码:
现在让我们= Date()
让有效负载:[字符串:任何] = [“ iss”:teamId,“ iat”:Int(now.timeIntervalSince1970)]
让jwt = JWTCreator(payload:有效负载)!
让pem =试试! PEMKey(pemPath:“ ./AuthKey_5354D789X6.p8”)
返回尝试! jwt.sign(alg:JWT.Alg.es256,键:pem,标头:[“ kid”:“ 5354D789X6”])
Perfect提供JWTCreator
和PEMKey
对象。 刘海是安全的,因为这里任何nil
都将是开发错误。
现在,请确保您不要太频繁地创建新的jwts,Apple将关闭您的连接。 同时保持相同的curl_handle
,不要关闭它或重新打开它。 您想要一个持久的连接。 如果Apple关闭它,libcurl将自动为您重新打开它,这非常方便。
您还必须做更多的事情,您需要收听Apple的响应,如果它们发送某些HTTP响应代码,则需要从数据库中删除这些令牌。 互联网认为,如果您忽略这些消息,Apple将开始限制您的连接,甚至更糟。
完成所有这些操作后,我的APNs系统已经运行了数周。 我很惊讶,但实际上我有libcurl的人要为此付出一切,他们付出了辛勤的工作。
不要自己写
如果需要APN,请选择“蒸气”。
嘿!
我是Max Howell,我想专职从事开放源码的写作,写作和全部工作。 我从事开源工作已有15年了,您可能已经使用过其中的一部分(有人自制吗?)。 我需要您的帮助才能继续,任何贡献都值得欢迎。 非常感谢。
https://patreon.com/mxcl
第6部分即将推出!
下周:最终想法,结论和后见之明。