博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
APNs推送那些事
阅读量:5925 次
发布时间:2019-06-19

本文共 12461 字,大约阅读时间需要 41 分钟。

#####目录 #####0.各版本推送特性 #####1.证书配置 #####2.测试脚本 #####3.xcode7项目配置推送 #####4.推送处理 #####5.遇到的坑 #####6.参考资料 #####7.消息大批量发送方案

####正文 #####0.各版本推送特性 APNs Apple Push Notification service (APNs) 推送字段长度 很显著的变化是从iOS8开始Apple对消息字节有很大的扩容

推送内容为字节=(x)个字节 - 45个设备Token/默认占位标示符x
=iOS8&&x
=iOS9 4KB复制代码

推送通知样式

系统版本         显示样式iOS8以前        只有3个地方展示,点击进入应用iOS8版本			提供快捷处理ActionsiOS9版本			提供快捷回复TextInput复制代码

#####1.证书配置 这方面的资料有很多,优秀的博文也很多,按照下面接个配置即可。

http://blog.csdn.net/showhilllee/article/details/8631734 [是对raywenderlich的一个翻译版本,需要注意的是这个版本还是开发者中心改版之前的一个版本,但大体流程没有问题]http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1http://www.raywenderlich.com/32963/apple-push-notification-services-in-ios-6-tutorial-part-2复制代码

这里有几个坑需要注意一下

1.1 导出时点击证书上级 级别,即iPhone Developer:E.....这个

验证.p12的方式有很多种,我一切从简,直接把.p12传到上去验证,很直观明了。

1.2 证书文件的有效期

无论是Development Push SSLCertificate还是Production Push SSL Certificate 都有过期时间的。 Development Push SSL Certificate有效期大概四个月左右,而ProductionPush SSL Certificate的有效期是一年。需要注意在过期之前生成新的证书,以免影响使用。

1.3 那段pushMe.php貌似有问题了,下面会贴出我的测试php代码。

#####2.测试脚本

"CATEGORY_ID" //用来快捷处理消息唯一标示 } } */ $deviceToken= '944a39dada1f6daf10b62fe7d135063a959ad568d1c5879656e043943.....'; //没有空格 $body = []; $type = 5; //1 课程 2计划 3文章 4活动 5web页面跳转 控制推送内容 ///拼接推送字符串 switch ($type) { case 1: $content = '从搭建Golang开发环境开始, 一步步介绍Golang系统库之输入输出的功能及特性。结合行数统计及图片读取,在实战中扎扎实实的学习Golang'; $body = array("aps" => array("alert" => $content,"badge" => 10,"sound"=>'default','data'=>array('tid'=>10000,'id'=>492,'type'=>0,'systype'=>$type))); break; case 2: $content = '随着互联网的发展速度迅猛,前端工程师职业越来越火热,想学习Web前端技能吗 ? 该路径从基础知识到实战案例演练,一步步带您快速掌握如何搭建网站静态页面、开发网站交互特效,为您打开WEB前端工程师大门。还在等什么?快来学习吧!'; $body = array("aps" => array("alert" => $content,"badge" => 11,"sound"=>'default','data'=>array('tid'=>10001,'id'=>32,'type'=>0,'systype'=>$type))); break; case 3: $content = 'CodeStriker CodeStriker是一个免费&开源的Web应用程序,可以帮助开发人员基于Web的代码审查。它不但允许开发人员将问题、意见和决定记录在数据库中,还为实际执行代码审查提供了一个舒适的工作区域。 官方网站:http://codestriker.sourceforge.net/index.html 2)RhodeCode Rhode'; $body = array("aps" => array("alert" => $content,"badge" => 12,"sound"=>'default','data'=>array('tid'=>10002,'id'=>2493,'type'=>0,'systype'=>$type))); break; case 4: $content = '高薪捉拿程序大拿'; $body = array("aps" => array("alert" => $content,"badge" => 12,"sound"=>'default','data'=>array('tid'=>27820,'id'=>2493,'type'=>0,'systype'=>$type,'url'=>'http://t.imooc.com'))); break; case 5: $content = '如何从零开始开发一款AppleWatch App?'; $body = array("aps" => array("alert" => $content,"badge" => 13,"sound"=>'default','data'=>array('tid'=>10003,'id'=>0,'type'=>0,'systype'=>$type,'url'=>'http://t.imooc.com'),"category"=>"CATEGORY_ID")); break; default: # code... break; } $ctx = stream_context_create(); //如果在Windows的服务器上,寻找pem路径会有问题,路径修改成这样的方法: //$pem = dirname(__FILE__) . '/' . 'apns-dev.pem'; //linux 的服务器直接写pem的路径即可 stream_context_set_option($ctx,"ssl","local_cert","ck.pem"); $pass = "1234"; stream_context_set_option($ctx, 'ssl', 'passphrase', $pass); //此处有两个服务器需要选择,如果是开发测试用,选择第二名sandbox的服务器并使用Dev的pem证书,如果是正是发布,使用Product的pem并选用正式的服务器 // $fp = stream_socket_client("ssl://gateway.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx); $fp = stream_socket_client("ssl://gateway.sandbox.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx); if (!$fp) { echo "Failed to connect $err $errstrn"; return; } print "Connection OK\\n"; $payload = json_encode($body); $msg = chr(0) . pack("n",32) . pack("H*", str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload; echo "sending message :" . $payload ."\\n"; fwrite($fp, $msg); fclose($fp);?>复制代码

