今天看啥
热点:

iOS消息推送机制和过程原理

iOS消息推送的工作机制可以简单的用下图来概括:


 

Provider是指某个iPhone软件的Push服务器,APNS是Apple Push Notification Service的缩写,是苹果的服务器。

 

上图可以分为三个阶段:

第一阶段:应用程序把要发送的消息、目的iPhone的标识打包,发给APNS。

第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发送到iPhone。

第三阶段:iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。

 

从上图我们可以看到:

1、应用程序注册消息推送。

2、iOS从APNS Server获取device token,应用程序接收device token。

3、应用程序将device token发送给PUSH服务端程序。

4、服务端程序向APNS服务发送消息。

5、APNS服务将消息发送给iPhone应用程序。

 

无论是iPhone客户端和APNS,还是Provider和APNS,都需要通过证书进行连接。原文来自帮客之家www.bkjia.com

 iOS消息推送机制的相关证书

下面我介绍一下几种用到的证书。

 

一、CSR文件

 

1、生成Certificate Signing Request(CSR)


 

2、填写你的邮箱和常用名称,并选择保存到硬盘。


 

点击继续:


 

这样就在本地生成了一个Push.certSigningRequest文件。

 

二、p12文件

 

1、导出密钥。



 

2、输入你的密码。

 

 

这样就生成了一个Push.p12文件。

 

三、SSL certificate文件

 

1、用你付过费的帐号登录到iOS Provisioning Portal,并新建一个App ID,这个过程可以参考:iOS应用的真机调试,这样就会生成下面这条记录:


 

2、点击右侧的Configure:


 

3、点击Development Push SSL Certificate一行后的Configure:

 

 

4、点击Continue:


 

5、选择前面生成好的Push.certSigningRequest文件,点击Generate,出现如下所示的页面:


 

6、点击Continue:


 

7、点击Download,并将文件命名为aps_developer_identity.cer。

 

8、点击Done,你会发现状态变成了Enabled:


 

注意:有的App ID的Apple Push Notification service列是灰色的,并且不允许使用Configure按钮,这是因为APNS不支持带通配符的App ID。

 

到现在为止,我们已经生成了三个文件:

 

1、Push.certSigningRequest

2、Push.p12

3、aps_developer_identity.cer

 

在项目的AppDelegate中的didFinishLaunchingWithOptions方法中加入下面的代码:

 

Ios代码
  1. [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];

 

通过registerForRemoteNotificationTypes方法,告诉应用程序,能接受push来的通知。

 

在项目的AppDelegate中添加下面的方法来获取deviceToken:

 

Ios代码
	[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];  

获取到的deviceToken,我们可以提交给后台应用程序,发送通知的后台应用程序除了需要知道deviceToken之外,还需要一个与APNS连接的证书。

 

这个证书可以通过我们前面生成的两个文件中得到。

 

1、将aps_developer_identity.cer转换成aps_developer_identity.pem格式

 

Shell代码
  1. 			openssl x509 -in aps_developer_identity.cer -inform DER -out aps_developer_identity.pem -outform PEM 
    	

 

2、将p12格式的私钥转换成pem

 

Shell代码
  1. 			openssl pkcs12 -nocerts -out Push_Noenc.pem -in Push.p12 
    	

 

3、创建p12文件

 

Shell代码
  1. 			openssl pkcs12 -export -in aps_developer_identity.pem -inkey Push_Noenc.pem -certfile Push.certSigningRequest -name "aps_developer_identity" -out aps_developer_identity.p12 
    	

 

这样我们就得到了在.net或java等后台应用程序中使用的证书文件:aps_developer_identity.p12

 

如果后台应用是php的话,那么可以按照 iOS消息推送机制中pem文件的生成这篇文章中的方法来生成php后台应用程序中使用的证书文件:ck.pem

 

IOS消息推送过程出现的常见问题和故障

下午把IOS消息推送接口的证书、URL地址更换为正式的,测试推送消息时竟然出错…

在使用测试证书、URL测试时,一切正常,应该是苹果那边对接口进行了一些限制。

根据报的异常对消息推送接口做了2个小修改:

1、临时设置php脚本执行允许的最大时间
 

set_time_limit(0);

2、在每推送一个苹果设备device_token后程序休眠5秒,然后继续推送下一个设备…
 

sleep(5);

设置休眠的原因是避免对苹果接口在短时间的频繁读取,造成链接中断。5秒觉得有点长,后续根据情况再做适当调整吧。

然后测试了一下接口,对设备连续推送20次消息,设备成功接收20个消息提示,一切正常。

补充:2013/07/25 11:30

按照昨天的修改今天又测试了一下,对单个设备联系发送是没有问题的,但是当从服务器获取所有设备token信息后,对这些设置进行循环推送信息时出现问题了:
 

Warning: fwrite() [function.fwrite]: SSL operation failed with code 1. OpenSSL Error messages: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry in /home/75/api/controller/iospush.class.php on line 102
 
Warning: fwrite() [function.fwrite]: SSL: Broken pipe in /home/75/api/controller/iospush.class.php on line 102

在谷歌上搜索了下出现这些问题的解决方法,根据一些建议常识了一下:

1、在原基础上添加2个stream_context_set_option操作:
 

stream_context_set_option($ctx, 'ssl', 'allow_self_signed', true);
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);

添加后:
 

$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'allow_self_signed', true);
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
stream_context_set_option($ctx, 'ssl', 'local_cert', $pem_path);
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);

测试后,单一设备连续推送20次成功,从服务器读取所有设备信息后,对这些设备进行推送,只成功推送了前几条,后面的都失败。

2、尝试更改SSL版本:

把:
 

$fp = stream_socket_client("ssl://gateway.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);

改为:
 

$fp = stream_socket_client("sslv3://gateway.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);

测试后,单一设备连续发送成功。因推送操作是正式推送,为不影响用户,未对所有设备再进行推送操作。后续再补充

补充:2013/07/26 18:22

好像找到问题所在了,应该是服务器存储的用户device-token中,有些数据是无用的,也就是存在那些已经把APP应用卸载了的用户数据,这个需要定期通过苹果APNS feedback服务来更新自己服务器上的device-token信息,以此来保证服务器上存储的都是有用的数据。正在测试通过feedback服务来删除无用的数据中…

补充:2013/07/29 16:39

在原有基础上,做了以下修改:

1、通过feedback服务定期更新数据库device_token信息(删除无用的token值)。

2、获取所有device_token信息后,进行分组,分批进行推送。每推送一批后断开SSL链接,休眠N秒,再次链接SSL,进行下一批推送。这里考虑数据量不是很大,所以直接从数据库中获取所有device_token信息后再分组处理,而没有采取分批从数据库获取数据的方式。

3、限制推送内容的长度。加长度限制是由于苹果服务器接收推送消息一次只可以接收7000 字节,每次发送消息又必须少于256 字节。

4、添加推送进度条,显示推送进度状况。

继续测试,发现没问题。
 

 

评论暂时关闭