iOS 推送基础知识

Apple 使用公共密钥数字证书对来自 iOS 应用程序的推送请求进行身份验证,所以您首先需要创建身份验证密钥,并向 Apple 注册它们。我将在下一节中花相当长的篇幅来直接介绍这一点。

接下来,需要确定安装该应用程序并选择接收该应用程序的推送通知的每台设备。工作顺序如下:

  1. iOS 应用程序中的一个警告对话框会请求用户的许可,以接收推送通知。
  2. 如果用户授予权限,iOS 应用程序会联系 Apple Push Notification 服务 (APNs) 获得一个 ID 字符串,以惟一地标识在此设备上安装的这个应用程序。(您可以将 ID 看作类似于传统消息场景中的收件人电话号码)。
  3. iOS 应用程序将 ID 上传到您的服务器应用程序。
  4. 当服务器应用程序需要发送推送消息时,它对 Apple 的推送服务器进行身份验证,然后使用从步骤 2 和 3 中获得的 ID 指定消息的收件人。
  5. 如果收件人设备在线,它接收并处理消息。如果设备离线,那么消息将会排队,然后当设备下一次在线时交付。

    APNs 也使您的服务器应用程序可以定期验证您所保存的应用程序 ID 列表。这使您有机会删除那些在后来删除应用程序或修改其推送选择状态的用户和 ID。

    这听起来好像要涉及很多工作,的确是这样的。这就是为什么会存在像 Urban Airship 的服务,收费代理消息(见侧栏)。

    在说明如何注册应用程序之后,我将进入开发 iOS 推送通知应用程序的细节,并利用开源 Java 库及其服务器组件的帮助。

您自己服务器的一个替代方案:Urban Airship

Urban Airship 是一种服务,让您无需运行自己的服务器就可以推送消息(参见 参考资料)。将私钥上传到 Urban Airship 并使用其基于 Web 的消息控制台,以向用户推送消息。Urban Airship 提供了一个 iOS SDK,使您的应用程序可以很容易地将每个已安装的设备注册到其服务器,那么这些设备就会出现在消息控制台。虽然 Urban Airship 可以简化您的工作,但是成本昂贵,并且您还需要了解基本的推送通知概念。

APNs 也使您的服务器应用程序可以定期验证您所保存的应用程序 ID 列表。这使您有机会删除那些在后来删除应用程序或修改其推送选择状态的用户和 ID。

这听起来好像要涉及很多工作,的确是这样的。这就是为什么会存在像 Urban Airship 的服务,收费代理消息(见侧栏)。

在说明如何注册应用程序之后,我将进入开发 iOS 推送通知应用程序的细节,并利用开源 Java 库及其服务器组件的帮助。

注册应用程序

要注册您的应用程序使用推送通知,您首先需要创建一对私有/公共密钥,对 APNs 服务器的 API 调用进行身份验证。在 Mac 上,您可以通过使用 KeyChain Access 应用程序完成该操作。选择 KeyChain Access > Certificate Assistant > Request a Certificate from a Certificate Authority,以创建一个证书签名请求文件。该请求文件包含生成的公共密钥对,而相应的私钥则保存在 KeyChain Access 中。请务必在对话框中选择 Saved to disk 选项,如图 1 所示:

图 1. 在 Mac 上从 KeyChain Access 程序生成一个密钥对和签名请求

接下来,登录到 Apple 的应用程序配置门户(参见 参考资料),并上传您的签名请求文件,它将被关联到相应的配置概要文件。大多数应用程序都有一个供测试人员使用的开发配置概要文件,以及一个用于 App Store 的生产概要文件,所以您将最有可能产生和上传两个签名请求。在您上传签名请求后,该门户生成一个数字证书,供您下载。该证书包含公钥,现在 APNs 识别为与您应用程序关联。图 2 显示了一个示例:

图 2. 来自 Apple 的数字证书

下载数字证书,并双击要下载的文件。现在,KeyChain Access 自动导入数字证书,并将它与您在创建签名请求时生成的私钥关联起来。图 3 显示了在 KeyChain Access 中的公钥和私钥对:

图 3. 在 KeyChain Access 中的公钥和私钥对

现在,将密钥对导出为一个文件,所使用的格式称为 Personal Information Exchange (p12)。当您创建 p12 文件时,KeyChain Access 要求您指定一个密码来保护私钥。如果您想使用一个空密码,也没有问题。

从这时起,所有对 APNs 推送服务器的 API 请求都必须由 p12 文件中​​的私钥进行加密,然后由该 p12 文件中的公钥进行数字签名,以验证 API 调用是真的由您生成的。稍后在本文中描述如何与 APNs 服务器交互时,我将演示如何使用密钥。(如果您使用 Urban Airship,它会要求您将 p12 文件以及任何密码上传到其服务器,以便它能够以您的名义发送推送消息。)

