【转】APNs消息推送完整讲解
在项目的AppDelegate中的didFinishLaunchingWithOptions方法中加入下面的代码:
- [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];
通过registerForRemoteNotificationTypes方法,告诉应用程序,能接受push来的通知。
在项目的AppDelegate中添加下面的方法来获取deviceToken:
- - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
- NSString *token = [NSString stringWithFormat:@"%@", deviceToken];
- NSLog(@"My token is:%@", token);
- }
- - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
- NSString *error_str = [NSString stringWithFormat: @"%@", error];
- NSLog(@"Failed to get token, error:%@", error_str);
- }
获取到的deviceToken,我们可以提交给后台应用程序,发送通知的后台应用程序除了需要知道deviceToken之外,还需要一个与APNS连接的证书。
(自iOS开发文档"Local and Push Notification Programming Guide"里与iOS相关的部分翻译)
-----------------------------------------▲客户端处理------------------------------------------
建议每次程序启动的时候都调用registerForRemoteNotificationTypes来重新获取设备相关的token,而不要缓存token.
这是因为,如果用户重装了iOS或者用户换了设备并且恢复程序备份到一个新的设备,都将导致这个token值不一样。
当iOS收到远程消息时,
如果应用程序isn't running in the foreground,iOS会处理这个消息,比如弹出一个框、在应用程序的icon上显示红色数字。
然后如果用户通过点击弹框进入程序,iOS会启动程序并调用application:didFinishLaunchingWithOptions并且拿远程消息的payload进行传参.
如果用户直接点击app icon进入程序,iOS会启动程序并同样调用application:didFinishLaunchingWithOptions,但是传参将不会有远程消息的任何信息。
如果应用程序is running in the foreground,就会调用application:didReceiveRemoteNotification.
----------------------------------------------▲APNs----------------------------------------------
IOS设备会持久连接APNs以接受远程消息。
provider发送消息到APNs,然后APNs再发送到目标IOS设备。(这个传输是单向的。)
这个消息的内容含两部分:设备token和payload.
反馈服务--
有时候APNs发送消息到某设备(token)某程序(bundle identifier)但是该设备并没有这个程序,多次这种情况之后,APNs会通知provider,通过其连接的一个反馈服务(a feedback service)。
反馈服务为每一个程序维护了一个失效设备列表,provider应该获取这个列表从而停止向APNs发送以这些设备为目的地的某程序的远程消息。
APNs的安全架构--
provider需要一个有效证书才能和APNs连接(这个证书有目标程序的Bundle identifier信息)。
与APNs连接后,provider向APNs发送的消息带有设备token(由目标程序连接provider然后发来token),APNs以此找到目标设备,然后看目标设备里的目标程序有接受推送的证书,APNs以此验证给目标设备的目标程序发送的消息是合法的。
注意:远程消息是不可靠的。
----------------------------------------▲Provider-------------------------------------------
Payload--
最多256bytes。
本地化alert:
eg:"alert" : {"loc-key":"GAME_PLAY_REQUEST_FORMAT","loc-args":["Jenna","Frank"]},
程序包里面的本地化字符串如下:
"GAME_PLAY_REQUEST_FORMAT" = "%@ and %@ have invited you to play Monopoly";
这样,最后显示alert的字符串就是:
"Jenna and Frank have invited you to play Monopoly"
一个JSON Payload的完整例子(为了性能,建议去掉空白字符)
{
"aps" :
{
"alert" : "Message received from Bob",
"badge" : 5,
"sound" : "bingbong.aiff"
},
"myCustomData" : ["bang", "bang、bang、bang"],
"myCustomData2": 42
}
----------------------------------------▲部署-------------------------------------------
要部署provider端client/server程序,需要来自苹果的SSL证书。下称provider证书。
provider证书对应于特定的iOS Application(Bundle identifier)。
同时,provider证书分为开发测试和产品两种版本,对应于两种APNs环境:
Sandbox(Development) :可用模拟器测试。地址是gateway.sandbox.push.apple.com: TCP 2195
Production(Distribution):gateway.push.apple.com: TCP 2195
同
时,provision profile也对应了两个版本:Development和Distribution.(The Distribution
provision profile is a requirement for submitting your application to
the App Store.)
可以在xcode里看iOS
application所处何环境:看编译选项里的code-signing identity,如果是"iPhone
Developer:Firstname Lastname"证书与provisioning
profile匹配成对,说明是sandbox环境。如果是"iPhone
Distribution:Companyname"证书与provision
profile匹配成对,说明是production环境。根据release和debug分别配置code-signing
identity选项的证书将会是一个好主意。
注意:尽管SSL证书(即provider证书)没有放到iOS
application的providion profile里,但是ios
application是否支持远程消息推送依然取决于profile,因为profile内含开发者证书、设备ID、application
ID(Bundle identifier)、"是否支持推送"(在苹果开发者网站上配置证书的时候配置的)等信息。(The provisioning
profile is a collection of assets that associates developers of an
application and their devices with an authorized development team and
enables those devices to be used for testing.The profile contains
certificates,device identifiers,the application's bundle ID,and all
entitlement,including <aps-environment>.)
以文本方式打
开*.mobileprovision,会看到里面类似xml格式,其中<key>Entitlements</key>里包含
了<key>aps-environment</key>,说明支持远程消息推送,<key>aps-
environment</key>下面的<string>说明是调试版本还是发布版本(对应于Sandbox环境和
Production环境)。
●安装证书到服务端
你应该安装SSL证书和私匙到你的provider程序运行的服务器上。
步骤如下:
0.安装该证书到mac电脑的钥匙串。
1.打开钥匙串,在左侧面板上点击我的证书栏。
2.找到这个SSL证书,展开会看到证书和私匙。
3.我们选中证书和私匙,然后导出为"个人信息交换文件"--即扩展名为p12的文件。
4.provider服务器程序最好用Ruby和Perl这类语言,可以方便的处理"个人信息交换文件"里的证书。mac下打开终端输入以下命令以把证书转换为这类语言乐于交流的格式:
openssl pkcs12 -in CertificateName.p12 -out CertificateName.pem -nodes
5.把这pem文件拷到服务器上并安装到某个适当的位置。
----------------------------------------▲Provider与APNs连接----------------------------------------
●连接APNs之前provider需要具备什么
APNs提供的连接接口是二进制的、streaming TCP socket、异步 的。
Production环境是通过gateway.push.apple.com:2195,Development环境是gateway.sandbox.push.apple.com:2195。
Provider可以建立多个与APNs的连接。每个都得用TLS(or SSL)来建立安全通道,需要用到SSL证书(就是上面提到的provider连接APNs要用到的SSL证书)。
----------------------
Note
要建立与APNs的TLS会话,需要在provider服务器上安装Entrust Secure CA根证书。Moa OS
X是默认已安装的,其他系统的话,可以没有安装,可以从Entrust SSL
Certificates的网站http://www.entrust.net/下载安装根证书。
----------------------
●发送消息的二进制接口和消息的数据包格式
消息须是网络字节顺序(即大尾顺序),消息里面的payload部分不可以超过256字节,且不得以'\0'结尾。
消息格式见"The Binary Interface and Notification Formats"章节。
●The Feedback Service
feedback service包含了这样的列表:某iOS应用程序对应的"设备"("设备"用二进制格式的设备token来标识)。--这些设备是由于各种原因而不能接收APNs发来的消息。
Provider应该定期查询这个列表,并且作出对应处理,如:停止向这些的设备发送消息。
provider访问feedback server通过一个与发送消息类似的二进制接口。
Production环境通过feedback.push.apple.com:2196来建立连接,Development通过feedback.sandbox.push.apple.com:2196。
feedback service和发送消息是不同的服务接口(但都属于APNs),他的连接方式和发送消息是一样的。也要通过证书建立SSL连接,连接后你不需要发送任何命令,直接开始读取流一直读完为止,然后provider要解析读到的数据。
数据是由多个这样的格式组成的:
| 四字节时间 | 2字节的token 长度 | 32字节的设备token |
关
于"四字节时间":Provider需要判断对应设备的这个iOS应用程序有没有在该时间之后重新像provider发送注册推送消息所获得的设备
token。如果没有,就认为该设备失效了,需停止向该设备发送消息。如果有,那就是这个设备失效过,但是现在又有效了,只是feedback
service还没来得及刷新列表。