首先简单说下iOS APNS:
Apple 使用公共密钥数字证书对来自 iOS应用程序的推送请求进行身份验证,所以您首先需要创建身份验证密钥,并向 Apple 注册它们。我将在下一节中花相当长的篇幅来直接介绍这一点。
接下来,需要确定安装该应用程序并选择接收该应用程序的推送通知的每台设备。工作顺序如下:
1.iOS 应用程序中的一个警告对话框会请求用户的许可,以接收推送通知。
2.如果用户授予权限,iOS 应用程序会联系 Apple Push Notification服务 (APNs) 获得一个 ID字符串,以惟一地标识在此设备上安装的这个应用程序。(您可以将 ID 看作类似于传统消息场景中的收件人电话号码)。
3.iOS 应用程序将 ID上传到您的服务器应用程序。
4.当服务器应用程序需要发送推送消息时,它对 Apple 的推送服务器进行身份验证,然后使用从步骤2 和 3中获得的 ID 指定消息的收件人。
如果收件人设备在线,它接收并处理消息。如果设备离线,那么消息将会排队,然后当设备下一次在线时交付。
APNS也使您的服务器应用程序可以定期验证您所保存的应用程序 ID列表。这使您有机会删除那些在后来删除应用程序或修改其推送选择状态的用户和 ID。
请求和保存设备令牌
您的 iOS 应用程序需要请求用户许可,在它所安装的设备上接收推送通知。通常情况下,您可以通过一个简单的 API调用在应用程序代理中实现这一点,如下:
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
如果用户授予许可,应用程序会自动联系 APNS 服务器获取设备令牌。令牌使 APNS可以将该特定设备上所安装的这个特定应用程序识别为一个消息目的地。这个过程是自动的,并且在后台执行。您不需要为它编写任何代码。
在 APNS 服务器响应后,应用程序代理中的 didRegisterForRemoteNotificationsWithDeviceToken方法被调用,并将设备令牌作为一个调用参数传递进来。您必须保存设备令牌并将它上传到自己的推送通知服务器,如下:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { NSString *tokenStr = [deviceToken description]; NSString *pushToken = [[[[tokenStr stringByReplacingOccurrencesOfString:@"<" withString:@""] stringByReplacingOccurrencesOfString:@">" withString:@""] stringByReplacingOccurrencesOfString:@" " withString:@""] retain]; // Save the token to server NSString *urlStr = [NSString stringWithFormat:@"https://%@/push_token", RINGFULDOMAIN]; NSURL *url = [NSURL URLWithString:urlStr]; NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; [req setHTTPMethod:@"POST"]; [req setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-type"]; NSMutableData *postBody = [NSMutableData data]; [postBody appendData:[[NSString stringWithFormat:@"username=%@", username] dataUsingEncoding:NSUTF8StringEncoding]]; [postBody appendData:[[NSString stringWithFormat:@"&token=%@", pushToken] dataUsingEncoding:NSUTF8StringEncoding]]; [req setHTTPBody:postBody]; [[NSURLConnection alloc] initWithRequest:req delegate:nil]; }
服务器应该将令牌及其相关的标识信息保存在数据库中。在大多数应用程序中,它被保存在用户配置文件数据库中。
发送一个推送消息
要发送一个推送消息,您的服务器要查找即将发送消息的目标应用程序 ID 列表,根据收件人的用户配置文件为每个收件人个性化消息
联系 APNS 消息服务器,APNS 服务器的 Web服务 API 很复杂。对 Java开发人员来说幸运的是,开源 JavaPNS 库可以使其使用变得更简单。JavaPNS和下载和文档链接参见 参考资料。下面代码显示了如何使用 JavaPNS 库向设备发送类似于短信的消息:
String[] devices = {"token1", "token2}; List<PushedNotification> notifications = Push.alert("Hello World!", "keypair.p12", "password", false, devices);
JavaPNS 库的主界面方法是在 Push类中的静态方法。APNS 允许您在消息中嵌入各种内容。请参阅 iOS推送消息指南,获取所支持的负载类型的完整清单(参见 参考资料)。Push类为每种类型的消息提供方便的方法,并且它将消息的转换为 APNS 服务器接受的 JavaScript Object Notation (JSON)格式。在 清单3 中,keypair.p12 是从 KeyChain Access导出的 p12 文件,password是 p12 文件的密码。devices阵列是从 iOS 应用程序接收的设备令牌列表。所有这些设备都将收到这个推送消息。在参数中的false值指定该消息应发送到 APNS 开发服务器(沙箱),而不是其生产服务器。(回忆一下,您通常为沙箱创建一个 p12密钥对,为生产服务器创建一个不同的密钥对。)
方法调用返回的值是一个 PushedNotification对象的列表,您可以用它来确定推送交付的状态,如图所示:
for (PushedNotification notification : notifications) { if (notification.isSuccessful()) { /* Apple accepted the notification and should deliver it */ } else { String invalidToken = notification.getDevice().getToken(); /* Add code here to remove invalidToken from your database */ } }
如果通知对象告诉您,有某个设备令牌不再处于激活状态,例如,如果用户从设备中删除了该应用程序,或在应用程序设置中禁用了通知,您应该从数据库中删除该令牌,以便您不会再向它发送消息。
保持最新的活动设备令牌列表的另一种方式,是让您的服务器应用程序定期检查 APNS服务器。清单 5显示了如何查询 APNS 反馈服务,使用 JavaPNS从 APNS 沙箱接收一个无效设备令牌的列表:
<?php
//feedback.php
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'server_certificates_bundle.pem');
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
// assume the private key passphase was removed.
// stream_context_set_option($ctx, 'ssl', 'passphrase', $pass);
$fp = stream_socket_client('ssl://feedback.push.apple.com:2196', $error, $errorString, 60, STREAM_CLIENT_CONNECT, $ctx);
// Development server is ssl://feedback.sandbox.push.apple.com:2196
if (!$fp) {
print "Failed to connect feedback server: $err $errstr\n";
return;
}
else {
print "Connection to feedback server OK\n";
}
print "APNS feedback results\n";
while ($devcon = fread($fp, 38))
{
$arr = unpack("H*", $devcon);
$rawhex = trim(implode("", $arr));
$feedbackTime = hexdec(substr($rawhex, 0, 8));
$feedbackDate = date('Y-m-d H:i', $feedbackTime);
$feedbackLen = hexdec(substr($rawhex, 8, 4));
$feedbackDeviceToken = substr($rawhex, 12, 64);
print "TIMESTAMP:" . $feedbackDate . "\n";
print "DEVICE ID:" . $feedbackDeviceToken. "\n\n";
}
fclose($fp);
?>
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
可能是要先给已经删除了应用的设备发送push,apple才会认为此token无效,此时再访问feedback才能正确获取无效的token列表,否则可能为空。不要将资源浪费在将消息发送到已删除您的应用程序的设备,或选择不接收通知的设备,这一点很重要。
其他考虑事项
推送通知不能在 iOS模拟器上进行测试;您必须将应用程序部署到实际设备上对其进行测试。因为用于对消息进行身份验证的数字证书被捆绑到应用程序的配置概要文件,您需要使用在开发或临时分发应用程序中的开发证书进行测试。在应用程序通过审批并在 App Store中提供后,您必须切换到生产证书。
此外,重要的是要理解,为大数据库中的用户定制和发送推送消息是一项资源密集型工作。例如,每5 秒遍历一次一个百万用户级的数据库,以确定 10个当时需要收到消息的用户,这成本非常高。服务器端的基础架构需要精心的设计和规划,以支持对大量用户的频繁推送通知。相反,一次向一百万个用户发送推送消息会产生大量的流量,因此通过使用一个线程池可以更好地处理这一场景,而不是阻止一个单独线程。JavaPNS库提供一个简单的 API,它使用线程池,可以同时将消息推送给大量设备。
结束语
推送技术让您的服务器应用程序绕过电信运营商,并直接通过 Internet向 iOS 设备的应用程序发送消息。虽然实现推送通知并非小事(客户端 SSL证书对 Apple 服务器的身份验证需求很复杂),但是来自 Urban Airship和 JavaPNS 等第三方的帮助可以使发送通知更加容易。SMS和 MMS 有自己的位置,并且仍然比推送技术更可靠,但您可以通过实现推送消息使您的 iOS应用程序更加丰富,提供更多的功能。
细说feedback客户服务器
如果供应商试图推送通知给应用程序,但应用程序不再存在于设备,该设备反馈一个报告给苹果推送通知服务器。这种情况经常发生在用户卸载应用程序。如果设备报告失败的传递尝试的应用程序的APN需要一些方法来通知供应商,以便它能够避免将通知发送给该设备。这样做可以减少不必要的报文开销,提高了系统的整体性能。
为了这个目的,苹果推送通知服务为每一个应用程序建立了一个feedback的APN不断更新列表中的设备的服务。设备标识以设备令牌二进制编码格式被识别。供应商应定期查询反馈服务器来确定他们的应用列表中的设备令牌。然后,经核实该应用程序已没有注册接受APNS应停止将通知发送给这些设备。
访问的反馈服务是通过二进制接口与用于发送推送通知您的生产反馈服务访问端口2196通过feedback.push.apple.com,类似;您访问沙箱反馈通过feedback.sandbox.push服务apple.com,端口2196。推送通知的二进制接口,你必须使用TLS(SSL)建立一个安全的通信通道的SSL证书,需要为这些连接的是同一个置备发送通知。要建立一个值得信赖的供应商的身份,你应该出示该证书的APN在连接时使用对等验证。
一旦你连接,传输立即开始,你不需要发送任何命令的APN开始读取流书面反馈服务,直到有没有更多的数据读取接收到的数据是在具有下列格式的元组:
Timestamp:自1970年以来,固定在UTC时间戳(一个四字节time_t的值),表示在APN时,决定不再存在于设备中的应用。这个值,这是网络顺序,代表秒。您应该使用时间戳来确定,如果应用程序在设备上重新注册的设备令牌的那一刻起录得的反馈服务与您的服务,如果没有的话,你应该停止的设备发送推送通知。
Token length:长度为两个字节的整数值,以网络顺序的设备令牌。
Device token:设备令牌是二进制编码。
在检查反馈服务,不从设备上是不存在的应用程序发送推送通知的APN显示器供应商的辛勤工作。
参考文章:http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWIthAPS/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW3