Push的基本原理
可以用苹果官方文档中的一张图片简单的概括:

它是基于这样一种工作流程:
- 我们的iOS设备,只要处于联网状态,就会和苹果的服务器保持长连接,以便苹果的各种消息服务能够正常工作(比如说iMassage、FaceTime、以及我们要用到的APNs服务等) 。
- 当用户装了我们实现Push功能的应用,启动应用时会向苹果注册DeviceToken (这个token是消息推送的唯一标识,APNs寻找消息推送的设备就是靠这个标识,但是这个token不可以作为设备的唯一标识使用,因为当用户重装设备系统或者恢复设备的时候DeviceToken会发生改变),我们获得这个DeviceToken之后需要发送给我们的服务器(即Provider)。
- 当有推送需求的时候,Provider把消息和DeviceToken按照指定的格式发送给APNs。
- APNs收到Provider发送的消息,会根据DeviceToken查找对应的设备,如果设备在线,则会把消息发送给设备,如果设备不在线,则会等到设备在线的时候把消息推送到设备。
注:苹果并不保证每条消息都会推送成功。 - 设备收到消息之后,根据SSL证书判断是哪个程序,然后程序再做相应的处理(比如显示消息文字、声音、消息数量等)。
流程了解完毕,下面就可以考虑实现了。实现其实很简单,只需要生成所需要的证书,然后简单的设置一下,写几行代码就可以搞定。
生成各种需要的证书
相信程序做到推送这里的人肯定都会把CSR文件、APP ID 以及真机调试文件之类的安装好了,我们需要做的就只是在开发者中心的APP ID配置中选择对应的APP ID,然后点击Configure,打开Enable for Apple Push Notification Service选项,该选项下有Development和Production两个SSL证书可以配置,显然其分别为开发证书和产品证书。我们测试的话就生成Development证书就可以了。根据CSR文件,生成相应的SSL Certificate,然后保存,假如命名为aps_development.cer。然后我们需要单击以下aps_development以安装到我们的MAC上。
然后我们在钥匙串中导出aps_development.cer为**.p12**,设置密码,选择保存路径,假设命名为aps_development_key.p12(如果你的证书是在别的Mac上生成的,则导出为.p12这个选项可能是灰色的,不能点击,这时你需要在原电脑上导出.p12)。
下面我们要用生成的证书,生成服务器端所需要的证书。
此时应该有3个证书:
- CertificateSigningRequest.certSigningRequest
- aps_development.cer
- aps_development_key.p12
- 将aps_development.cer转换成pem格式
openssl x509 -in aps_development.cer -inform DER -out aps_development.pem -outform PEM
- 将aps_development_key.p12转换成aps_development_key.pem
openssl pkcs12 -nocerts -out aps_development_key.pem -in aps_development_key.p12
- 创建用于服务器端的SSL p12证书aps_development_service.p12
openssl pkcs12 -export -in aps_development.pem -inkey aps_development_key.pem -certfile CertificateSigningRequest.certSigningRequest -name "aps_development_service" -out aps_development_service.p12
这个步骤需要输入3次左右的密码,建议密码和aps_development_key.p12的密码一致,以防混淆。
这里生成的aps_development_service.p12就是服务器向APNs服务器发送Push消息需要的证书。把证书和密码给服务器端,他们就可以连接APNs并发送消息了。
苹果APNs服务器有两个地址,分别为测试的沙盒地址:
gateway.sandbox.push.apple.com:2195
以及正式地址:
gateway.push.apple.com:2195
客户端获取DeviceToken
- 注册Push服务
服务器想要给指定设备发送消息,需要知道这个设备的DeviceToken,然后上传到服务器。下面就来说明如何获得DeviceToken。
想要能够接收到苹果返回的DeviceToken,需要先注册Push功能:(iOS8和之前注册方式不同,请注意判断)
//推送注册
if (iOS8) {
[[UIApplication sharedApplication] registerForRemoteNotifications];
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil]];
}else{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];
}
- 接收token
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
//获取token
NSString *token = [NSString stringWithFormat:@"%@",deviceToken];
NSLog(@"获取asseccToken%@",token);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
NSLog(@"获取asseccToken失败%@",error);
}
拿到了这个DeviceToken,就可以上传到服务器了,服务器就可以用这个DeviceToken给设备发消息了。
服务器发送Push消息
苹果对于所发的消息也有严格的要求,必须要按照苹果的格式,且内容不能超过256字节,如果超过,APNs则不会推送给设备。
基本格式:
{
"aps" : {
"alert" : {
"title" : "我是标题",
"body" : "我是内容"
},
"sound" : "default",
"badge" : 999
}
}
其中aps键值是必须的,badge表示应用图标小红点所显示的数字,为0则不显示。sound表示提示音。
如果需要添加自定义数据,请加到aps空间之外。
{
"aps" : {
"alert" : {
"title" : "我是标题",
"body" : "我是内容"
},
"sound" : "default",
"badge" : 999
}
"page":"home"
}
为了减小消息体积,可以把page写成p,home写成1、2、3之类的,和服务器人员统一好结构。比如"p":"1"。
详细结构参考苹果官方文档:ApplePushService
客户端接收Push
服务器发送消息后,经过APNs的处理,就可以到达我们的设备了。我们需要用下面的代码接收消息。
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(@"%@",userInfo);
}
如果应用还没启动,则可以在下面的方法中获取消息。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//推送信息
NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
}
如果服务器给badge设置了值的话,应用图标会一直显示数字,可以用下面的函数清空。
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
如果你做完了这些,迫切的想测试结果,但是服务器那边还没开发完成的话,你可以用下面的工具来测试。
Push测试工具
因为我们公司的服务器是用C#写的,所以附上一个可用的项目地址吧:
C#服务器端代码
小结
只要把各种证书和Token设置好,苹果的推送相对来说特别的简单。
苹果把推送完全控制在自己手里,对开发者和用户来说,都有很大的好处。对于开发者来说,用官方的接口能够很方便的集成推送功能,对用户来说,不会每天都收到乱七八糟的各种推送。这种为用户和开发者考虑的行为,真的很让人舒服。