iOS如何让APP删除后不接受APNS推送消息
http://blog.csdn.net/jinglijun/article/details/8642768?reload
首先简单说下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调用在应用程序代理中实现这一点,如下:
[html]view plaincopy [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]; 如果用户授予许可,应用程序会自动联系APNS 服务器获取设备令牌。令牌使APNS可以将该特定设备上所安装的这个特定应用程序识别为一个消息目的地。这个过程是自动的,并且在后台执行。您不需要为它编写任何代码。 在APNS服务器响应后,应用程序代理中的didRegisterForRemoteNotificationsWithDeviceToken方法被调用,并将设备令牌作为一个调用参数传递进来。您必须保存设备令牌并将它上传到自己的推送通知服务器,如下: [html]view plaincopy - (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 库向设备发送类似于短信的消息:
[html]view plaincopy 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对象的列表,您可以用它来确定推送交付的状态,如图所示:
[html]view plaincopy 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