iOS消息推送完整版
来源:互联网 发布:plc编程软件免费下载 编辑:程序博客网 时间:2024/06/08 01:22
<div id="article_content" class="article_content">
<h2><a name="t0"></a>一、背景概述:<span style="white-space:pre"> </span></h2>
<h3><a name="t1"></a>1,环境配置</h3>
<p>APNS:Apple Push Notification Service。本文对推送相关概念不再赘述,只侧重完整流程。 </p>
<p>Demo 开发环境:Mac os 10.9.4 ,Xcode 6.0.1 ;<a href="http://lib.csdn.net/base/softwaretest" class="replace_word" title="软件测试知识库" target="_blank" style="color:#df3434; font-weight:bold;">测试</a>设备:iphone 4s(<a href="http://lib.csdn.net/base/ios" class="replace_word" title="iOS知识库" target="_blank" style="color:#df3434; font-weight:bold;">iOS</a> 7.1)</p>
<p>服务端开发环境:mac 10.9.4 + <a href="http://lib.csdn.net/base/php" class="replace_word" title="PHP知识库" target="_blank" style="color:#df3434; font-weight:bold;">PHP</a> 5.4.24、</p>
<p>Demo 下载地址:<a target="_blank" href="http://download.csdn.net/detail/jiajiayouba/8019667">点击打开链接</a></p>
<h3><a name="t2"></a>2,APNS 相关博客</h3>
<p>如对apns相关概念不清楚,可参考以下几个博客:(博客中部分内容重复,但总体来说,通读一遍,还是大有裨益的)</p>
<p> http://cshbbrain.iteye.com/blog/1859810 =》IOS 基于APNS消息推送原理与实现(<a href="http://lib.csdn.net/base/javaee" class="replace_word" title="Java EE知识库" target="_blank" style="color:#df3434; font-weight:bold;">Java</a>后台)</p>
<p>http://www.cnblogs.com/qq78292959/archive/2012/07/16/2593651.html =》iOS消息推送机制的实现<br>
</p>
<p>http://blog.csdn<a href="http://lib.csdn.net/base/dotnet" class="replace_word" title=".NET知识库" target="_blank" style="color:#df3434; font-weight:bold;">.NET</a>/xunyn/article/details/8243573 =》APNS编程----iOS真机测试消息推送<br>
</p>
<p>http://blog.csdn<a href="http://lib.csdn.net/base/dotnet" class="replace_word" title=".NET知识库" target="_blank" style="color:#df3434; font-weight:bold;">.Net</a>/wswqiang/article/details/8208581 =》IOS APNS 处理<br>
</p>
<p>http://eric-gao.iteye.com/blog/1567777 =》 IOS PEM 文件的生成</p>
<p>http://www.36coder.com/study/996.html =》PHP 实现APNS 推送<br>
</p>
<p></p>
<p><span style="color:#ff6666">http://blog.csdn.net/sxfcct/article/details/7939082 =》 APNS 相关总结</span><span style="color:#ff0000"></span>(推荐)</p>
<h3><a name="t3"></a>3,APNS 接口</h3>
<p><span style="color:#ff9900">消息推送:</span></p>
<p></p>
<p>开发接口:gateway.sandbox.push.apple.com:2195</p>
<p></p>
<p>发布接口:gateway.push.apple.com:2195</p>
<p><span style="color:#ff9966">反馈服务:</span></p>
<p>开发接口:feedback.sandbox.push.apple.com:2196</p>
<p>发布接口:产品接口:feedback.push.apple.com:2196</p>
<p style="margin-top:0px; margin-bottom:16px; color:rgb(68,68,68); font-family:'Microsoft Yahei','Helvetica Neue',Helvetica,Arial,sans-serif; font-size:15px; line-height:25px">
<span style="font-family:Arial,Helvetica,sans-serif; font-size:12px">二、制作Push证书和Pem文件</span></p>
<h3><a name="t4"></a>1,新建一个App ID</h3>
<div>新建流程不再赘述,这里只提醒两点:1》App ID Suffix 中,一定要选择Explicit App ID;2》App Services 中,记得勾选Push Notifications。这里以新建一个id为:com.eversoft.PushDemo 为例。</div>
<h3><a name="t5"></a>2,配置push开发证书</h3>
<div>在App IDs中,选中刚才新建的App id:com.eversoft.PushDemo ,单击,展开详细信息属性。</div>
<div><img src="http://img.blog.csdn.net/20141009135115859?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
<div>在详细信息属性中,单击下方的“Edit”按钮,<img src="http://img.blog.csdn.net/20141009135553281?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></div>
<div>在新打开的编辑界面,单击“Create Certificate”,</div>
<div><img src="http://img.blog.csdn.net/20141009140028786?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
<div>在新打开的界面中,会提示我们,创建一个csr 证书签名请求文件。具体的创建步骤,界面中已经给出了详细的英文说明。</div>
<div><img src="http://img.blog.csdn.net/20141009140333334?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
<div>在进行下一步之前,我们先按照英文说明,创建一个 CSR 文件。</div>
<div>
<ul>
<li>在mac电脑上,打开应用程序 keychain(钥匙串访问);</li><li>在keychain菜单栏中,依次选择“钥匙串访问”=》“证书助理”=》“从证书颁发机构请求证书”;<img src="http://img.blog.csdn.net/20141009140849749?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></li><li>在新打开的“证书助理”界面中,填写用户电子邮件地址,常用名称,CA电子邮件地址,这两个邮件地址直接填写你的苹果账号的邮件地址即可,然后选择“存储到磁盘”,然后点击“继续”;<img src="http://img.blog.csdn.net/20141009141351843?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></li><li>选择CSR文件保存位置,“存储”即可。至此, CSR 文件,制作完成。</li></ul>
<br>
</div>
<div>回到刚才我们的web页面上,点击“Continue”,进入下一页面;新的页面中,会要求我们上传刚才制作的csr文件,选择“Choose File”,找到我们刚才存储的csr文件,单击“打开”,最后,点击页面上的“Generate”按钮,到此,开发使用的push证书制作完毕。<img src="http://img.blog.csdn.net/20141009142241621?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></div>
<div>证书生成成功后,选择“Download”,将制作好的证书下载到本地。然后双击下载的证书aps_development.cer,双击后,证书就自动导入到钥匙串中了。</div>
<div><br>
</div>
<div>打开 keychain,左侧钥匙串选择“登录”,种类选择“所有项目”,在右侧窗口中,选中刚才导入的Apple Development IOS Push Services证书(不用选中专用密钥),右键,选择导出,命名为:ck.p12 ,存储时,会提示输入保护密码,这里为演示方便,就输入了123456。之后又会要求输入电脑登录密码,输入即可。</div>
<div><img src="http://img.blog.csdn.net/20141009145405000?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
<h3><a name="t6"></a>3,生成PEM文件</h3>
<div>最后,打开终端,执行以下命令,生成pem文件</div>
<div></div>
<p>openssl pkcs12 -in ck.p12 -out ck.pem -nodes </p>
<p>执行时,会要求输入导入密码,这里输入刚才的保护密码123456即可。</p>
<p><img src="http://img.blog.csdn.net/20141009145927262?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</p>
<p>到此,php 服务端使用的pem证书就制作完毕了。</p>
<p>Development PP 文件制作不再赘述。</p>
<h2><a name="t7"></a>三、IOS 代码编写</h2>
<p>首先,在AppDelegate.m 中:</p>
<h3><a name="t8"></a>1,注册通知</h3>
<p></p>
<div class="dp-highlighter bg_objc"><div class="bar"><div class="tools"><b>[objc]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 423px; top: 5195px; width: 22px; height: 11px; z-index: 99;"><embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="22" height="11" name="ZeroClipboardMovie_1" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=1&width=22&height=11" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><span class="tracking-ad" data-mod="popu_167"><a href="https://code.csdn.net/snippets/481571" target="_blank" title="在CODE上查看代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/CODE_ico.png" width="12" height="12" alt="在CODE上查看代码片" style="position:relative;top:1px;left:2px;"></a></span><span class="tracking-ad" data-mod="popu_170"><a href="https://code.csdn.net/snippets/481571/fork" target="_blank" title="派生到我的代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/ico_fork.svg" width="12" height="12" alt="派生到我的代码片" style="position:relative;top:2px;left:2px;"></a></span></div></div><ol start="1" class="dp-objc"><li class="alt"><span><span>- (</span><span class="keyword">BOOL</span><span>)application:(</span><span class="keyword">UIApplication</span><span> *)application</span><span class="vars"> didFinishLaunchingWithOptions</span><span>:(</span><span class="keyword">NSDictionary</span><span> *)launchOptions { </span></span></li><li class=""><span> <span class="comment">// Override point for customization after application launch.</span><span> </span></span></li><li class="alt"><span> <span class="keyword">ViewController</span><span> *mainCtrl=[[ViewController</span><span class="vars"> alloc</span><span>]</span><span class="vars"> init</span><span>]; </span></span></li><li class=""><span> <span class="keyword">self</span><span class="xcodeconstants">.window</span><span class="xcodeconstants">.rootViewController</span><span>=mainCtrl; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="comment">//注册通知</span><span> </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> ([UIDevice</span><span class="vars"> currentDevice</span><span>]</span><span class="xcodeconstants">.systemVersion</span><span class="xcodeconstants">.doubleValue</span><span><</span><span class="xcodenumber">8</span><span class="xcodeconstants">.0</span><span>) { </span></span></li><li class=""><span> [[UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="vars"> registerForRemoteNotificationTypes</span><span>:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)]; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">else</span><span> { </span></span></li><li class="alt"><span> [[UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="vars"> registerForRemoteNotifications</span><span>]; </span></span></li><li class=""><span> [[UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="vars"> registerUserNotificationSettings</span><span>:[UIUserNotificationSettings</span><span class="vars"> settingsForTypes</span><span>:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert</span><span class="vars"> categories</span><span class="keyword">:nil</span><span>]]; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">//判断是否由远程消息通知触发应用程序启动</span><span> </span></span></li><li class=""><span> <span class="keyword">if</span><span> (launchOptions) { </span></span></li><li class="alt"><span> <span class="comment">//获取应用程序消息通知标记数(即小红圈中的数字)</span><span> </span></span></li><li class=""><span> NSInteger badge = [UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="xcodeconstants">.applicationIconBadgeNumber</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (badge></span><span class="xcodenumber">0</span><span>) { </span></span></li><li class=""><span> <span class="comment">//如果应用程序消息通知标记数(即小红圈中的数字)大于0,清除标记。</span><span> </span></span></li><li class="alt"><span> badge--; </span></li><li class=""><span> <span class="comment">//清除标记。清除小红圈中数字,小红圈中数字为0,小红圈才会消除。</span><span> </span></span></li><li class="alt"><span> [UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="xcodeconstants">.applicationIconBadgeNumber</span><span> = badge; </span></span></li><li class=""><span> <span class="keyword">NSDictionary</span><span> *pushInfo = [launchOptions</span><span class="vars"> objectForKey</span><span>:</span><span class="string">@"UIApplicationLaunchOptionsRemoteNotificationKey"</span><span>]; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="comment">//获取推送详情</span><span> </span></span></li><li class="alt"><span> <span class="keyword">NSString</span><span> *pushString = [NSString</span><span class="vars"> stringWithFormat</span><span>:</span><span class="string">@"%@"</span><span>,[pushInfo </span><span class="vars"> objectForKey</span><span>:</span><span class="string">@"aps"</span><span>]]; </span></span></li><li class=""><span> <span class="keyword">UIAlertView</span><span> *alert=[[UIAlertView</span><span class="vars"> alloc</span><span>]</span><span class="vars"> initWithTitle</span><span>:</span><span class="string">@"finish Loaunch"</span><span class="vars"> message</span><span>:pushString</span><span class="vars"> delegate</span><span class="keyword">:nil</span><span class="vars"> cancelButtonTitle</span><span>:</span><span class="string">@"cancel"</span><span class="vars"> otherButtonTitles</span><span class="keyword">:nil</span><span>,</span><span class="keyword"> nil</span><span class="vars"> nil</span><span>]; </span></span></li><li class="alt"><span> [alert<span class="vars"> show</span><span>]; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">YES</span><span>; </span></span></li><li class=""><span>} </span></li></ol><div class="save_code tracking-ad" data-mod="popu_249" style="display: none;"><a href="javascript:;" target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png"></a></div></div><pre code_snippet_id="481571" snippet_file_name="blog_20141010_1_1959414" name="code" class="objc" style="display: none;">- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
ViewController *mainCtrl=[[ViewController alloc] init];
self.window.rootViewController=mainCtrl;
//注册通知
if ([UIDevice currentDevice].systemVersion.doubleValue<8.0) {
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];
}
else {
[[UIApplication sharedApplication] registerForRemoteNotifications];
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil]];
}
//判断是否由远程消息通知触发应用程序启动
if (launchOptions) {
//获取应用程序消息通知标记数(即小红圈中的数字)
NSInteger badge = [UIApplication sharedApplication].applicationIconBadgeNumber;
if (badge>0) {
//如果应用程序消息通知标记数(即小红圈中的数字)大于0,清除标记。
badge--;
//清除标记。清除小红圈中数字,小红圈中数字为0,小红圈才会消除。
[UIApplication sharedApplication].applicationIconBadgeNumber = badge;
NSDictionary *pushInfo = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
//获取推送详情
NSString *pushString = [NSString stringWithFormat:@"%@",[pushInfo objectForKey:@"aps"]];
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"finish Loaunch" message:pushString delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil];
[alert show];
}
}
return YES;
}</pre><br>
<p></p>
<h3><a name="t9"></a>2,注册通知后,获取device token</h3>
<p></p>
<p></p>
<div class="dp-highlighter bg_objc"><div class="bar"><div class="tools"><b>[objc]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 423px; top: 5978px; width: 22px; height: 11px; z-index: 99;"><embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="22" height="11" name="ZeroClipboardMovie_2" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=2&width=22&height=11" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><span class="tracking-ad" data-mod="popu_167"><a href="https://code.csdn.net/snippets/481571" target="_blank" title="在CODE上查看代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/CODE_ico.png" width="12" height="12" alt="在CODE上查看代码片" style="position:relative;top:1px;left:2px;"></a></span><span class="tracking-ad" data-mod="popu_170"><a href="https://code.csdn.net/snippets/481571/fork" target="_blank" title="派生到我的代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/ico_fork.svg" width="12" height="12" alt="派生到我的代码片" style="position:relative;top:2px;left:2px;"></a></span></div></div><ol start="1" class="dp-objc"><li class="alt"><span><span>- (</span><span class="keyword">void</span><span>)application:(</span><span class="keyword">UIApplication</span><span> *)app</span><span class="vars"> didRegisterForRemoteNotificationsWithDeviceToken</span><span>:(</span><span class="keyword">NSData</span><span> *)deviceToken { </span></span></li><li class=""><span> <span class="keyword">NSString</span><span> *token = [NSString</span><span class="vars"> stringWithFormat</span><span>:</span><span class="string">@"%@"</span><span>,</span><span class="vars"> deviceToken</span><span>]; </span></span></li><li class="alt"><span> NSLog(<span class="string">@"My token is:%@"</span><span>, token); </span></span></li><li class=""><span> <span class="comment">//这里应将device token发送到服务器端</span><span> </span></span></li><li class="alt"><span>} </span></li><li class=""><span> </span></li><li class="alt"><span>- (<span class="keyword">void</span><span>)application:(</span><span class="keyword">UIApplication</span><span> *)app</span><span class="vars"> didFailToRegisterForRemoteNotificationsWithError</span><span>:(</span><span class="keyword">NSError</span><span> *)error { </span></span></li><li class=""><span> <span class="keyword">NSString</span><span> *error_str = [NSString</span><span class="vars"> stringWithFormat</span><span>: </span><span class="string">@"%@"</span><span>,</span><span class="vars"> error</span><span>]; </span></span></li><li class="alt"><span> NSLog(<span class="string">@"Failed to get token, error:%@"</span><span>, error_str); </span></span></li><li class=""><span>} </span></li></ol><div class="save_code tracking-ad" data-mod="popu_249"><a href="javascript:;" target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png"></a></div></div><pre code_snippet_id="481571" snippet_file_name="blog_20141010_2_1720217" name="code" class="objc" style="display: none;">- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [NSString stringWithFormat:@"%@", deviceToken];
NSLog(@"My token is:%@", token);
//这里应将device token发送到服务器端
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSString *error_str = [NSString stringWithFormat: @"%@", error];
NSLog(@"Failed to get token, error:%@", error_str);
}</pre><br>
<p></p>
<h3><a name="t10"></a>3,接收推送通知</h3>
<p></p>
<p></p>
<div class="dp-highlighter bg_objc"><div class="bar"><div class="tools"><b>[objc]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 423px; top: 6275px; width: 22px; height: 11px; z-index: 99;"><embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="22" height="11" name="ZeroClipboardMovie_3" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=3&width=22&height=11" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><span class="tracking-ad" data-mod="popu_167"><a href="https://code.csdn.net/snippets/481571" target="_blank" title="在CODE上查看代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/CODE_ico.png" width="12" height="12" alt="在CODE上查看代码片" style="position:relative;top:1px;left:2px;"></a></span><span class="tracking-ad" data-mod="popu_170"><a href="https://code.csdn.net/snippets/481571/fork" target="_blank" title="派生到我的代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/ico_fork.svg" width="12" height="12" alt="派生到我的代码片" style="position:relative;top:2px;left:2px;"></a></span></div></div><ol start="1" class="dp-objc"><li class="alt"><span><span>- (</span><span class="keyword">void</span><span>)application:(</span><span class="keyword">UIApplication</span><span> *)application</span><span class="vars"> didReceiveRemoteNotification</span><span>:(</span><span class="keyword">NSDictionary</span><span> *)userInfo </span></span></li><li class=""><span>{ </span></li><li class="alt"><span> [UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="xcodeconstants">.applicationIconBadgeNumber</span><span>=</span><span class="xcodenumber">0</span><span>; </span></span></li><li class=""><span> <span class="keyword">for</span><span> (</span><span class="keyword">id</span><span> key in userInfo) { </span></span></li><li class="alt"><span> NSLog(<span class="string">@"key: %@, value: %@"</span><span>, key, [userInfo</span><span class="vars"> objectForKey</span><span>:key]); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="comment">/* eg.</span> </span></li><li class=""><span><span class="comment"> key: aps, value: {</span> </span></li><li class="alt"><span><span class="comment"> alert = "\U8fd9\U662f\U4e00\U6761\U6d4b\U8bd5\U4fe1\U606f";</span> </span></li><li class=""><span><span class="comment"> badge = 1;</span> </span></li><li class="alt"><span><span class="comment"> sound = default;</span> </span></li><li class=""><span><span class="comment"> }</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li class=""><span> <span class="keyword">UIAlertView</span><span> *alert=[[UIAlertView</span><span class="vars"> alloc</span><span>]</span><span class="vars"> initWithTitle</span><span>:</span><span class="string">@"remote notification"</span><span class="vars"> message</span><span>:userInfo[</span><span class="string">@"aps"</span><span>][</span><span class="string">@"alert"</span><span>]</span><span class="vars"> delegate</span><span class="keyword">:nil</span><span class="vars"> cancelButtonTitle</span><span>:</span><span class="string">@"cancel"</span><span class="vars"> otherButtonTitles</span><span class="keyword">:nil</span><span>,</span><span class="keyword"> nil</span><span class="vars"> nil</span><span>]; </span></span></li><li class="alt"><span> [alert<span class="vars"> show</span><span>]; </span></span></li><li class=""><span>} </span></li></ol><div class="save_code tracking-ad" data-mod="popu_249" style="display: none;"><a href="javascript:;" target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png"></a></div></div><pre code_snippet_id="481571" snippet_file_name="blog_20141010_3_1480237" name="code" class="objc" style="display: none;">- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[UIApplication sharedApplication].applicationIconBadgeNumber=0;
for (id key in userInfo) {
NSLog(@"key: %@, value: %@", key, [userInfo objectForKey:key]);
}
/* eg.
key: aps, value: {
alert = "\U8fd9\U662f\U4e00\U6761\U6d4b\U8bd5\U4fe1\U606f";
badge = 1;
sound = default;
}
*/
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"remote notification" message:userInfo[@"aps"][@"alert"] delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil];
[alert show];
}</pre><br>
注意:app 前台运行时,会调用 remote notification;app后台运行时,点击提醒框,会调用remote notification,点击app 图标,不调用remote notification,没反应;app 没有运行时,点击提醒框,finishLaunching 中,launchOptions 传参,点击app 图标,launchOptions 不传参,不调用remote notification。
<p></p>
<h2><a name="t11"></a>四、服务器端代码编写</h2>
<div>此章不在IOS程序员职责范围之内,故只给出示例代码,不做深入讨论。</div>
<h3><a name="t12"></a>1,php 源码:</h3>
<p></p>
<div class="dp-highlighter bg_php"><div class="bar"><div class="tools"><b>[php]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 420px; top: 6828px; width: 22px; height: 11px; z-index: 99;"><embed id="ZeroClipboardMovie_4" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="22" height="11" name="ZeroClipboardMovie_4" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=4&width=22&height=11" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><span class="tracking-ad" data-mod="popu_167"><a href="https://code.csdn.net/snippets/481571" target="_blank" title="在CODE上查看代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/CODE_ico.png" width="12" height="12" alt="在CODE上查看代码片" style="position:relative;top:1px;left:2px;"></a></span><span class="tracking-ad" data-mod="popu_170"><a href="https://code.csdn.net/snippets/481571/fork" target="_blank" title="派生到我的代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/ico_fork.svg" width="12" height="12" alt="派生到我的代码片" style="position:relative;top:2px;left:2px;"></a></span></div></div><ol start="1" class="dp-c"><li class="alt"><span><span><!DOCTYPE html> </span></span></li><li class=""><span><html> </span></li><li class="alt"><span><head> </span></li><li class=""><span><meta http-equiv=<span class="string">"content-type"</span><span> content=</span><span class="string">"text/html;charset=utf-8"</span><span>> </span></span></li><li class="alt"><span><title>APNS</title> </span></li><li class=""><span></head> </span></li><li class="alt"><span><body> </span></li><li class=""><span><?php </span></li><li class="alt"><span><span class="comment">/**</span> </span></li><li class=""><span><span class="comment">* @file apns.php</span> </span></li><li class="alt"><span><span class="comment">* @synopsis apple APNS class</span> </span></li><li class=""><span><span class="comment">* @author Yee, <rlk002@gmail.com></span> </span></li><li class="alt"><span><span class="comment">* @version 1.0</span> </span></li><li class=""><span><span class="comment">* @date 2012-09-17 11:27:59</span> </span></li><li class="alt"><span><span class="comment">*/</span><span> </span></span></li><li class=""><span> <span class="keyword">class</span><span> APNS </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">const</span><span> ENVIRONMENT_PRODUCTION = 0; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> ENVIRONMENT_SANDBOX = 1; </span></span></li><li class=""><span> <span class="keyword">const</span><span> DEVICE_BINARY_SIZE = 32; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> CONNECT_RETRY_INTERVAL = 1000000; </span></span></li><li class=""><span> <span class="keyword">const</span><span> SOCKET_SELECT_TIMEOUT = 1000000; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> COMMAND_PUSH = 1; </span></span></li><li class=""><span> <span class="keyword">const</span><span> STATUS_CODE_INTERNAL_ERROR = 999; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> ERROR_RESPONSE_SIZE = 6; </span></span></li><li class=""><span> <span class="keyword">const</span><span> ERROR_RESPONSE_COMMAND = 8; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> PAYLOAD_MAXIMUM_SIZE = 256; </span></span></li><li class=""><span> <span class="keyword">const</span><span> APPLE_RESERVED_NAMESPACE = </span><span class="string">'aps'</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_environment</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_providerCertificateFile</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_rootCertificationAuthorityFile</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_connectTimeout</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_connectRetryTimes</span><span> = 3; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_connectRetryInterval</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_socketSelectTimeout</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_hSocket</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_deviceTokens</span><span> = </span><span class="keyword">array</span><span>(); </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_text</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_badge</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_sound</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_customProperties</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_expiryValue</span><span> = 604800; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_customIdentifier</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_autoAdjustLongPayload</span><span> = true; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$asurls</span><span> = </span><span class="keyword">array</span><span>(</span><span class="string">'ssl://gateway.push.apple.com:2195'</span><span>,</span><span class="string">'ssl://gateway.sandbox.push.apple.com:2195'</span><span>); </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_errorResponseMessages</span><span> = </span><span class="keyword">array</span><span> </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> 0 => <span class="string">'No errors encountered'</span><span>, </span></span></li><li class="alt"><span> 1 => <span class="string">'Processing error'</span><span>, </span></span></li><li class=""><span> 2 => <span class="string">'Missing device token'</span><span>, </span></span></li><li class="alt"><span> 3 => <span class="string">'Missing topic'</span><span>, </span></span></li><li class=""><span> 4 => <span class="string">'Missing payload'</span><span>, </span></span></li><li class="alt"><span> 5 => <span class="string">'Invalid token size'</span><span>, </span></span></li><li class=""><span> 6 => <span class="string">'Invalid topic size'</span><span>, </span></span></li><li class="alt"><span> 7 => <span class="string">'Invalid payload size'</span><span>, </span></span></li><li class=""><span> 8 => <span class="string">'Invalid token'</span><span>, </span></span></li><li class="alt"><span> self::STATUS_CODE_INTERNAL_ERROR => <span class="string">'Internal error'</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">function</span><span> __construct(</span><span class="vars">$environment</span><span>,</span><span class="vars">$providerCertificateFile</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">if</span><span>(</span><span class="vars">$environment</span><span> != self::ENVIRONMENT_PRODUCTION && </span><span class="vars">$environment</span><span> != self::ENVIRONMENT_SANDBOX) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception( </span></span></li><li class="alt"><span> <span class="string">"Invalid environment '{$environment}'"</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$this</span><span>->_environment = </span><span class="vars">$environment</span><span>; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span>(!</span><span class="func">is_readable</span><span>(</span><span class="vars">$providerCertificateFile</span><span>)) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception( </span></span></li><li class="alt"><span> <span class="string">"Unable to read certificate file '{$providerCertificateFile}'"</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$this</span><span>->_providerCertificateFile = </span><span class="vars">$providerCertificateFile</span><span>; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="vars">$this</span><span>->_connectTimeout = @</span><span class="func">ini_get</span><span>(</span><span class="string">"default_socket_timeout"</span><span>); </span></span></li><li class="alt"><span> <span class="vars">$this</span><span>->_connectRetryInterval = self::CONNECT_RETRY_INTERVAL; </span></span></li><li class=""><span> <span class="vars">$this</span><span>->_socketSelectTimeout = self::SOCKET_SELECT_TIMEOUT; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setRCA(</span><span class="vars">$rootCertificationAuthorityFile</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span>(!</span><span class="func">is_readable</span><span>(</span><span class="vars">$rootCertificationAuthorityFile</span><span>)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception( </span></span></li><li class=""><span> <span class="string">"Unable to read Certificate Authority file '{$rootCertificationAuthorityFile}'"</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$this</span><span>->_rootCertificationAuthorityFile = </span><span class="vars">$rootCertificationAuthorityFile</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getRCA() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_rootCertificationAuthorityFile; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> _connect() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$sURL</span><span> = </span><span class="vars">$this</span><span>->asurls[</span><span class="vars">$this</span><span>->_environment]; </span></span></li><li class=""><span> <span class="vars">$streamContext</span><span> = stream_context_create( </span></span></li><li class="alt"><span> <span class="keyword">array</span><span> </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">'ssl'</span><span> => </span><span class="keyword">array</span><span> </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">'verify_peer'</span><span> => isset(</span><span class="vars">$this</span><span>->_rootCertificationAuthorityFile), </span></span></li><li class=""><span> <span class="string">'cafile'</span><span> => </span><span class="vars">$this</span><span>->_rootCertificationAuthorityFile, </span></span></li><li class="alt"><span> <span class="string">'local_cert'</span><span> => </span><span class="vars">$this</span><span>->_providerCertificateFile </span></span></li><li class=""><span> ) </span></li><li class="alt"><span> ) </span></li><li class=""><span> ); </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="vars">$this</span><span>->_hSocket = @stream_socket_client(</span><span class="vars">$sURL</span><span>,</span><span class="vars">$nError</span><span>,</span><span class="vars">$sError</span><span>,</span><span class="vars">$this</span><span>->_connectTimeout,STREAM_CLIENT_CONNECT, </span><span class="vars">$streamContext</span><span>); </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span> (!</span><span class="vars">$this</span><span>->_hSocket) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> <span class="string">"Unable to connect to '{$sURL}': {$sError} ({$nError})"</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> stream_set_blocking(<span class="vars">$this</span><span>->_hSocket, 0); </span></span></li><li class=""><span> stream_set_write_buffer(<span class="vars">$this</span><span>->_hSocket, 0); </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> true; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> connect() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$bConnected</span><span> = false; </span></span></li><li class="alt"><span> <span class="vars">$retry</span><span> = 0; </span></span></li><li class=""><span> <span class="keyword">while</span><span>(!</span><span class="vars">$bConnected</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> try </span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$bConnected</span><span> = </span><span class="vars">$this</span><span>->_connect(); </span></span></li><li class="alt"><span> }catch (Exception <span class="vars">$e</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="vars">$nRetry</span><span> >= </span><span class="vars">$this</span><span>->_connectRetryTimes) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="vars">$e</span><span>; </span></span></li><li class=""><span> }<span class="keyword">else</span><span> </span></span></li><li class="alt"><span> { </span></li><li class=""><span> usleep(<span class="vars">$this</span><span>->_nConnectRetryInterval); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$retry</span><span>++; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> disconnect() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="func">is_resource</span><span>(</span><span class="vars">$this</span><span>->_hSocket)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> fclose(</span><span class="vars">$this</span><span>->_hSocket); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">return</span><span> false; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> getBinaryNotification(</span><span class="vars">$deviceToken</span><span>, </span><span class="vars">$payload</span><span>, </span><span class="vars">$messageID</span><span> = 0, </span><span class="vars">$Expire</span><span> = 604800) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$tokenLength</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$deviceToken</span><span>); </span></span></li><li class="alt"><span> <span class="vars">$payloadLength</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$payload</span><span>); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="vars">$ret</span><span> = pack(</span><span class="string">'CNNnH*'</span><span>, self::COMMAND_PUSH, </span><span class="vars">$messageID</span><span>, </span><span class="vars">$Expire</span><span> > 0 ? time() + </span><span class="vars">$Expire</span><span> : 0, self::DEVICE_BINARY_SIZE, </span><span class="vars">$deviceToken</span><span>); </span></span></li><li class=""><span> <span class="vars">$ret</span><span> .= pack(</span><span class="string">'n'</span><span>, </span><span class="vars">$payloadLength</span><span>); </span></span></li><li class="alt"><span> <span class="vars">$ret</span><span> .= </span><span class="vars">$payload</span><span>; </span></span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$ret</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> readErrorMessage() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$errorResponse</span><span> = @</span><span class="func">fread</span><span>(</span><span class="vars">$this</span><span>->_hSocket, self::ERROR_RESPONSE_SIZE); </span></span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="vars">$errorResponse</span><span> === false || </span><span class="func">strlen</span><span>(</span><span class="vars">$errorResponse</span><span>) != self::ERROR_RESPONSE_SIZE) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$errorResponse</span><span> = </span><span class="vars">$this</span><span>->parseErrorMessage(</span><span class="vars">$errorResponse</span><span>); </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (!</span><span class="func">is_array</span><span>(</span><span class="vars">$errorResponse</span><span>) || </span><span class="func">empty</span><span>(</span><span class="vars">$errorResponse</span><span>)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">if</span><span> (!isset(</span><span class="vars">$errorResponse</span><span>[</span><span class="string">'command'</span><span>], </span><span class="vars">$errorResponse</span><span>[</span><span class="string">'statusCode'</span><span>], </span><span class="vars">$errorResponse</span><span>[</span><span class="string">'identifier'</span><span>])) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="vars">$errorResponse</span><span>[</span><span class="string">'command'</span><span>] != self::ERROR_RESPONSE_COMMAND) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$errorResponse</span><span>[</span><span class="string">'timeline'</span><span>] = time(); </span></span></li><li class=""><span> <span class="vars">$errorResponse</span><span>[</span><span class="string">'statusMessage'</span><span>] = </span><span class="string">'None (unknown)'</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (isset(</span><span class="vars">$this</span><span>->_aErrorResponseMessages[</span><span class="vars">$errorResponse</span><span>[</span><span class="string">'statusCode'</span><span>]])) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$errorResponse</span><span>[</span><span class="string">'statusMessage'</span><span>] = </span><span class="vars">$this</span><span>->_errorResponseMessages[</span><span class="vars">$errorResponse</span><span>[</span><span class="string">'statusCode'</span><span>]]; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$errorResponse</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> parseErrorMessage(</span><span class="vars">$errorMessage</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span> unpack(</span><span class="string">'Ccommand/CstatusCode/Nidentifier'</span><span>, </span><span class="vars">$errorMessage</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> send() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (!</span><span class="vars">$this</span><span>->_hSocket) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">'Not connected to Push Notification Service'</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$sendCount</span><span> = </span><span class="vars">$this</span><span>->getDTNumber(); </span></span></li><li class="alt"><span> <span class="vars">$messagePayload</span><span> = </span><span class="vars">$this</span><span>->getPayload(); </span></span></li><li class=""><span> <span class="keyword">foreach</span><span>(</span><span class="vars">$this</span><span>->_deviceTokens AS </span><span class="vars">$key</span><span> => </span><span class="vars">$value</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$apnsMessage</span><span> = </span><span class="vars">$this</span><span>->getBinaryNotification(</span><span class="vars">$value</span><span>, </span><span class="vars">$messagePayload</span><span>, </span><span class="vars">$messageID</span><span> = 0, </span><span class="vars">$Expire</span><span> = 604800); </span></span></li><li class="alt"><span> <span class="vars">$nLen</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$apnsMessage</span><span>); </span></span></li><li class=""><span> <span class="vars">$aErrorMessage</span><span> = null; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="vars">$nLen</span><span> !== (</span><span class="vars">$nWritten</span><span> = (int)@fwrite(</span><span class="vars">$this</span><span>->_hSocket, </span><span class="vars">$apnsMessage</span><span>))) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$aErrorMessage</span><span> = </span><span class="keyword">array</span><span> </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">'identifier'</span><span> => </span><span class="vars">$key</span><span>, </span></span></li><li class=""><span> <span class="string">'statusCode'</span><span> => self::STATUS_CODE_INTERNAL_ERROR, </span></span></li><li class="alt"><span> <span class="string">'statusMessage'</span><span> => sprintf(</span><span class="string">'%s (%d bytes written instead of %d bytes)'</span><span>,</span><span class="vars">$this</span><span>->_errorResponseMessages[self::STATUS_CODE_INTERNAL_ERROR], </span><span class="vars">$nWritten</span><span>, </span><span class="vars">$nLen</span><span>) </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> addDT(</span><span class="vars">$deviceToken</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">if</span><span> (!preg_match(</span><span class="string">'~^[a-f0-9]{64}$~i'</span><span>, </span><span class="vars">$deviceToken</span><span>)) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> <span class="string">"Invalid device token '{$deviceToken}'"</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$this</span><span>->_deviceTokens[] = </span><span class="vars">$deviceToken</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getDTNumber() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="func">count</span><span>(</span><span class="vars">$this</span><span>->_deviceTokens); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setText(</span><span class="vars">$text</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$this</span><span>->_text = </span><span class="vars">$text</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> </span><span class="func">getText</span><span>() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_text; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setBadge(</span><span class="vars">$badge</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (!</span><span class="func">is_int</span><span>(</span><span class="vars">$badge</span><span>)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">"Invalid badge number '{$badge}'"</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$this</span><span>->_badge = </span><span class="vars">$badge</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getBadge() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_badge; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setSound(</span><span class="vars">$sound</span><span> = </span><span class="string">'default'</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$this</span><span>->_sound = </span><span class="vars">$sound</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getSound() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_sound; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setCP(</span><span class="vars">$name</span><span>, </span><span class="vars">$value</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="vars">$name</span><span> == self::APPLE_RESERVED_NAMESPACE) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> <span class="string">"Property name '"</span><span> . self::APPLE_RESERVED_NAMESPACE . </span><span class="string">"' can not be used for custom property."</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$this</span><span>->_customProperties[trim(</span><span class="vars">$name</span><span>)] = </span><span class="vars">$value</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> _getPayload() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$aPayload</span><span>[self::APPLE_RESERVED_NAMESPACE] = </span><span class="keyword">array</span><span>(); </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span> (isset(</span><span class="vars">$this</span><span>->_text)) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$aPayload</span><span>[self::APPLE_RESERVED_NAMESPACE][</span><span class="string">'alert'</span><span>] = (string)</span><span class="vars">$this</span><span>->_text; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">if</span><span> (isset(</span><span class="vars">$this</span><span>->_badge) && </span><span class="vars">$this</span><span>->_badge > 0) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$aPayload</span><span>[self::APPLE_RESERVED_NAMESPACE][</span><span class="string">'badge'</span><span>] = (int)</span><span class="vars">$this</span><span>->_badge; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">if</span><span> (isset(</span><span class="vars">$this</span><span>->_sound)) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$aPayload</span><span>[self::APPLE_RESERVED_NAMESPACE][</span><span class="string">'sound'</span><span>] = (string)</span><span class="vars">$this</span><span>->_sound; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="func">is_array</span><span>(</span><span class="vars">$this</span><span>->_customProperties)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">foreach</span><span>(</span><span class="vars">$this</span><span>->_customProperties </span><span class="keyword">as</span><span> </span><span class="vars">$propertyName</span><span> => </span><span class="vars">$propertyValue</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$aPayload</span><span>[</span><span class="vars">$propertyName</span><span>] = </span><span class="vars">$propertyValue</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$aPayload</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setExpiry(</span><span class="vars">$expiryValue</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (!</span><span class="func">is_int</span><span>(</span><span class="vars">$expiryValue</span><span>)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">"Invalid seconds number '{$expiryValue}'"</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$this</span><span>->_expiryValue = </span><span class="vars">$expiryValue</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getExpiry() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_expiryValue; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setCustomIdentifier(</span><span class="vars">$customIdentifier</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$this</span><span>->_customIdentifier = </span><span class="vars">$customIdentifier</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getCustomIdentifier() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_customIdentifier; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getPayload() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$sJSONPayload</span><span> = </span><span class="func">str_replace</span><span> </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> <span class="string">'"'</span><span> . self::APPLE_RESERVED_NAMESPACE . </span><span class="string">'":[]'</span><span>, </span></span></li><li class="alt"><span> <span class="string">'"'</span><span> . self::APPLE_RESERVED_NAMESPACE . </span><span class="string">'":{}'</span><span>, </span></span></li><li class=""><span> json_encode(<span class="vars">$this</span><span>->_getPayload()) </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> <span class="vars">$nJSONPayloadLen</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$sJSONPayload</span><span>); </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="vars">$nJSONPayloadLen</span><span> > self::PAYLOAD_MAXIMUM_SIZE) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="vars">$this</span><span>->_autoAdjustLongPayload) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$maxTextLen</span><span> = </span><span class="vars">$textLen</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$this</span><span>->_text) - (</span><span class="vars">$nJSONPayloadLen</span><span> - self::PAYLOAD_MAXIMUM_SIZE); </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="vars">$nMaxTextLen</span><span> > 0) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">while</span><span> (</span><span class="func">strlen</span><span>(</span><span class="vars">$this</span><span>->_text = mb_substr(</span><span class="vars">$this</span><span>->_text, 0, --</span><span class="vars">$textLen</span><span>, </span><span class="string">'UTF-8'</span><span>)) > </span><span class="vars">$maxTextLen</span><span>); </span></span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->getPayload(); </span></span></li><li class="alt"><span> }<span class="keyword">else</span><span> </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is "</span><span> . </span></span></li><li class=""><span> self::PAYLOAD_MAXIMUM_SIZE . <span class="string">" bytes. The message text can not be auto-adjusted."</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> }<span class="keyword">else</span><span> </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is "</span><span> . </span></span></li><li class=""><span> self::PAYLOAD_MAXIMUM_SIZE . <span class="string">" bytes"</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$sJSONPayload</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span>?> </span></li><li class="alt"><span><?php </span></li><li class=""><span>date_default_timezone_set(<span class="string">'PRC'</span><span>); </span></span></li><li class="alt"><span><span class="func">echo</span><span> </span><span class="string">"we are young,test apns. -"</span><span>.</span><span class="func">date</span><span>(</span><span class="string">'Y-m-d h:i:s'</span><span>,time()); </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="vars">$rootpath</span><span> = </span><span class="string">'entrust_root_certification_authority.pem'</span><span>; </span><span class="comment">//ROOT证书地址</span><span> </span></span></li><li class=""><span><span class="vars">$cp</span><span> = </span><span class="string">'ck.pem'</span><span>; </span><span class="comment">//provider证书地址</span><span> </span></span></li><li class="alt"><span><span class="vars">$apns</span><span> = </span><span class="keyword">new</span><span> APNS(1,</span><span class="vars">$cp</span><span>); </span></span></li><li class=""><span>try </span></li><li class="alt"><span>{ </span></li><li class=""><span> <span class="comment">//$apns->setRCA($rootpath); //设置ROOT证书</span><span> </span></span></li><li class="alt"><span> <span class="vars">$apns</span><span>->connect(); </span><span class="comment">//连接</span><span> </span></span></li><li class=""><span> <span class="vars">$apns</span><span>->addDT(</span><span class="string">'acc5150a4df26507a84f19ba145ca3c1be5842a6177511ce7c43d01badb1bd96'</span><span>); </span><span class="comment">//加入deviceToken</span><span> </span></span></li><li class="alt"><span> <span class="vars">$apns</span><span>->setText(</span><span class="string">'这是一条测试信息'</span><span>); </span><span class="comment">//发送内容</span><span> </span></span></li><li class=""><span> <span class="vars">$apns</span><span>->setBadge(1); </span><span class="comment">//设置图标数</span><span> </span></span></li><li class="alt"><span> <span class="vars">$apns</span><span>->setSound(); </span><span class="comment">//设置声音</span><span> </span></span></li><li class=""><span> <span class="vars">$apns</span><span>->setExpiry(3600); </span><span class="comment">//过期时间</span><span> </span></span></li><li class="alt"><span> <span class="vars">$apns</span><span>->setCP(</span><span class="string">'custom operation'</span><span>,</span><span class="keyword">array</span><span>(</span><span class="string">'type'</span><span> => </span><span class="string">'1'</span><span>,</span><span class="string">'url'</span><span> => </span><span class="string">'http://www.google.com.hk'</span><span>)); //自定义操作 </span></span></li><li class=""><span> <span class="vars">$apns</span><span>->send(); </span><span class="comment">//发送</span><span> </span></span></li><li class="alt"><span> <span class="func">echo</span><span> </span><span class="string">' sent ok'</span><span>; </span></span></li><li class=""><span>}catch(Exception <span class="vars">$e</span><span>) </span></span></li><li class="alt"><span>{ </span></li><li class=""><span> <span class="func">echo</span><span> </span><span class="vars">$e</span><span>; </span></span></li><li class="alt"><span>} </span></li><li class=""><span>?> </span></li><li class="alt"><span> </span></li><li class=""><span></body> </span></li><li class="alt"><span></html> </span></li></ol><div class="save_code tracking-ad" data-mod="popu_249"><a href="javascript:;" target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png"></a></div></div><pre code_snippet_id="481571" snippet_file_name="blog_20141010_4_193481" name="code" class="php" style="display: none;"><!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>APNS</title>
</head>
<body>
<?php
/**
* @file apns.php
* @synopsis apple APNS class
* @author Yee, <rlk002@gmail.com>
* @version 1.0
* @date 2012-09-17 11:27:59
*/
class APNS
{
const ENVIRONMENT_PRODUCTION = 0;
const ENVIRONMENT_SANDBOX = 1;
const DEVICE_BINARY_SIZE = 32;
const CONNECT_RETRY_INTERVAL = 1000000;
const SOCKET_SELECT_TIMEOUT = 1000000;
const COMMAND_PUSH = 1;
const STATUS_CODE_INTERNAL_ERROR = 999;
const ERROR_RESPONSE_SIZE = 6;
const ERROR_RESPONSE_COMMAND = 8;
const PAYLOAD_MAXIMUM_SIZE = 256;
const APPLE_RESERVED_NAMESPACE = 'aps';
protected $_environment;
protected $_providerCertificateFile;
protected $_rootCertificationAuthorityFile;
protected $_connectTimeout;
protected $_connectRetryTimes = 3;
protected $_connectRetryInterval;
protected $_socketSelectTimeout;
protected $_hSocket;
protected $_deviceTokens = array();
protected $_text;
protected $_badge;
protected $_sound;
protected $_customProperties;
protected $_expiryValue = 604800;
protected $_customIdentifier;
protected $_autoAdjustLongPayload = true;
protected $asurls = array('ssl://gateway.push.apple.com:2195','ssl://gateway.sandbox.push.apple.com:2195');
protected $_errorResponseMessages = array
(
0 => 'No errors encountered',
1 => 'Processing error',
2 => 'Missing device token',
3 => 'Missing topic',
4 => 'Missing payload',
5 => 'Invalid token size',
6 => 'Invalid topic size',
7 => 'Invalid payload size',
8 => 'Invalid token',
self::STATUS_CODE_INTERNAL_ERROR => 'Internal error'
);
function __construct($environment,$providerCertificateFile)
{
if($environment != self::ENVIRONMENT_PRODUCTION && $environment != self::ENVIRONMENT_SANDBOX)
{
throw new Exception(
"Invalid environment '{$environment}'"
);
}
$this->_environment = $environment;
if(!is_readable($providerCertificateFile))
{
throw new Exception(
"Unable to read certificate file '{$providerCertificateFile}'"
);
}
$this->_providerCertificateFile = $providerCertificateFile;
$this->_connectTimeout = @ini_get("default_socket_timeout");
$this->_connectRetryInterval = self::CONNECT_RETRY_INTERVAL;
$this->_socketSelectTimeout = self::SOCKET_SELECT_TIMEOUT;
}
public function setRCA($rootCertificationAuthorityFile)
{
if(!is_readable($rootCertificationAuthorityFile))
{
throw new Exception(
"Unable to read Certificate Authority file '{$rootCertificationAuthorityFile}'"
);
}
$this->_rootCertificationAuthorityFile = $rootCertificationAuthorityFile;
}
public function getRCA()
{
return $this->_rootCertificationAuthorityFile;
}
protected function _connect()
{
$sURL = $this->asurls[$this->_environment];
$streamContext = stream_context_create(
array
(
'ssl' => array
(
'verify_peer' => isset($this->_rootCertificationAuthorityFile),
'cafile' => $this->_rootCertificationAuthorityFile,
'local_cert' => $this->_providerCertificateFile
)
)
);
$this->_hSocket = @stream_socket_client($sURL,$nError,$sError,$this->_connectTimeout,STREAM_CLIENT_CONNECT, $streamContext);
if (!$this->_hSocket)
{
throw new Exception
(
"Unable to connect to '{$sURL}': {$sError} ({$nError})"
);
}
stream_set_blocking($this->_hSocket, 0);
stream_set_write_buffer($this->_hSocket, 0);
return true;
}
public function connect()
{
$bConnected = false;
$retry = 0;
while(!$bConnected)
{
try
{
$bConnected = $this->_connect();
}catch (Exception $e)
{
if ($nRetry >= $this->_connectRetryTimes)
{
throw $e;
}else
{
usleep($this->_nConnectRetryInterval);
}
}
$retry++;
}
}
public function disconnect()
{
if (is_resource($this->_hSocket))
{
return fclose($this->_hSocket);
}
return false;
}
protected function getBinaryNotification($deviceToken, $payload, $messageID = 0, $Expire = 604800)
{
$tokenLength = strlen($deviceToken);
$payloadLength = strlen($payload);
$ret = pack('CNNnH*', self::COMMAND_PUSH, $messageID, $Expire > 0 ? time() + $Expire : 0, self::DEVICE_BINARY_SIZE, $deviceToken);
$ret .= pack('n', $payloadLength);
$ret .= $payload;
return $ret;
}
protected function readErrorMessage()
{
$errorResponse = @fread($this->_hSocket, self::ERROR_RESPONSE_SIZE);
if ($errorResponse === false || strlen($errorResponse) != self::ERROR_RESPONSE_SIZE)
{
return;
}
$errorResponse = $this->parseErrorMessage($errorResponse);
if (!is_array($errorResponse) || empty($errorResponse))
{
return;
}
if (!isset($errorResponse['command'], $errorResponse['statusCode'], $errorResponse['identifier']))
{
return;
}
if ($errorResponse['command'] != self::ERROR_RESPONSE_COMMAND)
{
return;
}
$errorResponse['timeline'] = time();
$errorResponse['statusMessage'] = 'None (unknown)';
if (isset($this->_aErrorResponseMessages[$errorResponse['statusCode']]))
{
$errorResponse['statusMessage'] = $this->_errorResponseMessages[$errorResponse['statusCode']];
}
return $errorResponse;
}
protected function parseErrorMessage($errorMessage)
{
return unpack('Ccommand/CstatusCode/Nidentifier', $errorMessage);
}
public function send()
{
if (!$this->_hSocket)
{
throw new Exception
(
'Not connected to Push Notification Service'
);
}
$sendCount = $this->getDTNumber();
$messagePayload = $this->getPayload();
foreach($this->_deviceTokens AS $key => $value)
{
$apnsMessage = $this->getBinaryNotification($value, $messagePayload, $messageID = 0, $Expire = 604800);
$nLen = strlen($apnsMessage);
$aErrorMessage = null;
if ($nLen !== ($nWritten = (int)@fwrite($this->_hSocket, $apnsMessage)))
{
$aErrorMessage = array
(
'identifier' => $key,
'statusCode' => self::STATUS_CODE_INTERNAL_ERROR,
'statusMessage' => sprintf('%s (%d bytes written instead of %d bytes)',$this->_errorResponseMessages[self::STATUS_CODE_INTERNAL_ERROR], $nWritten, $nLen)
);
}
}
}
public function addDT($deviceToken)
{
if (!preg_match('~^[a-f0-9]{64}$~i', $deviceToken))
{
throw new Exception
(
"Invalid device token '{$deviceToken}'"
);
}
$this->_deviceTokens[] = $deviceToken;
}
public function getDTNumber()
{
return count($this->_deviceTokens);
}
public function setText($text)
{
$this->_text = $text;
}
public function getText()
{
return $this->_text;
}
public function setBadge($badge)
{
if (!is_int($badge))
{
throw new Exception
(
"Invalid badge number '{$badge}'"
);
}
$this->_badge = $badge;
}
public function getBadge()
{
return $this->_badge;
}
public function setSound($sound = 'default')
{
$this->_sound = $sound;
}
public function getSound()
{
return $this->_sound;
}
public function setCP($name, $value)
{
if ($name == self::APPLE_RESERVED_NAMESPACE)
{
throw new Exception
(
"Property name '" . self::APPLE_RESERVED_NAMESPACE . "' can not be used for custom property."
);
}
$this->_customProperties[trim($name)] = $value;
}
protected function _getPayload()
{
$aPayload[self::APPLE_RESERVED_NAMESPACE] = array();
if (isset($this->_text))
{
$aPayload[self::APPLE_RESERVED_NAMESPACE]['alert'] = (string)$this->_text;
}
if (isset($this->_badge) && $this->_badge > 0)
{
$aPayload[self::APPLE_RESERVED_NAMESPACE]['badge'] = (int)$this->_badge;
}
if (isset($this->_sound))
{
$aPayload[self::APPLE_RESERVED_NAMESPACE]['sound'] = (string)$this->_sound;
}
if (is_array($this->_customProperties))
{
foreach($this->_customProperties as $propertyName => $propertyValue)
{
$aPayload[$propertyName] = $propertyValue;
}
}
return $aPayload;
}
public function setExpiry($expiryValue)
{
if (!is_int($expiryValue))
{
throw new Exception
(
"Invalid seconds number '{$expiryValue}'"
);
}
$this->_expiryValue = $expiryValue;
}
public function getExpiry()
{
return $this->_expiryValue;
}
public function setCustomIdentifier($customIdentifier)
{
$this->_customIdentifier = $customIdentifier;
}
public function getCustomIdentifier()
{
return $this->_customIdentifier;
}
public function getPayload()
{
$sJSONPayload = str_replace
(
'"' . self::APPLE_RESERVED_NAMESPACE . '":[]',
'"' . self::APPLE_RESERVED_NAMESPACE . '":{}',
json_encode($this->_getPayload())
);
$nJSONPayloadLen = strlen($sJSONPayload);
if ($nJSONPayloadLen > self::PAYLOAD_MAXIMUM_SIZE)
{
if ($this->_autoAdjustLongPayload)
{
$maxTextLen = $textLen = strlen($this->_text) - ($nJSONPayloadLen - self::PAYLOAD_MAXIMUM_SIZE);
if ($nMaxTextLen > 0)
{
while (strlen($this->_text = mb_substr($this->_text, 0, --$textLen, 'UTF-8')) > $maxTextLen);
return $this->getPayload();
}else
{
throw new Exception
(
"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .
self::PAYLOAD_MAXIMUM_SIZE . " bytes. The message text can not be auto-adjusted."
);
}
}else
{
throw new Exception
(
"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .
self::PAYLOAD_MAXIMUM_SIZE . " bytes"
);
}
}
return $sJSONPayload;
}
}
?>
<?php
date_default_timezone_set('PRC');
echo "we are young,test apns. -".date('Y-m-d h:i:s',time());
$rootpath = 'entrust_root_certification_authority.pem'; //ROOT证书地址
$cp = 'ck.pem'; //provider证书地址
$apns = new APNS(1,$cp);
try
{
//$apns->setRCA($rootpath); //设置ROOT证书
$apns->connect(); //连接
$apns->addDT('acc5150a4df26507a84f19ba145ca3c1be5842a6177511ce7c43d01badb1bd96'); //加入deviceToken
$apns->setText('这是一条测试信息'); //发送内容
$apns->setBadge(1); //设置图标数
$apns->setSound(); //设置声音
$apns->setExpiry(3600); //过期时间
$apns->setCP('custom operation',array('type' => '1','url' => 'http://www.google.com.hk')); //自定义操作
$apns->send(); //发送
echo ' sent ok';
}catch(Exception $e)
{
echo $e;
}
?>
</body>
</html></pre>
<p></p>
<p><br>
</p>
<h3><a name="t13"></a>2,启动 Apache </h3>
mac 自带apache,可直接运行php。
<p></p>
<p>打开“终端(terminal)”,输入 sudo apachectl -v,可显示Apache的版本;</p>
<p>输入 sudo apachectl start,这样Apache就启动了。</p>
<p>编辑文件 /etc/apache2/httpd.conf , 把 LoadModule php5_module libexec/apache2/libphp5.so 前面的注释去掉;然后重启apache: sudo apachectl restart</p>
<p>打开Safari浏览器地址栏输入 “http://localhost”,可以看到内容为“It works!”的页面。其位</p>
<p>于“/Library/WebServer/Documents/”下,这就是Apache的默认根目录。<br>
</p>
<h3><a name="t14"></a>3,如何调试</h3>
<div>将服务器端写好的apns.php 文件以及生成的 ck.pem 文件,直接拷贝到 /Library/WebServer/Documents/ 下,在浏览器中,直接浏览: http://localhost/apns.php 。这样消息就发送到了苹果服务器。</div>
<div><img src="http://img.blog.csdn.net/20151209163146784?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
</div>
<h2><a name="t0"></a>一、背景概述:<span style="white-space:pre"> </span></h2>
<h3><a name="t1"></a>1,环境配置</h3>
<p>APNS:Apple Push Notification Service。本文对推送相关概念不再赘述,只侧重完整流程。 </p>
<p>Demo 开发环境:Mac os 10.9.4 ,Xcode 6.0.1 ;<a href="http://lib.csdn.net/base/softwaretest" class="replace_word" title="软件测试知识库" target="_blank" style="color:#df3434; font-weight:bold;">测试</a>设备:iphone 4s(<a href="http://lib.csdn.net/base/ios" class="replace_word" title="iOS知识库" target="_blank" style="color:#df3434; font-weight:bold;">iOS</a> 7.1)</p>
<p>服务端开发环境:mac 10.9.4 + <a href="http://lib.csdn.net/base/php" class="replace_word" title="PHP知识库" target="_blank" style="color:#df3434; font-weight:bold;">PHP</a> 5.4.24、</p>
<p>Demo 下载地址:<a target="_blank" href="http://download.csdn.net/detail/jiajiayouba/8019667">点击打开链接</a></p>
<h3><a name="t2"></a>2,APNS 相关博客</h3>
<p>如对apns相关概念不清楚,可参考以下几个博客:(博客中部分内容重复,但总体来说,通读一遍,还是大有裨益的)</p>
<p> http://cshbbrain.iteye.com/blog/1859810 =》IOS 基于APNS消息推送原理与实现(<a href="http://lib.csdn.net/base/javaee" class="replace_word" title="Java EE知识库" target="_blank" style="color:#df3434; font-weight:bold;">Java</a>后台)</p>
<p>http://www.cnblogs.com/qq78292959/archive/2012/07/16/2593651.html =》iOS消息推送机制的实现<br>
</p>
<p>http://blog.csdn<a href="http://lib.csdn.net/base/dotnet" class="replace_word" title=".NET知识库" target="_blank" style="color:#df3434; font-weight:bold;">.NET</a>/xunyn/article/details/8243573 =》APNS编程----iOS真机测试消息推送<br>
</p>
<p>http://blog.csdn<a href="http://lib.csdn.net/base/dotnet" class="replace_word" title=".NET知识库" target="_blank" style="color:#df3434; font-weight:bold;">.Net</a>/wswqiang/article/details/8208581 =》IOS APNS 处理<br>
</p>
<p>http://eric-gao.iteye.com/blog/1567777 =》 IOS PEM 文件的生成</p>
<p>http://www.36coder.com/study/996.html =》PHP 实现APNS 推送<br>
</p>
<p></p>
<p><span style="color:#ff6666">http://blog.csdn.net/sxfcct/article/details/7939082 =》 APNS 相关总结</span><span style="color:#ff0000"></span>(推荐)</p>
<h3><a name="t3"></a>3,APNS 接口</h3>
<p><span style="color:#ff9900">消息推送:</span></p>
<p></p>
<p>开发接口:gateway.sandbox.push.apple.com:2195</p>
<p></p>
<p>发布接口:gateway.push.apple.com:2195</p>
<p><span style="color:#ff9966">反馈服务:</span></p>
<p>开发接口:feedback.sandbox.push.apple.com:2196</p>
<p>发布接口:产品接口:feedback.push.apple.com:2196</p>
<p style="margin-top:0px; margin-bottom:16px; color:rgb(68,68,68); font-family:'Microsoft Yahei','Helvetica Neue',Helvetica,Arial,sans-serif; font-size:15px; line-height:25px">
<span style="font-family:Arial,Helvetica,sans-serif; font-size:12px">二、制作Push证书和Pem文件</span></p>
<h3><a name="t4"></a>1,新建一个App ID</h3>
<div>新建流程不再赘述,这里只提醒两点:1》App ID Suffix 中,一定要选择Explicit App ID;2》App Services 中,记得勾选Push Notifications。这里以新建一个id为:com.eversoft.PushDemo 为例。</div>
<h3><a name="t5"></a>2,配置push开发证书</h3>
<div>在App IDs中,选中刚才新建的App id:com.eversoft.PushDemo ,单击,展开详细信息属性。</div>
<div><img src="http://img.blog.csdn.net/20141009135115859?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
<div>在详细信息属性中,单击下方的“Edit”按钮,<img src="http://img.blog.csdn.net/20141009135553281?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></div>
<div>在新打开的编辑界面,单击“Create Certificate”,</div>
<div><img src="http://img.blog.csdn.net/20141009140028786?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
<div>在新打开的界面中,会提示我们,创建一个csr 证书签名请求文件。具体的创建步骤,界面中已经给出了详细的英文说明。</div>
<div><img src="http://img.blog.csdn.net/20141009140333334?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
<div>在进行下一步之前,我们先按照英文说明,创建一个 CSR 文件。</div>
<div>
<ul>
<li>在mac电脑上,打开应用程序 keychain(钥匙串访问);</li><li>在keychain菜单栏中,依次选择“钥匙串访问”=》“证书助理”=》“从证书颁发机构请求证书”;<img src="http://img.blog.csdn.net/20141009140849749?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></li><li>在新打开的“证书助理”界面中,填写用户电子邮件地址,常用名称,CA电子邮件地址,这两个邮件地址直接填写你的苹果账号的邮件地址即可,然后选择“存储到磁盘”,然后点击“继续”;<img src="http://img.blog.csdn.net/20141009141351843?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></li><li>选择CSR文件保存位置,“存储”即可。至此, CSR 文件,制作完成。</li></ul>
<br>
</div>
<div>回到刚才我们的web页面上,点击“Continue”,进入下一页面;新的页面中,会要求我们上传刚才制作的csr文件,选择“Choose File”,找到我们刚才存储的csr文件,单击“打开”,最后,点击页面上的“Generate”按钮,到此,开发使用的push证书制作完毕。<img src="http://img.blog.csdn.net/20141009142241621?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></div>
<div>证书生成成功后,选择“Download”,将制作好的证书下载到本地。然后双击下载的证书aps_development.cer,双击后,证书就自动导入到钥匙串中了。</div>
<div><br>
</div>
<div>打开 keychain,左侧钥匙串选择“登录”,种类选择“所有项目”,在右侧窗口中,选中刚才导入的Apple Development IOS Push Services证书(不用选中专用密钥),右键,选择导出,命名为:ck.p12 ,存储时,会提示输入保护密码,这里为演示方便,就输入了123456。之后又会要求输入电脑登录密码,输入即可。</div>
<div><img src="http://img.blog.csdn.net/20141009145405000?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
<h3><a name="t6"></a>3,生成PEM文件</h3>
<div>最后,打开终端,执行以下命令,生成pem文件</div>
<div></div>
<p>openssl pkcs12 -in ck.p12 -out ck.pem -nodes </p>
<p>执行时,会要求输入导入密码,这里输入刚才的保护密码123456即可。</p>
<p><img src="http://img.blog.csdn.net/20141009145927262?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhamlheW91YmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</p>
<p>到此,php 服务端使用的pem证书就制作完毕了。</p>
<p>Development PP 文件制作不再赘述。</p>
<h2><a name="t7"></a>三、IOS 代码编写</h2>
<p>首先,在AppDelegate.m 中:</p>
<h3><a name="t8"></a>1,注册通知</h3>
<p></p>
<div class="dp-highlighter bg_objc"><div class="bar"><div class="tools"><b>[objc]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 423px; top: 5195px; width: 22px; height: 11px; z-index: 99;"><embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="22" height="11" name="ZeroClipboardMovie_1" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=1&width=22&height=11" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><span class="tracking-ad" data-mod="popu_167"><a href="https://code.csdn.net/snippets/481571" target="_blank" title="在CODE上查看代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/CODE_ico.png" width="12" height="12" alt="在CODE上查看代码片" style="position:relative;top:1px;left:2px;"></a></span><span class="tracking-ad" data-mod="popu_170"><a href="https://code.csdn.net/snippets/481571/fork" target="_blank" title="派生到我的代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/ico_fork.svg" width="12" height="12" alt="派生到我的代码片" style="position:relative;top:2px;left:2px;"></a></span></div></div><ol start="1" class="dp-objc"><li class="alt"><span><span>- (</span><span class="keyword">BOOL</span><span>)application:(</span><span class="keyword">UIApplication</span><span> *)application</span><span class="vars"> didFinishLaunchingWithOptions</span><span>:(</span><span class="keyword">NSDictionary</span><span> *)launchOptions { </span></span></li><li class=""><span> <span class="comment">// Override point for customization after application launch.</span><span> </span></span></li><li class="alt"><span> <span class="keyword">ViewController</span><span> *mainCtrl=[[ViewController</span><span class="vars"> alloc</span><span>]</span><span class="vars"> init</span><span>]; </span></span></li><li class=""><span> <span class="keyword">self</span><span class="xcodeconstants">.window</span><span class="xcodeconstants">.rootViewController</span><span>=mainCtrl; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="comment">//注册通知</span><span> </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> ([UIDevice</span><span class="vars"> currentDevice</span><span>]</span><span class="xcodeconstants">.systemVersion</span><span class="xcodeconstants">.doubleValue</span><span><</span><span class="xcodenumber">8</span><span class="xcodeconstants">.0</span><span>) { </span></span></li><li class=""><span> [[UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="vars"> registerForRemoteNotificationTypes</span><span>:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)]; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">else</span><span> { </span></span></li><li class="alt"><span> [[UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="vars"> registerForRemoteNotifications</span><span>]; </span></span></li><li class=""><span> [[UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="vars"> registerUserNotificationSettings</span><span>:[UIUserNotificationSettings</span><span class="vars"> settingsForTypes</span><span>:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert</span><span class="vars"> categories</span><span class="keyword">:nil</span><span>]]; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">//判断是否由远程消息通知触发应用程序启动</span><span> </span></span></li><li class=""><span> <span class="keyword">if</span><span> (launchOptions) { </span></span></li><li class="alt"><span> <span class="comment">//获取应用程序消息通知标记数(即小红圈中的数字)</span><span> </span></span></li><li class=""><span> NSInteger badge = [UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="xcodeconstants">.applicationIconBadgeNumber</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (badge></span><span class="xcodenumber">0</span><span>) { </span></span></li><li class=""><span> <span class="comment">//如果应用程序消息通知标记数(即小红圈中的数字)大于0,清除标记。</span><span> </span></span></li><li class="alt"><span> badge--; </span></li><li class=""><span> <span class="comment">//清除标记。清除小红圈中数字,小红圈中数字为0,小红圈才会消除。</span><span> </span></span></li><li class="alt"><span> [UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="xcodeconstants">.applicationIconBadgeNumber</span><span> = badge; </span></span></li><li class=""><span> <span class="keyword">NSDictionary</span><span> *pushInfo = [launchOptions</span><span class="vars"> objectForKey</span><span>:</span><span class="string">@"UIApplicationLaunchOptionsRemoteNotificationKey"</span><span>]; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="comment">//获取推送详情</span><span> </span></span></li><li class="alt"><span> <span class="keyword">NSString</span><span> *pushString = [NSString</span><span class="vars"> stringWithFormat</span><span>:</span><span class="string">@"%@"</span><span>,[pushInfo </span><span class="vars"> objectForKey</span><span>:</span><span class="string">@"aps"</span><span>]]; </span></span></li><li class=""><span> <span class="keyword">UIAlertView</span><span> *alert=[[UIAlertView</span><span class="vars"> alloc</span><span>]</span><span class="vars"> initWithTitle</span><span>:</span><span class="string">@"finish Loaunch"</span><span class="vars"> message</span><span>:pushString</span><span class="vars"> delegate</span><span class="keyword">:nil</span><span class="vars"> cancelButtonTitle</span><span>:</span><span class="string">@"cancel"</span><span class="vars"> otherButtonTitles</span><span class="keyword">:nil</span><span>,</span><span class="keyword"> nil</span><span class="vars"> nil</span><span>]; </span></span></li><li class="alt"><span> [alert<span class="vars"> show</span><span>]; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">YES</span><span>; </span></span></li><li class=""><span>} </span></li></ol><div class="save_code tracking-ad" data-mod="popu_249" style="display: none;"><a href="javascript:;" target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png"></a></div></div><pre code_snippet_id="481571" snippet_file_name="blog_20141010_1_1959414" name="code" class="objc" style="display: none;">- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
ViewController *mainCtrl=[[ViewController alloc] init];
self.window.rootViewController=mainCtrl;
//注册通知
if ([UIDevice currentDevice].systemVersion.doubleValue<8.0) {
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];
}
else {
[[UIApplication sharedApplication] registerForRemoteNotifications];
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil]];
}
//判断是否由远程消息通知触发应用程序启动
if (launchOptions) {
//获取应用程序消息通知标记数(即小红圈中的数字)
NSInteger badge = [UIApplication sharedApplication].applicationIconBadgeNumber;
if (badge>0) {
//如果应用程序消息通知标记数(即小红圈中的数字)大于0,清除标记。
badge--;
//清除标记。清除小红圈中数字,小红圈中数字为0,小红圈才会消除。
[UIApplication sharedApplication].applicationIconBadgeNumber = badge;
NSDictionary *pushInfo = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
//获取推送详情
NSString *pushString = [NSString stringWithFormat:@"%@",[pushInfo objectForKey:@"aps"]];
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"finish Loaunch" message:pushString delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil];
[alert show];
}
}
return YES;
}</pre><br>
<p></p>
<h3><a name="t9"></a>2,注册通知后,获取device token</h3>
<p></p>
<p></p>
<div class="dp-highlighter bg_objc"><div class="bar"><div class="tools"><b>[objc]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 423px; top: 5978px; width: 22px; height: 11px; z-index: 99;"><embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="22" height="11" name="ZeroClipboardMovie_2" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=2&width=22&height=11" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><span class="tracking-ad" data-mod="popu_167"><a href="https://code.csdn.net/snippets/481571" target="_blank" title="在CODE上查看代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/CODE_ico.png" width="12" height="12" alt="在CODE上查看代码片" style="position:relative;top:1px;left:2px;"></a></span><span class="tracking-ad" data-mod="popu_170"><a href="https://code.csdn.net/snippets/481571/fork" target="_blank" title="派生到我的代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/ico_fork.svg" width="12" height="12" alt="派生到我的代码片" style="position:relative;top:2px;left:2px;"></a></span></div></div><ol start="1" class="dp-objc"><li class="alt"><span><span>- (</span><span class="keyword">void</span><span>)application:(</span><span class="keyword">UIApplication</span><span> *)app</span><span class="vars"> didRegisterForRemoteNotificationsWithDeviceToken</span><span>:(</span><span class="keyword">NSData</span><span> *)deviceToken { </span></span></li><li class=""><span> <span class="keyword">NSString</span><span> *token = [NSString</span><span class="vars"> stringWithFormat</span><span>:</span><span class="string">@"%@"</span><span>,</span><span class="vars"> deviceToken</span><span>]; </span></span></li><li class="alt"><span> NSLog(<span class="string">@"My token is:%@"</span><span>, token); </span></span></li><li class=""><span> <span class="comment">//这里应将device token发送到服务器端</span><span> </span></span></li><li class="alt"><span>} </span></li><li class=""><span> </span></li><li class="alt"><span>- (<span class="keyword">void</span><span>)application:(</span><span class="keyword">UIApplication</span><span> *)app</span><span class="vars"> didFailToRegisterForRemoteNotificationsWithError</span><span>:(</span><span class="keyword">NSError</span><span> *)error { </span></span></li><li class=""><span> <span class="keyword">NSString</span><span> *error_str = [NSString</span><span class="vars"> stringWithFormat</span><span>: </span><span class="string">@"%@"</span><span>,</span><span class="vars"> error</span><span>]; </span></span></li><li class="alt"><span> NSLog(<span class="string">@"Failed to get token, error:%@"</span><span>, error_str); </span></span></li><li class=""><span>} </span></li></ol><div class="save_code tracking-ad" data-mod="popu_249"><a href="javascript:;" target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png"></a></div></div><pre code_snippet_id="481571" snippet_file_name="blog_20141010_2_1720217" name="code" class="objc" style="display: none;">- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [NSString stringWithFormat:@"%@", deviceToken];
NSLog(@"My token is:%@", token);
//这里应将device token发送到服务器端
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSString *error_str = [NSString stringWithFormat: @"%@", error];
NSLog(@"Failed to get token, error:%@", error_str);
}</pre><br>
<p></p>
<h3><a name="t10"></a>3,接收推送通知</h3>
<p></p>
<p></p>
<div class="dp-highlighter bg_objc"><div class="bar"><div class="tools"><b>[objc]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 423px; top: 6275px; width: 22px; height: 11px; z-index: 99;"><embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="22" height="11" name="ZeroClipboardMovie_3" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=3&width=22&height=11" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><span class="tracking-ad" data-mod="popu_167"><a href="https://code.csdn.net/snippets/481571" target="_blank" title="在CODE上查看代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/CODE_ico.png" width="12" height="12" alt="在CODE上查看代码片" style="position:relative;top:1px;left:2px;"></a></span><span class="tracking-ad" data-mod="popu_170"><a href="https://code.csdn.net/snippets/481571/fork" target="_blank" title="派生到我的代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/ico_fork.svg" width="12" height="12" alt="派生到我的代码片" style="position:relative;top:2px;left:2px;"></a></span></div></div><ol start="1" class="dp-objc"><li class="alt"><span><span>- (</span><span class="keyword">void</span><span>)application:(</span><span class="keyword">UIApplication</span><span> *)application</span><span class="vars"> didReceiveRemoteNotification</span><span>:(</span><span class="keyword">NSDictionary</span><span> *)userInfo </span></span></li><li class=""><span>{ </span></li><li class="alt"><span> [UIApplication<span class="vars"> sharedApplication</span><span>]</span><span class="xcodeconstants">.applicationIconBadgeNumber</span><span>=</span><span class="xcodenumber">0</span><span>; </span></span></li><li class=""><span> <span class="keyword">for</span><span> (</span><span class="keyword">id</span><span> key in userInfo) { </span></span></li><li class="alt"><span> NSLog(<span class="string">@"key: %@, value: %@"</span><span>, key, [userInfo</span><span class="vars"> objectForKey</span><span>:key]); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="comment">/* eg.</span> </span></li><li class=""><span><span class="comment"> key: aps, value: {</span> </span></li><li class="alt"><span><span class="comment"> alert = "\U8fd9\U662f\U4e00\U6761\U6d4b\U8bd5\U4fe1\U606f";</span> </span></li><li class=""><span><span class="comment"> badge = 1;</span> </span></li><li class="alt"><span><span class="comment"> sound = default;</span> </span></li><li class=""><span><span class="comment"> }</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li class=""><span> <span class="keyword">UIAlertView</span><span> *alert=[[UIAlertView</span><span class="vars"> alloc</span><span>]</span><span class="vars"> initWithTitle</span><span>:</span><span class="string">@"remote notification"</span><span class="vars"> message</span><span>:userInfo[</span><span class="string">@"aps"</span><span>][</span><span class="string">@"alert"</span><span>]</span><span class="vars"> delegate</span><span class="keyword">:nil</span><span class="vars"> cancelButtonTitle</span><span>:</span><span class="string">@"cancel"</span><span class="vars"> otherButtonTitles</span><span class="keyword">:nil</span><span>,</span><span class="keyword"> nil</span><span class="vars"> nil</span><span>]; </span></span></li><li class="alt"><span> [alert<span class="vars"> show</span><span>]; </span></span></li><li class=""><span>} </span></li></ol><div class="save_code tracking-ad" data-mod="popu_249" style="display: none;"><a href="javascript:;" target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png"></a></div></div><pre code_snippet_id="481571" snippet_file_name="blog_20141010_3_1480237" name="code" class="objc" style="display: none;">- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[UIApplication sharedApplication].applicationIconBadgeNumber=0;
for (id key in userInfo) {
NSLog(@"key: %@, value: %@", key, [userInfo objectForKey:key]);
}
/* eg.
key: aps, value: {
alert = "\U8fd9\U662f\U4e00\U6761\U6d4b\U8bd5\U4fe1\U606f";
badge = 1;
sound = default;
}
*/
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"remote notification" message:userInfo[@"aps"][@"alert"] delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil];
[alert show];
}</pre><br>
注意:app 前台运行时,会调用 remote notification;app后台运行时,点击提醒框,会调用remote notification,点击app 图标,不调用remote notification,没反应;app 没有运行时,点击提醒框,finishLaunching 中,launchOptions 传参,点击app 图标,launchOptions 不传参,不调用remote notification。
<p></p>
<h2><a name="t11"></a>四、服务器端代码编写</h2>
<div>此章不在IOS程序员职责范围之内,故只给出示例代码,不做深入讨论。</div>
<h3><a name="t12"></a>1,php 源码:</h3>
<p></p>
<div class="dp-highlighter bg_php"><div class="bar"><div class="tools"><b>[php]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 420px; top: 6828px; width: 22px; height: 11px; z-index: 99;"><embed id="ZeroClipboardMovie_4" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="22" height="11" name="ZeroClipboardMovie_4" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=4&width=22&height=11" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><span class="tracking-ad" data-mod="popu_167"><a href="https://code.csdn.net/snippets/481571" target="_blank" title="在CODE上查看代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/CODE_ico.png" width="12" height="12" alt="在CODE上查看代码片" style="position:relative;top:1px;left:2px;"></a></span><span class="tracking-ad" data-mod="popu_170"><a href="https://code.csdn.net/snippets/481571/fork" target="_blank" title="派生到我的代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/ico_fork.svg" width="12" height="12" alt="派生到我的代码片" style="position:relative;top:2px;left:2px;"></a></span></div></div><ol start="1" class="dp-c"><li class="alt"><span><span><!DOCTYPE html> </span></span></li><li class=""><span><html> </span></li><li class="alt"><span><head> </span></li><li class=""><span><meta http-equiv=<span class="string">"content-type"</span><span> content=</span><span class="string">"text/html;charset=utf-8"</span><span>> </span></span></li><li class="alt"><span><title>APNS</title> </span></li><li class=""><span></head> </span></li><li class="alt"><span><body> </span></li><li class=""><span><?php </span></li><li class="alt"><span><span class="comment">/**</span> </span></li><li class=""><span><span class="comment">* @file apns.php</span> </span></li><li class="alt"><span><span class="comment">* @synopsis apple APNS class</span> </span></li><li class=""><span><span class="comment">* @author Yee, <rlk002@gmail.com></span> </span></li><li class="alt"><span><span class="comment">* @version 1.0</span> </span></li><li class=""><span><span class="comment">* @date 2012-09-17 11:27:59</span> </span></li><li class="alt"><span><span class="comment">*/</span><span> </span></span></li><li class=""><span> <span class="keyword">class</span><span> APNS </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">const</span><span> ENVIRONMENT_PRODUCTION = 0; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> ENVIRONMENT_SANDBOX = 1; </span></span></li><li class=""><span> <span class="keyword">const</span><span> DEVICE_BINARY_SIZE = 32; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> CONNECT_RETRY_INTERVAL = 1000000; </span></span></li><li class=""><span> <span class="keyword">const</span><span> SOCKET_SELECT_TIMEOUT = 1000000; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> COMMAND_PUSH = 1; </span></span></li><li class=""><span> <span class="keyword">const</span><span> STATUS_CODE_INTERNAL_ERROR = 999; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> ERROR_RESPONSE_SIZE = 6; </span></span></li><li class=""><span> <span class="keyword">const</span><span> ERROR_RESPONSE_COMMAND = 8; </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> PAYLOAD_MAXIMUM_SIZE = 256; </span></span></li><li class=""><span> <span class="keyword">const</span><span> APPLE_RESERVED_NAMESPACE = </span><span class="string">'aps'</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_environment</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_providerCertificateFile</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_rootCertificationAuthorityFile</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_connectTimeout</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_connectRetryTimes</span><span> = 3; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_connectRetryInterval</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_socketSelectTimeout</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_hSocket</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_deviceTokens</span><span> = </span><span class="keyword">array</span><span>(); </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_text</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_badge</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_sound</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_customProperties</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_expiryValue</span><span> = 604800; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$_customIdentifier</span><span>; </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_autoAdjustLongPayload</span><span> = true; </span></span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="vars">$asurls</span><span> = </span><span class="keyword">array</span><span>(</span><span class="string">'ssl://gateway.push.apple.com:2195'</span><span>,</span><span class="string">'ssl://gateway.sandbox.push.apple.com:2195'</span><span>); </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="vars">$_errorResponseMessages</span><span> = </span><span class="keyword">array</span><span> </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> 0 => <span class="string">'No errors encountered'</span><span>, </span></span></li><li class="alt"><span> 1 => <span class="string">'Processing error'</span><span>, </span></span></li><li class=""><span> 2 => <span class="string">'Missing device token'</span><span>, </span></span></li><li class="alt"><span> 3 => <span class="string">'Missing topic'</span><span>, </span></span></li><li class=""><span> 4 => <span class="string">'Missing payload'</span><span>, </span></span></li><li class="alt"><span> 5 => <span class="string">'Invalid token size'</span><span>, </span></span></li><li class=""><span> 6 => <span class="string">'Invalid topic size'</span><span>, </span></span></li><li class="alt"><span> 7 => <span class="string">'Invalid payload size'</span><span>, </span></span></li><li class=""><span> 8 => <span class="string">'Invalid token'</span><span>, </span></span></li><li class="alt"><span> self::STATUS_CODE_INTERNAL_ERROR => <span class="string">'Internal error'</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">function</span><span> __construct(</span><span class="vars">$environment</span><span>,</span><span class="vars">$providerCertificateFile</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">if</span><span>(</span><span class="vars">$environment</span><span> != self::ENVIRONMENT_PRODUCTION && </span><span class="vars">$environment</span><span> != self::ENVIRONMENT_SANDBOX) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception( </span></span></li><li class="alt"><span> <span class="string">"Invalid environment '{$environment}'"</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$this</span><span>->_environment = </span><span class="vars">$environment</span><span>; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span>(!</span><span class="func">is_readable</span><span>(</span><span class="vars">$providerCertificateFile</span><span>)) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception( </span></span></li><li class="alt"><span> <span class="string">"Unable to read certificate file '{$providerCertificateFile}'"</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$this</span><span>->_providerCertificateFile = </span><span class="vars">$providerCertificateFile</span><span>; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="vars">$this</span><span>->_connectTimeout = @</span><span class="func">ini_get</span><span>(</span><span class="string">"default_socket_timeout"</span><span>); </span></span></li><li class="alt"><span> <span class="vars">$this</span><span>->_connectRetryInterval = self::CONNECT_RETRY_INTERVAL; </span></span></li><li class=""><span> <span class="vars">$this</span><span>->_socketSelectTimeout = self::SOCKET_SELECT_TIMEOUT; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setRCA(</span><span class="vars">$rootCertificationAuthorityFile</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span>(!</span><span class="func">is_readable</span><span>(</span><span class="vars">$rootCertificationAuthorityFile</span><span>)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception( </span></span></li><li class=""><span> <span class="string">"Unable to read Certificate Authority file '{$rootCertificationAuthorityFile}'"</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$this</span><span>->_rootCertificationAuthorityFile = </span><span class="vars">$rootCertificationAuthorityFile</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getRCA() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_rootCertificationAuthorityFile; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> _connect() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$sURL</span><span> = </span><span class="vars">$this</span><span>->asurls[</span><span class="vars">$this</span><span>->_environment]; </span></span></li><li class=""><span> <span class="vars">$streamContext</span><span> = stream_context_create( </span></span></li><li class="alt"><span> <span class="keyword">array</span><span> </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">'ssl'</span><span> => </span><span class="keyword">array</span><span> </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">'verify_peer'</span><span> => isset(</span><span class="vars">$this</span><span>->_rootCertificationAuthorityFile), </span></span></li><li class=""><span> <span class="string">'cafile'</span><span> => </span><span class="vars">$this</span><span>->_rootCertificationAuthorityFile, </span></span></li><li class="alt"><span> <span class="string">'local_cert'</span><span> => </span><span class="vars">$this</span><span>->_providerCertificateFile </span></span></li><li class=""><span> ) </span></li><li class="alt"><span> ) </span></li><li class=""><span> ); </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="vars">$this</span><span>->_hSocket = @stream_socket_client(</span><span class="vars">$sURL</span><span>,</span><span class="vars">$nError</span><span>,</span><span class="vars">$sError</span><span>,</span><span class="vars">$this</span><span>->_connectTimeout,STREAM_CLIENT_CONNECT, </span><span class="vars">$streamContext</span><span>); </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span> (!</span><span class="vars">$this</span><span>->_hSocket) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> <span class="string">"Unable to connect to '{$sURL}': {$sError} ({$nError})"</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> stream_set_blocking(<span class="vars">$this</span><span>->_hSocket, 0); </span></span></li><li class=""><span> stream_set_write_buffer(<span class="vars">$this</span><span>->_hSocket, 0); </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> true; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> connect() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$bConnected</span><span> = false; </span></span></li><li class="alt"><span> <span class="vars">$retry</span><span> = 0; </span></span></li><li class=""><span> <span class="keyword">while</span><span>(!</span><span class="vars">$bConnected</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> try </span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$bConnected</span><span> = </span><span class="vars">$this</span><span>->_connect(); </span></span></li><li class="alt"><span> }catch (Exception <span class="vars">$e</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="vars">$nRetry</span><span> >= </span><span class="vars">$this</span><span>->_connectRetryTimes) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="vars">$e</span><span>; </span></span></li><li class=""><span> }<span class="keyword">else</span><span> </span></span></li><li class="alt"><span> { </span></li><li class=""><span> usleep(<span class="vars">$this</span><span>->_nConnectRetryInterval); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$retry</span><span>++; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> disconnect() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="func">is_resource</span><span>(</span><span class="vars">$this</span><span>->_hSocket)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> fclose(</span><span class="vars">$this</span><span>->_hSocket); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">return</span><span> false; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> getBinaryNotification(</span><span class="vars">$deviceToken</span><span>, </span><span class="vars">$payload</span><span>, </span><span class="vars">$messageID</span><span> = 0, </span><span class="vars">$Expire</span><span> = 604800) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$tokenLength</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$deviceToken</span><span>); </span></span></li><li class="alt"><span> <span class="vars">$payloadLength</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$payload</span><span>); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="vars">$ret</span><span> = pack(</span><span class="string">'CNNnH*'</span><span>, self::COMMAND_PUSH, </span><span class="vars">$messageID</span><span>, </span><span class="vars">$Expire</span><span> > 0 ? time() + </span><span class="vars">$Expire</span><span> : 0, self::DEVICE_BINARY_SIZE, </span><span class="vars">$deviceToken</span><span>); </span></span></li><li class=""><span> <span class="vars">$ret</span><span> .= pack(</span><span class="string">'n'</span><span>, </span><span class="vars">$payloadLength</span><span>); </span></span></li><li class="alt"><span> <span class="vars">$ret</span><span> .= </span><span class="vars">$payload</span><span>; </span></span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$ret</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> readErrorMessage() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$errorResponse</span><span> = @</span><span class="func">fread</span><span>(</span><span class="vars">$this</span><span>->_hSocket, self::ERROR_RESPONSE_SIZE); </span></span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="vars">$errorResponse</span><span> === false || </span><span class="func">strlen</span><span>(</span><span class="vars">$errorResponse</span><span>) != self::ERROR_RESPONSE_SIZE) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$errorResponse</span><span> = </span><span class="vars">$this</span><span>->parseErrorMessage(</span><span class="vars">$errorResponse</span><span>); </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (!</span><span class="func">is_array</span><span>(</span><span class="vars">$errorResponse</span><span>) || </span><span class="func">empty</span><span>(</span><span class="vars">$errorResponse</span><span>)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">if</span><span> (!isset(</span><span class="vars">$errorResponse</span><span>[</span><span class="string">'command'</span><span>], </span><span class="vars">$errorResponse</span><span>[</span><span class="string">'statusCode'</span><span>], </span><span class="vars">$errorResponse</span><span>[</span><span class="string">'identifier'</span><span>])) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="vars">$errorResponse</span><span>[</span><span class="string">'command'</span><span>] != self::ERROR_RESPONSE_COMMAND) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$errorResponse</span><span>[</span><span class="string">'timeline'</span><span>] = time(); </span></span></li><li class=""><span> <span class="vars">$errorResponse</span><span>[</span><span class="string">'statusMessage'</span><span>] = </span><span class="string">'None (unknown)'</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (isset(</span><span class="vars">$this</span><span>->_aErrorResponseMessages[</span><span class="vars">$errorResponse</span><span>[</span><span class="string">'statusCode'</span><span>]])) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$errorResponse</span><span>[</span><span class="string">'statusMessage'</span><span>] = </span><span class="vars">$this</span><span>->_errorResponseMessages[</span><span class="vars">$errorResponse</span><span>[</span><span class="string">'statusCode'</span><span>]]; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$errorResponse</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> parseErrorMessage(</span><span class="vars">$errorMessage</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span> unpack(</span><span class="string">'Ccommand/CstatusCode/Nidentifier'</span><span>, </span><span class="vars">$errorMessage</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> send() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (!</span><span class="vars">$this</span><span>->_hSocket) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">'Not connected to Push Notification Service'</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$sendCount</span><span> = </span><span class="vars">$this</span><span>->getDTNumber(); </span></span></li><li class="alt"><span> <span class="vars">$messagePayload</span><span> = </span><span class="vars">$this</span><span>->getPayload(); </span></span></li><li class=""><span> <span class="keyword">foreach</span><span>(</span><span class="vars">$this</span><span>->_deviceTokens AS </span><span class="vars">$key</span><span> => </span><span class="vars">$value</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$apnsMessage</span><span> = </span><span class="vars">$this</span><span>->getBinaryNotification(</span><span class="vars">$value</span><span>, </span><span class="vars">$messagePayload</span><span>, </span><span class="vars">$messageID</span><span> = 0, </span><span class="vars">$Expire</span><span> = 604800); </span></span></li><li class="alt"><span> <span class="vars">$nLen</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$apnsMessage</span><span>); </span></span></li><li class=""><span> <span class="vars">$aErrorMessage</span><span> = null; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="vars">$nLen</span><span> !== (</span><span class="vars">$nWritten</span><span> = (int)@fwrite(</span><span class="vars">$this</span><span>->_hSocket, </span><span class="vars">$apnsMessage</span><span>))) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$aErrorMessage</span><span> = </span><span class="keyword">array</span><span> </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">'identifier'</span><span> => </span><span class="vars">$key</span><span>, </span></span></li><li class=""><span> <span class="string">'statusCode'</span><span> => self::STATUS_CODE_INTERNAL_ERROR, </span></span></li><li class="alt"><span> <span class="string">'statusMessage'</span><span> => sprintf(</span><span class="string">'%s (%d bytes written instead of %d bytes)'</span><span>,</span><span class="vars">$this</span><span>->_errorResponseMessages[self::STATUS_CODE_INTERNAL_ERROR], </span><span class="vars">$nWritten</span><span>, </span><span class="vars">$nLen</span><span>) </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> addDT(</span><span class="vars">$deviceToken</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">if</span><span> (!preg_match(</span><span class="string">'~^[a-f0-9]{64}$~i'</span><span>, </span><span class="vars">$deviceToken</span><span>)) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> <span class="string">"Invalid device token '{$deviceToken}'"</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$this</span><span>->_deviceTokens[] = </span><span class="vars">$deviceToken</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getDTNumber() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="func">count</span><span>(</span><span class="vars">$this</span><span>->_deviceTokens); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setText(</span><span class="vars">$text</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$this</span><span>->_text = </span><span class="vars">$text</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> </span><span class="func">getText</span><span>() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_text; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setBadge(</span><span class="vars">$badge</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (!</span><span class="func">is_int</span><span>(</span><span class="vars">$badge</span><span>)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">"Invalid badge number '{$badge}'"</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$this</span><span>->_badge = </span><span class="vars">$badge</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getBadge() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_badge; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setSound(</span><span class="vars">$sound</span><span> = </span><span class="string">'default'</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$this</span><span>->_sound = </span><span class="vars">$sound</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getSound() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_sound; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setCP(</span><span class="vars">$name</span><span>, </span><span class="vars">$value</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="vars">$name</span><span> == self::APPLE_RESERVED_NAMESPACE) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> <span class="string">"Property name '"</span><span> . self::APPLE_RESERVED_NAMESPACE . </span><span class="string">"' can not be used for custom property."</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="vars">$this</span><span>->_customProperties[trim(</span><span class="vars">$name</span><span>)] = </span><span class="vars">$value</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">function</span><span> _getPayload() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$aPayload</span><span>[self::APPLE_RESERVED_NAMESPACE] = </span><span class="keyword">array</span><span>(); </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span> (isset(</span><span class="vars">$this</span><span>->_text)) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$aPayload</span><span>[self::APPLE_RESERVED_NAMESPACE][</span><span class="string">'alert'</span><span>] = (string)</span><span class="vars">$this</span><span>->_text; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">if</span><span> (isset(</span><span class="vars">$this</span><span>->_badge) && </span><span class="vars">$this</span><span>->_badge > 0) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$aPayload</span><span>[self::APPLE_RESERVED_NAMESPACE][</span><span class="string">'badge'</span><span>] = (int)</span><span class="vars">$this</span><span>->_badge; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">if</span><span> (isset(</span><span class="vars">$this</span><span>->_sound)) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$aPayload</span><span>[self::APPLE_RESERVED_NAMESPACE][</span><span class="string">'sound'</span><span>] = (string)</span><span class="vars">$this</span><span>->_sound; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="func">is_array</span><span>(</span><span class="vars">$this</span><span>->_customProperties)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">foreach</span><span>(</span><span class="vars">$this</span><span>->_customProperties </span><span class="keyword">as</span><span> </span><span class="vars">$propertyName</span><span> => </span><span class="vars">$propertyValue</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="vars">$aPayload</span><span>[</span><span class="vars">$propertyName</span><span>] = </span><span class="vars">$propertyValue</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$aPayload</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setExpiry(</span><span class="vars">$expiryValue</span><span>) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">if</span><span> (!</span><span class="func">is_int</span><span>(</span><span class="vars">$expiryValue</span><span>)) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">"Invalid seconds number '{$expiryValue}'"</span><span> </span></span></li><li class=""><span> ); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="vars">$this</span><span>->_expiryValue = </span><span class="vars">$expiryValue</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getExpiry() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_expiryValue; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> setCustomIdentifier(</span><span class="vars">$customIdentifier</span><span>) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$this</span><span>->_customIdentifier = </span><span class="vars">$customIdentifier</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getCustomIdentifier() </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->_customIdentifier; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getPayload() </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$sJSONPayload</span><span> = </span><span class="func">str_replace</span><span> </span></span></li><li class="alt"><span> ( </span></li><li class=""><span> <span class="string">'"'</span><span> . self::APPLE_RESERVED_NAMESPACE . </span><span class="string">'":[]'</span><span>, </span></span></li><li class="alt"><span> <span class="string">'"'</span><span> . self::APPLE_RESERVED_NAMESPACE . </span><span class="string">'":{}'</span><span>, </span></span></li><li class=""><span> json_encode(<span class="vars">$this</span><span>->_getPayload()) </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> <span class="vars">$nJSONPayloadLen</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$sJSONPayload</span><span>); </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="vars">$nJSONPayloadLen</span><span> > self::PAYLOAD_MAXIMUM_SIZE) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="vars">$this</span><span>->_autoAdjustLongPayload) </span></span></li><li class="alt"><span> { </span></li><li class=""><span> <span class="vars">$maxTextLen</span><span> = </span><span class="vars">$textLen</span><span> = </span><span class="func">strlen</span><span>(</span><span class="vars">$this</span><span>->_text) - (</span><span class="vars">$nJSONPayloadLen</span><span> - self::PAYLOAD_MAXIMUM_SIZE); </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="vars">$nMaxTextLen</span><span> > 0) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">while</span><span> (</span><span class="func">strlen</span><span>(</span><span class="vars">$this</span><span>->_text = mb_substr(</span><span class="vars">$this</span><span>->_text, 0, --</span><span class="vars">$textLen</span><span>, </span><span class="string">'UTF-8'</span><span>)) > </span><span class="vars">$maxTextLen</span><span>); </span></span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$this</span><span>->getPayload(); </span></span></li><li class="alt"><span> }<span class="keyword">else</span><span> </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is "</span><span> . </span></span></li><li class=""><span> self::PAYLOAD_MAXIMUM_SIZE . <span class="string">" bytes. The message text can not be auto-adjusted."</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> }<span class="keyword">else</span><span> </span></span></li><li class=""><span> { </span></li><li class="alt"><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> Exception </span></span></li><li class=""><span> ( </span></li><li class="alt"><span> <span class="string">"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is "</span><span> . </span></span></li><li class=""><span> self::PAYLOAD_MAXIMUM_SIZE . <span class="string">" bytes"</span><span> </span></span></li><li class="alt"><span> ); </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="vars">$sJSONPayload</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span>?> </span></li><li class="alt"><span><?php </span></li><li class=""><span>date_default_timezone_set(<span class="string">'PRC'</span><span>); </span></span></li><li class="alt"><span><span class="func">echo</span><span> </span><span class="string">"we are young,test apns. -"</span><span>.</span><span class="func">date</span><span>(</span><span class="string">'Y-m-d h:i:s'</span><span>,time()); </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="vars">$rootpath</span><span> = </span><span class="string">'entrust_root_certification_authority.pem'</span><span>; </span><span class="comment">//ROOT证书地址</span><span> </span></span></li><li class=""><span><span class="vars">$cp</span><span> = </span><span class="string">'ck.pem'</span><span>; </span><span class="comment">//provider证书地址</span><span> </span></span></li><li class="alt"><span><span class="vars">$apns</span><span> = </span><span class="keyword">new</span><span> APNS(1,</span><span class="vars">$cp</span><span>); </span></span></li><li class=""><span>try </span></li><li class="alt"><span>{ </span></li><li class=""><span> <span class="comment">//$apns->setRCA($rootpath); //设置ROOT证书</span><span> </span></span></li><li class="alt"><span> <span class="vars">$apns</span><span>->connect(); </span><span class="comment">//连接</span><span> </span></span></li><li class=""><span> <span class="vars">$apns</span><span>->addDT(</span><span class="string">'acc5150a4df26507a84f19ba145ca3c1be5842a6177511ce7c43d01badb1bd96'</span><span>); </span><span class="comment">//加入deviceToken</span><span> </span></span></li><li class="alt"><span> <span class="vars">$apns</span><span>->setText(</span><span class="string">'这是一条测试信息'</span><span>); </span><span class="comment">//发送内容</span><span> </span></span></li><li class=""><span> <span class="vars">$apns</span><span>->setBadge(1); </span><span class="comment">//设置图标数</span><span> </span></span></li><li class="alt"><span> <span class="vars">$apns</span><span>->setSound(); </span><span class="comment">//设置声音</span><span> </span></span></li><li class=""><span> <span class="vars">$apns</span><span>->setExpiry(3600); </span><span class="comment">//过期时间</span><span> </span></span></li><li class="alt"><span> <span class="vars">$apns</span><span>->setCP(</span><span class="string">'custom operation'</span><span>,</span><span class="keyword">array</span><span>(</span><span class="string">'type'</span><span> => </span><span class="string">'1'</span><span>,</span><span class="string">'url'</span><span> => </span><span class="string">'http://www.google.com.hk'</span><span>)); //自定义操作 </span></span></li><li class=""><span> <span class="vars">$apns</span><span>->send(); </span><span class="comment">//发送</span><span> </span></span></li><li class="alt"><span> <span class="func">echo</span><span> </span><span class="string">' sent ok'</span><span>; </span></span></li><li class=""><span>}catch(Exception <span class="vars">$e</span><span>) </span></span></li><li class="alt"><span>{ </span></li><li class=""><span> <span class="func">echo</span><span> </span><span class="vars">$e</span><span>; </span></span></li><li class="alt"><span>} </span></li><li class=""><span>?> </span></li><li class="alt"><span> </span></li><li class=""><span></body> </span></li><li class="alt"><span></html> </span></li></ol><div class="save_code tracking-ad" data-mod="popu_249"><a href="javascript:;" target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png"></a></div></div><pre code_snippet_id="481571" snippet_file_name="blog_20141010_4_193481" name="code" class="php" style="display: none;"><!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>APNS</title>
</head>
<body>
<?php
/**
* @file apns.php
* @synopsis apple APNS class
* @author Yee, <rlk002@gmail.com>
* @version 1.0
* @date 2012-09-17 11:27:59
*/
class APNS
{
const ENVIRONMENT_PRODUCTION = 0;
const ENVIRONMENT_SANDBOX = 1;
const DEVICE_BINARY_SIZE = 32;
const CONNECT_RETRY_INTERVAL = 1000000;
const SOCKET_SELECT_TIMEOUT = 1000000;
const COMMAND_PUSH = 1;
const STATUS_CODE_INTERNAL_ERROR = 999;
const ERROR_RESPONSE_SIZE = 6;
const ERROR_RESPONSE_COMMAND = 8;
const PAYLOAD_MAXIMUM_SIZE = 256;
const APPLE_RESERVED_NAMESPACE = 'aps';
protected $_environment;
protected $_providerCertificateFile;
protected $_rootCertificationAuthorityFile;
protected $_connectTimeout;
protected $_connectRetryTimes = 3;
protected $_connectRetryInterval;
protected $_socketSelectTimeout;
protected $_hSocket;
protected $_deviceTokens = array();
protected $_text;
protected $_badge;
protected $_sound;
protected $_customProperties;
protected $_expiryValue = 604800;
protected $_customIdentifier;
protected $_autoAdjustLongPayload = true;
protected $asurls = array('ssl://gateway.push.apple.com:2195','ssl://gateway.sandbox.push.apple.com:2195');
protected $_errorResponseMessages = array
(
0 => 'No errors encountered',
1 => 'Processing error',
2 => 'Missing device token',
3 => 'Missing topic',
4 => 'Missing payload',
5 => 'Invalid token size',
6 => 'Invalid topic size',
7 => 'Invalid payload size',
8 => 'Invalid token',
self::STATUS_CODE_INTERNAL_ERROR => 'Internal error'
);
function __construct($environment,$providerCertificateFile)
{
if($environment != self::ENVIRONMENT_PRODUCTION && $environment != self::ENVIRONMENT_SANDBOX)
{
throw new Exception(
"Invalid environment '{$environment}'"
);
}
$this->_environment = $environment;
if(!is_readable($providerCertificateFile))
{
throw new Exception(
"Unable to read certificate file '{$providerCertificateFile}'"
);
}
$this->_providerCertificateFile = $providerCertificateFile;
$this->_connectTimeout = @ini_get("default_socket_timeout");
$this->_connectRetryInterval = self::CONNECT_RETRY_INTERVAL;
$this->_socketSelectTimeout = self::SOCKET_SELECT_TIMEOUT;
}
public function setRCA($rootCertificationAuthorityFile)
{
if(!is_readable($rootCertificationAuthorityFile))
{
throw new Exception(
"Unable to read Certificate Authority file '{$rootCertificationAuthorityFile}'"
);
}
$this->_rootCertificationAuthorityFile = $rootCertificationAuthorityFile;
}
public function getRCA()
{
return $this->_rootCertificationAuthorityFile;
}
protected function _connect()
{
$sURL = $this->asurls[$this->_environment];
$streamContext = stream_context_create(
array
(
'ssl' => array
(
'verify_peer' => isset($this->_rootCertificationAuthorityFile),
'cafile' => $this->_rootCertificationAuthorityFile,
'local_cert' => $this->_providerCertificateFile
)
)
);
$this->_hSocket = @stream_socket_client($sURL,$nError,$sError,$this->_connectTimeout,STREAM_CLIENT_CONNECT, $streamContext);
if (!$this->_hSocket)
{
throw new Exception
(
"Unable to connect to '{$sURL}': {$sError} ({$nError})"
);
}
stream_set_blocking($this->_hSocket, 0);
stream_set_write_buffer($this->_hSocket, 0);
return true;
}
public function connect()
{
$bConnected = false;
$retry = 0;
while(!$bConnected)
{
try
{
$bConnected = $this->_connect();
}catch (Exception $e)
{
if ($nRetry >= $this->_connectRetryTimes)
{
throw $e;
}else
{
usleep($this->_nConnectRetryInterval);
}
}
$retry++;
}
}
public function disconnect()
{
if (is_resource($this->_hSocket))
{
return fclose($this->_hSocket);
}
return false;
}
protected function getBinaryNotification($deviceToken, $payload, $messageID = 0, $Expire = 604800)
{
$tokenLength = strlen($deviceToken);
$payloadLength = strlen($payload);
$ret = pack('CNNnH*', self::COMMAND_PUSH, $messageID, $Expire > 0 ? time() + $Expire : 0, self::DEVICE_BINARY_SIZE, $deviceToken);
$ret .= pack('n', $payloadLength);
$ret .= $payload;
return $ret;
}
protected function readErrorMessage()
{
$errorResponse = @fread($this->_hSocket, self::ERROR_RESPONSE_SIZE);
if ($errorResponse === false || strlen($errorResponse) != self::ERROR_RESPONSE_SIZE)
{
return;
}
$errorResponse = $this->parseErrorMessage($errorResponse);
if (!is_array($errorResponse) || empty($errorResponse))
{
return;
}
if (!isset($errorResponse['command'], $errorResponse['statusCode'], $errorResponse['identifier']))
{
return;
}
if ($errorResponse['command'] != self::ERROR_RESPONSE_COMMAND)
{
return;
}
$errorResponse['timeline'] = time();
$errorResponse['statusMessage'] = 'None (unknown)';
if (isset($this->_aErrorResponseMessages[$errorResponse['statusCode']]))
{
$errorResponse['statusMessage'] = $this->_errorResponseMessages[$errorResponse['statusCode']];
}
return $errorResponse;
}
protected function parseErrorMessage($errorMessage)
{
return unpack('Ccommand/CstatusCode/Nidentifier', $errorMessage);
}
public function send()
{
if (!$this->_hSocket)
{
throw new Exception
(
'Not connected to Push Notification Service'
);
}
$sendCount = $this->getDTNumber();
$messagePayload = $this->getPayload();
foreach($this->_deviceTokens AS $key => $value)
{
$apnsMessage = $this->getBinaryNotification($value, $messagePayload, $messageID = 0, $Expire = 604800);
$nLen = strlen($apnsMessage);
$aErrorMessage = null;
if ($nLen !== ($nWritten = (int)@fwrite($this->_hSocket, $apnsMessage)))
{
$aErrorMessage = array
(
'identifier' => $key,
'statusCode' => self::STATUS_CODE_INTERNAL_ERROR,
'statusMessage' => sprintf('%s (%d bytes written instead of %d bytes)',$this->_errorResponseMessages[self::STATUS_CODE_INTERNAL_ERROR], $nWritten, $nLen)
);
}
}
}
public function addDT($deviceToken)
{
if (!preg_match('~^[a-f0-9]{64}$~i', $deviceToken))
{
throw new Exception
(
"Invalid device token '{$deviceToken}'"
);
}
$this->_deviceTokens[] = $deviceToken;
}
public function getDTNumber()
{
return count($this->_deviceTokens);
}
public function setText($text)
{
$this->_text = $text;
}
public function getText()
{
return $this->_text;
}
public function setBadge($badge)
{
if (!is_int($badge))
{
throw new Exception
(
"Invalid badge number '{$badge}'"
);
}
$this->_badge = $badge;
}
public function getBadge()
{
return $this->_badge;
}
public function setSound($sound = 'default')
{
$this->_sound = $sound;
}
public function getSound()
{
return $this->_sound;
}
public function setCP($name, $value)
{
if ($name == self::APPLE_RESERVED_NAMESPACE)
{
throw new Exception
(
"Property name '" . self::APPLE_RESERVED_NAMESPACE . "' can not be used for custom property."
);
}
$this->_customProperties[trim($name)] = $value;
}
protected function _getPayload()
{
$aPayload[self::APPLE_RESERVED_NAMESPACE] = array();
if (isset($this->_text))
{
$aPayload[self::APPLE_RESERVED_NAMESPACE]['alert'] = (string)$this->_text;
}
if (isset($this->_badge) && $this->_badge > 0)
{
$aPayload[self::APPLE_RESERVED_NAMESPACE]['badge'] = (int)$this->_badge;
}
if (isset($this->_sound))
{
$aPayload[self::APPLE_RESERVED_NAMESPACE]['sound'] = (string)$this->_sound;
}
if (is_array($this->_customProperties))
{
foreach($this->_customProperties as $propertyName => $propertyValue)
{
$aPayload[$propertyName] = $propertyValue;
}
}
return $aPayload;
}
public function setExpiry($expiryValue)
{
if (!is_int($expiryValue))
{
throw new Exception
(
"Invalid seconds number '{$expiryValue}'"
);
}
$this->_expiryValue = $expiryValue;
}
public function getExpiry()
{
return $this->_expiryValue;
}
public function setCustomIdentifier($customIdentifier)
{
$this->_customIdentifier = $customIdentifier;
}
public function getCustomIdentifier()
{
return $this->_customIdentifier;
}
public function getPayload()
{
$sJSONPayload = str_replace
(
'"' . self::APPLE_RESERVED_NAMESPACE . '":[]',
'"' . self::APPLE_RESERVED_NAMESPACE . '":{}',
json_encode($this->_getPayload())
);
$nJSONPayloadLen = strlen($sJSONPayload);
if ($nJSONPayloadLen > self::PAYLOAD_MAXIMUM_SIZE)
{
if ($this->_autoAdjustLongPayload)
{
$maxTextLen = $textLen = strlen($this->_text) - ($nJSONPayloadLen - self::PAYLOAD_MAXIMUM_SIZE);
if ($nMaxTextLen > 0)
{
while (strlen($this->_text = mb_substr($this->_text, 0, --$textLen, 'UTF-8')) > $maxTextLen);
return $this->getPayload();
}else
{
throw new Exception
(
"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .
self::PAYLOAD_MAXIMUM_SIZE . " bytes. The message text can not be auto-adjusted."
);
}
}else
{
throw new Exception
(
"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .
self::PAYLOAD_MAXIMUM_SIZE . " bytes"
);
}
}
return $sJSONPayload;
}
}
?>
<?php
date_default_timezone_set('PRC');
echo "we are young,test apns. -".date('Y-m-d h:i:s',time());
$rootpath = 'entrust_root_certification_authority.pem'; //ROOT证书地址
$cp = 'ck.pem'; //provider证书地址
$apns = new APNS(1,$cp);
try
{
//$apns->setRCA($rootpath); //设置ROOT证书
$apns->connect(); //连接
$apns->addDT('acc5150a4df26507a84f19ba145ca3c1be5842a6177511ce7c43d01badb1bd96'); //加入deviceToken
$apns->setText('这是一条测试信息'); //发送内容
$apns->setBadge(1); //设置图标数
$apns->setSound(); //设置声音
$apns->setExpiry(3600); //过期时间
$apns->setCP('custom operation',array('type' => '1','url' => 'http://www.google.com.hk')); //自定义操作
$apns->send(); //发送
echo ' sent ok';
}catch(Exception $e)
{
echo $e;
}
?>
</body>
</html></pre>
<p></p>
<p><br>
</p>
<h3><a name="t13"></a>2,启动 Apache </h3>
mac 自带apache,可直接运行php。
<p></p>
<p>打开“终端(terminal)”,输入 sudo apachectl -v,可显示Apache的版本;</p>
<p>输入 sudo apachectl start,这样Apache就启动了。</p>
<p>编辑文件 /etc/apache2/httpd.conf , 把 LoadModule php5_module libexec/apache2/libphp5.so 前面的注释去掉;然后重启apache: sudo apachectl restart</p>
<p>打开Safari浏览器地址栏输入 “http://localhost”,可以看到内容为“It works!”的页面。其位</p>
<p>于“/Library/WebServer/Documents/”下,这就是Apache的默认根目录。<br>
</p>
<h3><a name="t14"></a>3,如何调试</h3>
<div>将服务器端写好的apns.php 文件以及生成的 ck.pem 文件,直接拷贝到 /Library/WebServer/Documents/ 下,在浏览器中,直接浏览: http://localhost/apns.php 。这样消息就发送到了苹果服务器。</div>
<div><img src="http://img.blog.csdn.net/20151209163146784?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</div>
</div>
0 0
- iOS消息推送完整版
- IOS推送消息 php推送
- ios 推送消息 php推送
- ios 推送消息 极光推送/百度推送
- ios推送消息
- iOS消息推送
- iOS消息推送
- iOS推送消息实现
- iOS php消息推送
- IOS推送消息
- IOS消息推送
- iOS 消息推送
- ios消息推送
- IOS消息推送
- iOS 消息推送原理
- iOS 消息推送原理
- iOS 消息推送通知
- iOS消息推送
- redis的键(key)
- linux 下,查询某个文件位置 & 编辑文本时,定位文件中某个字符串位置
- 软工之内聚
- android textview 右上角跟随文本动态追加红点
- 学习WEB前端之路曲折前行
- iOS消息推送完整版
- java.lang.RuntimeException: Performing stop of activity that is not resumed OOM了也会造成之前Activity被系统杀掉
- Spring MVC的Controller统一异常处理:HandlerExceptionResolver
- 字节流和字符流
- Maven创建Struts2 + Spring + Hibernate项目
- Jflash源码分析
- AngularJS表单验证
- 002Android build.gradle 基本知识点
- 2维FFT算法实现——基于GPU的基2快速二维傅里叶变换