现在,您已经有了推送证书,您必须重新下载并重新安装您的应用程序配置概要文件,因为概要文件现在已被更新为可以支持应用程序的推送通知。

请求和保存设备令牌

您的 iOS 应用程序需要请求用户许可,在它所安装的设备上接收推送通知。通常情况下,您可以通过一个简单的 API 调用在应用程序代理中实现这一点,如清单 1 所示:

清单 1. 请求用户许可
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeAlert)];

如果用户授予许可,应用程序会自动联系 APNs 服务器获取设备令牌。令牌使 APNs 可以将该特定设备上所安装的这个特定应用程序识别为一个消息目的地。这个过程是自动的,并且在后台执行。您不需要为它编写任何代码。

在 APNs 服务器响应后,应用程序代理中的 didRegisterForRemoteNotificationsWithDeviceToken 方法被调用,并将设备令牌作为一个调用参数传递进来。您必须保存设备令牌并将它上传到自己的推送通知服务器,如清单 2 所示:

清单 2. 接收一个 ID 并将它上传到服务器
- (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];
}

在理想情况下,您将令牌与一些标记用户的信息(如在您的系统中的个人用户名)相关联,使您的服务器知道稍后要将消息发送给谁。(您可以将它想像为类似于将电话号码与个人姓名相关联。)如果您没有将令牌与自己的用户标识信息关联,您仍然可以将消息发送到这些设备,但您不能为每个用户自定义消息,因为您所拥有的是一个目标设备的字母令牌字符串。

服务器应该将令牌及其相关的标识信息保存在数据库中。在大多数应用程序中,它被保存在用户配置文件数据库中。

发送一个推送消息

要发送一个推送消息,您的服务器:

  1. 查找即将发送消息的目标应用程序 ID 列表
  2. 根据收件人的用户配置文件为每个收件人个性化消息
  3. 联系 APNs 消息服务器

APNs 服务器的 Web 服务 API 很复杂。对 Java 开发人员来说幸运的是,开源 JavaPNS 库可以使其使用变得更简单。JavaPNS 和下载和文档链接参见 参考资料

清单 3 中的代码显示了如何使用 JavaPNS 库向设备发送类似于短信的消息:

清单 3. 发送一个推送消息
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 对象的列表,您可以用它来确定推送交付的状态,如清单 4 所示:

清单 4. 检查推送交付的状态
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 沙箱接收一个无效设备令牌的列表:

清单 5. 检查以更新活动的设备令牌
List<Device> inactiveDevices = Push.feedback("keypair.p12", "password", false);
/* remove inactive devices from your own list of devices */

不要将资源浪费在将消息发送到已删除您的应用程序的设备,或选择不接收通知的设备,这一点很重要。

其他考虑事项

推送通知不能在 iOS 模拟器上进行测试;您必须将应用程序部署到实际设备上对其进行测试。因为用于对消息进行身份验证的数字证书被捆绑到应用程序的配置概要文件,您需要使用在开发或临时分发应用程序中的开发证书进行测试。在应用程序通过审批并在 App Store 中提供后,您必须切换到生产证书。

此外,重要的是要理解,为大数据库中的用户定制和发送推送消息是一项资源密集型工作。例如,每 5 秒遍历一次一个百万用户级的数据库,以确定 10 个当时需要收到消息的用户,这成本非常高。服务器端的基础架构需要精心的设计和规划,以支持对大量用户的频繁推送通知。相反,一次向一百万个用户发送推送消息会产生大量的流量,因此通过使用一个线程池可以更好地处理这一场景,而不是阻止一个单独线程。JavaPNS 库提供一个简单的 API,它使用线程池,可以同时将消息推送给大量设备。

结束语

推送技术让您的服务器应用程序绕过电信运营商,并直接通过 Internet 向 iOS 设备的应用程序发送消息。虽然实现推送通知并非小事(客户端 SSL 证书对 Apple 服务器的身份验证需求很复杂),但是来自 Urban Airship 和 JavaPNS 等第三方的帮助可以使发送通知更加容易。SMS 和 MMS 有自己的位置,并且仍然比推送技术更可靠,但您可以通过实现推送消息使您的 iOS 应用程序更加丰富,提供更多的功能。

