Override
远程推送通知,就是从远程服务器图推送给客户端的通知,需要联网,又称为APNs(Apple Push Notification Services)。
- 所有的苹果设备,在联网状态下,都会与苹果的服务器建立长连接,即只要联网了,就一直保持连接。
- 长连接的作用有:时间校准、系统升级、查找我的iPhone。
- 长连接的好处,数据传输速度快、数据保持最新状态。
APNs的推送机制
与Android上我们自己实现的推送服务不同,Apple对设备的控制非常严格,消息推送的流程必须要经过APNs:
Provider 表示发出通知的后台服务器,APNs 是Apple Push Notification Service的缩写,是苹果的推送服务器。Client App 是我们开发的App。
从上图中可看出,应用收到通知,分为三步:
- 应用程序的服务器端把要发送的消息、目的Apple设备的唯一标识打包,发给APNs。
- APNs在自身的已注册Push服务的应用列表中,查找有相应标识的设备,并把消息发送到设备。
- iOS系统把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。
要想实现消息推送,有两点非常重要:
-
App的推送证书
要能够完整实现一条消息推送,需要我们在App ID中打开Push Notifications,需要我们准备好Provisioning Profile和SSL证书,并且一定要注意Development和Distribution环境是需要分开的。最后,把SSL证书导入到服务器平台,就可以尝试远程消息推送了。具体的操作流程如下。
-
设备标识DeviceToken
知道了谁要推送,或者说要推送给哪个App之后,APNs还需要知道推到哪台设备上,这就是设备标识的作用。获取设备标识的流程如下:
APNs推送通知的详细工作流程
主要步骤如下:
- App注册APNs消息推送功能。
- iOS从APNs服务器上获取到DeviceToken,App接收DeviceToken。
- App将DeviceToken保存到后台服务器中
- 当某些特定事件发生时,后台服务器就会给APNs服务器发送一条推送消息
- APNs再将消息推送给目的设备,然后推送给App
APNs具体实现步骤
APNs服务器通过DeviceToken找到我们的设备应用,然后推送消息。而DeviceToken需要配置推送证书才可以获得,而推送证书需要知道我们的App ID(App的BundleID,应用的唯一标识)和UDID(设备唯一标识),还有自己的服务器的UDID。 另外,因模拟器不支持推送,所以我们需要一台苹果的设备,iPhone、iPad或iPod。
一、CSR文件
在开发证书、生产证书以及APNs推送证书的配置过程中,都会用到Certificate Signing Request(也就是CSR)文件。CSR文件的生成不分先后,可以在需要的时候在生成。
首先,找到Mac应用程序里的 钥匙串访问.app ,打开。
选择从证书颁发机构请求证书
填上你的邮箱和常用名,可以随便写,常用名 要记一下,会用到,选择保存到磁盘。
继续,选择存储位置。
点击完成。
生成后的CSR文件如下:
二、APNs推送证书
首先登陆进入Apple的开发者中心,选择证书模块。
点击iOS Apps的证书(Certificates)。
进入后选择App IDs。
打开我们需要启用APNs服务的App ID。如果不存在则点击右上角的“+”号创建App ID,创建App ID的流程可参考其它文章,不在此文介绍列。
发现Push Notifications是Disabled
或Configurable
时,点击Edit,找到推送模块,配送证书。
点击 Create Certificate… 按钮,进入下一界面,告诉我们需要一个CSR文件(就是上一节通过钥匙串生成的CSR文件 APNS.certSigningRequest ),意思就是让我们的MAC具有调试推送的权限.
点击继续。
选择 Choose File… 按钮上传我们上面生成的CSR文件(APNS.certSigningRequest)。
上传以后点击 Generate 按钮生成APNs推送证书。
到这里证书就配置好了,点击 Download 下载证书,Done 完成配置,或者点击 Add Another 继续添加APNs推送证书。也可以从Certificates->Development/Production中找到配置好的APNs推送证书,在下载下来。
双击打开我们下载下来的APNs推送证书。
打开以后,就可以在钥匙串中找到我们的证书了。
三、导出密钥
打开钥匙串访问,找到我们生产的专用秘钥(专用秘钥的名称就是我们在最开始生成CSR请求的时候填写的常用名)。
右键选择导出,输入导出名称为APNS
:
在这里需要输入一个密码来对文件进行加密。这个密码必须要铭记,切记!
然后输入你电脑的密码,点击允许。
这样我们就在桌面上生成了一个APNS.p12文件。
四、APNs推送调试
推送证书都配置好以后,为了保险起见,我还需要进行真机调试APNs。真机调试需要保证App的Bundle ID与APNs的App ID保持一致。然后就是在AppDelegate.m
中注册推送,然后可以借用一些工具测试我们的推送。如果操作正确,那么手机将会收到推送。推送可能会有一点延迟,请耐心等待。如果始终没有收到消息,那么需要你检查一下各个环节的配置是否正确。如果各个环节没有问题,但是仍没有收到消息,那么请看一下下面的主意事项:
- 推送的测试工具的Device Token与
AppDelegate.m
中注册的Device Token是否一致 - 设置完APNs后,有没有重新生成Provisioning证书
- 重新生成Provisioning证书以后,把该证书更新的我们的Mac上(最好先把之前的Provisioning证书全部删除,防止出错)
- 网络环境是否可以连接Apple的推送服务
- 企业证书打包的App,需要生产环境才能收到APNs推送
五、注册推送
iOS8以前的版本注册通知方式:
UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes];
iOS8及以后的APNs注册分为两步,且有两个方法需要调用:
方法一:registerForRemoteNotifications
方法没有参数,根据苹果的文档说明,该方法调用成功将会回调方法application:didRegisterForRemoteNotificationsWithDeviceToken:
,失败回调application:didFailToRegisterForRemoteNotificationsWithError:
。从中可以看出,该方法只是为了获取 deviceToken 。苹果可能考虑到一些应用注册提醒只是为乐获取 deviceToken ,所以单独提出了一个方法。
[[UIApplication sharedApplication] registerForRemoteNotifications];
方法二:registerUserNotificationSettings:
方法才是真正用于注册接受推送消息的,需要设置参数。
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
完整的注册方法:
UIUserNotificationType notificationTypes = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
兼容iOS8以前和iOS8及iOS以后的注册通知的代码:
UIApplication *application = [UIApplication sharedApplication];
if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationType notificationTypes = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
}
if ([application respondsToSelector:@selector(registerForRemoteNotifications)]) {
[application registerForRemoteNotifications];
}else{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
[application registerForRemoteNotificationTypes:notificationTypes];
}
ps: 开发证书只能在Debug模式下运行,在release下只能使用生产证书。