#####3.xcode7项目配置推送 3.1 配置你的项目bundleid和推送证书是一致的*

3.2 打开推送

3.3 选择推送测试证书

运行项目到手机,直接测试一下你的推送了,手机应该收到推送消息,若不对请自查上面各个步骤。

#####4.推送处理 以下方法均是AppDelegate中的

######4.1 上报机器Token给服务器处理函数

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{    NSString* newToken = [deviceToken description];    newToken = [newToken stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];    newToken = [newToken stringByReplacingOccurrencesOfString:@" " withString:@""];    //此处将token上报给服务器,token有可能随着app的删除重装改变,请不要将它做的唯一标示。 }复制代码
// 取token错误处理- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error{	   NSLog(@"Failed to get token, error: %@", error);}复制代码

######4.2 推送快捷处理 系统要求:

NS_CLASS_AVAILABLE_IOS(8_0)复制代码

效果图

在AppDeleate didFinishLaunchingWithOptions 中调用

//1.创建消息上面要添加的动作(按钮的形式显示出来)UIMutableUserNotificationAction *action = [[UIMutableUserNotificationAction alloc] init];        action.identifier = @"action";//按钮的标示        action.title=@"Accept";//按钮的标题        action.activationMode = UIUserNotificationActivationModeForeground;//当点击的时候启动程序        //    action.authenticationRequired = YES;        //    action.destructive = YES;                UIMutableUserNotificationAction *action2 = [[UIMutableUserNotificationAction alloc] init];        action2.identifier = @"action2";        action2.title=@"Reject";        action2.activationMode = UIUserNotificationActivationModeBackground;//当点击的时候不启动程序,在后台处理        action.authenticationRequired = YES;//需要解锁才能处理,如果action.activationMode = UIUserNotificationActivationModeForeground;则这个属性被忽略;        action.destructive = YES;                //2.创建动作(按钮)的类别集合        UIMutableUserNotificationCategory *categorys = [[UIMutableUserNotificationCategory alloc] init];        categorys.identifier = @"CATEGORY_ID";//这组动作的唯一标示        [categorys setActions:@[action,action2] forContext:(UIUserNotificationActionContextMinimal)];                //3.创建UIUserNotificationSettings,并设置消息的显示类类型        UIUserNotificationSettings *uns = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound) categories:[NSSet setWithObjects:categorys, nil]];                //4.注册推送        [[UIApplication sharedApplication] registerForRemoteNotifications];        [[UIApplication sharedApplication] registerUserNotificationSettings:uns];复制代码

在AppDelegate中实现这几个方法

//处理通过点击Actions进来的事件-(void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler{    //在没有启动本App时,收到服务器推送消息,下拉消息会有快捷回复的按钮,点击按钮后调用的方法,根据identifier来判断点击的哪个按钮}- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{    NSLog(@"%@", notificationSettings);}复制代码

接收消息处理

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{     if (userInfo&&application.applicationState==UIApplicationStateActive) {		//这是程序运行的时候,收到通知[这时推送直接调此方法]    }else if (userInfo&&application.applicationState==UIApplicationStateInactive){       // 这是程序不活跃,收到通    }else if (userInfo&&application.applicationState==UIApplicationStateBackground){    	//这是程序在后台,收到通知    }else{    	    }}复制代码

######4.3 推送快捷回复 系统要求:

NS_CLASS_AVAILABLE_IOS(9_0)复制代码

效果图

在Appdelegate 中 添加如下代码

UIMutableUserNotificationAction *textAction = [[UIMutableUserNotificationAction alloc] init];        textAction.identifier = @"TEXT_ACTION";//快捷回复按钮的标示        textAction.title=@"Reply";//快捷回复按钮的标题        textAction.authenticationRequired = NO;//        textAction.activationMode = UIUserNotificationActivationModeForeground;//当点击的时候启动程序        textAction.destructive =  NO;        textAction.behavior = UIUserNotificationActionBehaviorTextInput;                //2.创建动作(回复)的类别集合        UIMutableUserNotificationCategory *categorys = [[UIMutableUserNotificationCategory alloc] init];        categorys.identifier = @"CATEGORY_ID";//这组动作的唯一标示//        [categorys setActions:@[action,action2] forContext:(UIUserNotificationActionContextMinimal)];        [categorys setActions:@[textAction] forContext:UIUserNotificationActionContextDefault];        [categorys setActions:@[textAction] forContext:UIUserNotificationActionContextMinimal];        //3.创建UIUserNotificationSettings,并设置消息的显示类类型        UIUserNotificationSettings *uns = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound) categories:[NSSet setWithObjects:categorys, nil]];        //4.注册推送        [[UIApplication sharedApplication] registerForRemoteNotifications];复制代码

######4.4 推送流程图

(根据具体情况而定)

当然你可以写一个很高大上的启动任务队列来处理AppDelegate的任务处理,AppDelegate一庞大起来,会带来很多逻辑问题。

#####4.5 推送状态统计 If you send a notification that is accepted by APNs, nothing is returned.

If you send a notification that is malformed or otherwise unintelligible, APNs returns an error-response packet and closes the connection. Any notifications that you sent after the

The packet has a command value of 8 followed by a one-byte status code and the notification identifier of the malformed notification. Table 5-1 lists the possible status codes and their meanings.

Table 5-1 Codes in error-response packet

Status       codeDescription0              No errors encountered1              Processing error2              Missing device token3              Missing topic4              Missing payload5              Invalid token size6              Invalid topic size7              Invalid payload size8              Invalid token10             Shutdown255            None (unknown)复制代码

A status code of 10 indicates that the APNs server closed the connection (for example, to perform maintenance). The notification identifier in the error response indicates the last notification that was successfully sent. Any notifications you sent after it have been discarded and must be resent. When you receive this status code, stop using this connection and open a new connection.

Take note that the device token in the production environment and the device token in the development environment are not the same value.

具体来看官方文档

#####5.遇到的坑 当程序kill以后,推送到之后,点击通知进入App,程序不走

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo复制代码

这时此方法的 userInfo 不为空,且通过取他的 [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey] 内容,即是推送的json内容,对userInfo根据您App情况加以处理,当然userInfo包含了其他处理字段,请根据具体情况区别处理

#####6.参考资料 感谢一下读者的博客,本文只是对这些博文串起来叙述了APNS从证书落地到推送消息处理业务逻辑,有大量的参考资料代码,文字,感谢,统计标记在这儿,希望读者能去拜读一下前人栽的书。

配置流程没有问题,pushMe.php有问题 http://blog.csdn.net/showhilllee/article/details/8631734 http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1 http://www.raywenderlich.com/32963/apple-push-notification-services-in-ios-6-tutorial-part-2

phpme.php推送用这个解决 http://www.cnblogs.com/hubj/archive/2012/06/14/2549816.html

http://www.intertech.com/Blog/push-notifications-tutorial-for-ios-9/ http://blog.csdn.net/yujianxiang666/article/details/35260135

iOS9 Text Input http://fancypixel.github.io/blog/2015/06/11/ios9-notifications-and-text-input/

WWDC2015APNS video https://developer.apple.com/videos/play/wwdc2015-720/

http://54im.com/ios/手把手教你配置苹果apns推送服务.html#8.5_

#####7.消息大批量发送方案 a.消息大批量发送问题

目前由于APNS(Apple Push Notification Service)机制原因,目前easy apns的消息发送机制为:

对每一条发送的消息,为所有需要推送的设备都在数据库中apns_messages创建一条消息,然后通过轮训数据库表来一条一条向苹果消息推送服务器发送消息

在需要推送的设备较多的情况下,由于存在大量的网络链接,导致存在较长时间的延迟。

解决方案:

1、做批量消息推送时候,保持与苹果消息推送服务器的长链接

2、使用批量发送机制

You should also retain connections with APNs across multiple notifications. APNs may consider connections that are rapidly and repeatedly established and torn down as a denial-of-service attack. Upon error, APNs closes the connection on which the error occurred.

As a provider, you are responsible for the following aspects of push notifications:

You must compose the notification payload (see “The Notification Payload”).

You are responsible for supplying the badge number to be displayed on the application icon.

You should regularly connect with the feedback web server and fetch the current list of those devices that have repeatedly reported failed-delivery attempts. Then you should cease sending notifications to the devices associated with those applications. See “The Feedback Service” for more information.

b、数据库轮询效率问题

由于目前easy apns是采用数据库轮询的方式来进行消息推送,效率并不高,后期可以修改为Redis这样的NOSQL

13年走过几遍推送之后,后来项目一直不参与这块,最近突然接手这一块,发现虽然知道一些iOS7之后的新特性,但产品只能把推送归到一个推送,缺不明白其中有很多精妙的处理,有很多新的特性能可以为用户解决一些痛点,而产品的不可能做到每个端的技术细节,所以我们技术能做的时,跟上技术发展的方向,让自己知识体系保持最新,能为用户提供最优的技术解决方案。 最近有点多愁善感,文章有疏漏的地方请留言或者@

你可能感兴趣的文章
iso学习网站记录
查看>>
Doing well in your courses ---- a guide by Andrej Karpathy
查看>>
delete archivelog all 无法彻底删除归档日志?
查看>>
浅析SQL查询语句未显式指定排序方式,无法保证同样的查询每次排序结果都一致的原因...
查看>>
Apache Solr facet 分组查询
查看>>
15个最佳和最新的jQuery图像效果教程
查看>>
android游戏开发框架libgdx的使用(六)--演员和演出
查看>>
WPF 4.5中对绑定的改善
查看>>
android 获取 图片 缩略图
查看>>
7种常见的食物有毒 千万不能吃
查看>>
jQuery EasyUI API 中文文档 - 树(Tree)
查看>>
C 把一个字符串倒序输出
查看>>
白帽子讲Web安全
查看>>
[转载]RestSharp.WindowsPhone调用Rest服务
查看>>
Sqlserver:Sqlserver数据库的脚本生成器2.1
查看>>
如何制作chrome扩展程序
查看>>
iis7应用程序池经常自动停止如何解决?
查看>>
Qt之对话框设计——(1)标准对话框
查看>>
BinaryReader和BinaryWriter的leaveOpen参数 z
查看>>
Pgsql 里面 COALESCE的用法
查看>>