iOS远程消息推送的更多相关文章

  1. iOS远程消息推送原理

    1. 什么是远程消息推送? APNs:Apple Push Notification server 苹果推送通知服务苹果的APNs允许设备和苹果的推送通知服务器保持连接,支持开发者推送消息给用户设备对 ...

  2. 分分钟搞定IOS远程消息推送

    一.引言 IOS中消息的推送有两种方式,分别是本地推送和远程推送,本地推送在http://my.oschina.net/u/2340880/blog/405491这篇博客中有详细的介绍,这里主要讨论远 ...

  3. iOS远程消息推送自我整理版

    @interface AppDelegate () <UIApplicationDelegate> @end @implementation AppDelegate - (BOOL)app ...

  4. iOS 远程消息推送,原理和开发详解篇(新手推荐)

    1.APNS的推送机制 首先我们看一下苹果官方给出的对ios推送机制的解释.如下图 Provider就是我们自己程序的后台服务器,APNS是Apple Push Notification Servic ...

  5. iOS开发——远程消息推送的实现

    在我们使用App的过程中.总是会收到非常多的消息推送.今天我们就要来实现这个功能.首先消息推送分为本地消息推送和远程消息推送.而当中又以远程消息最为经常使用. 可是在推送远程消息之前.有两个前提条件. ...

  6. iOS开发笔记8:Remote Notification远程消息推送处理

    远程消息推送处理场景有三种:分别是app还没有运行.app在前台运行以及app在后台运行,下面介绍相关流程及三种场景下处理步骤 1.流程 (1)注册通知 首先是在注册远程消息推送,需要注意的是iOS8 ...

  7. iOS 10 消息推送(UserNotifications)秘籍总结(二)

    背景 上一篇博客iOS 10 消息推送(UserNotifications)秘籍总结(一)发布后被 简书编辑推荐至首页,这着实让我受宠若惊啊.可是好事不长,后面发生了让我伤心欲绝的事,我的女朋友不要我 ...

  8. iOS 10 消息推送(UserNotifications)秘籍总结(一)

    前言 之前说会单独整理消息通知的内容,但是因为工(就)作(是)的(很)事(懒)没有更新文章,违背了自己的学习的初衷.因为互联网一定要有危机意识,说不定眼一睁,我们就out丢了饭碗. 图片来源网络.jp ...

  9. iOS 之消息推送(个推)---个人小结

    前言:自从上个星期开始整这个推送,弄了差不多一个星期,今天终于给整好了,因此现在来记录这段"奇妙"的旅程. 我们公司使用的消息推送是用的第三方--个推,这里不得不说一下,个推的技术 ...

随机推荐

  1. 【转】Android ProgressDialog的使用

    原文网址:http://blog.csdn.net/sjf0115/article/details/7255280 版权声明:本文为博主原创文章,未经博主允许不得转载. <1>简介 Pro ...

  2. NDK的安装和下载

    从官网下载NDK 下载页面:https://developer.android.com/ndk/downloads/index.html 从镜像站点下载NDK "大师兄"是一个由腾 ...

  3. poj 3575 Crosses and Crosses(SG函数)

    Crosses and Crosses Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 3063   Accepted: 11 ...

  4. Milk Patterns - poj 3261 (求重复k次的最长子串)

    题目大意:给你一个数组,求这个数组里面至少重复k次的子串.   分析:后缀数组的练手题目...不过给的数字比较大,可以先离散化处理一下即可.   代码如下: ===================== ...

  5. Apache-POI操作Excel的一些小技巧

    Apache-POI操作Excel将合并后的单元格全部填充为相同数据的一个实例. private static void fillMergedRegion(final Sheet sheet) { f ...

  6. string.Format字符串格式说明

    先举几个简单的应用案例: 1.格式化货币(跟系统的环境有关,中文系统默认格式化人民币,英文系统格式化美元) string.Format("{0:C}",0.2) 结果为:¥0.20 ...

  7. UVa1606 UVaLive3259 FZU1309 HDU1661 POJ2280 ZOJ2390 Amphiphilic Carbon Molecules

    填坑系列 考虑所有经过两个点的直线,一定有最优解. 再考虑确定一个点,按极角顺序枚举所有直线,从而O(1)转移信息. 还有代码实现技巧 #include<cstdio> #include& ...

  8. <WEB>平板_手机开发_13 个处理触摸事件和多点触摸的JS 库

    触摸屏是现在所有智能手机的标配,还包括各种平板设备,而且很多桌面也慢慢在开始支持触摸操作.要开发支持触摸屏设备的 Web 应用,我们需要借助浏览器的触摸事件来实线. 下图是各种触摸事件说明: 本文我们 ...

  9. ThinkPHP 中M方法和D方法的具体区别(转)

    M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...

  10. hdu5294||2015多校联合第一场1007 最短路+最大流

    http://acm.hdu.edu.cn/showproblem.php? pid=5294 Problem Description Innocent Wu follows Dumb Zhang i ...