1、消息推送原理:php
在实现消息推送以前先说起几个于推送相关概念,以下图1-1:ios
一、Provider:就是为指定IOS设备应用程序提供Push的服务器,(若是IOS设备的应用程序是客户端的话,那么Provider能够理解为服务端[消息的发起者]);json
二、APNS:Apple Push Notification Service[苹果消息推送服务器];缓存
三、iPhone:用来接收APNS下发下来的消息;服务器
四、Client App:IOS设备上的应用程序,用来接收iphone传递APNS下发的消息到制定的一个客户端 app[消息的最终响应者];网络
上图能够分为三个阶段:app
阶段一:Provider[服务端]把要发送的消息,目的IOS设备标识打包,发送给APNS;iphone
阶段二:APNS在自身的已注册Push服务的IOS设备列表中,查找有相应标识的IOS设备,并将消息发送到IOS设备;ide
阶段三:IOS设备把发送的消息传递给对应的应用程序,而且按照设定弹出Push通知。工具
具体过程,以下图1-2:
一、[Client App]注册消息推送;
二、[Client App]跟[APNS Service]要deviceToken, Client App接收deviceToken;
三、[Client App]将deviceToken发送给[Provider]Push服务端程序;
四、当Push服务端程序知足发送消息条件了,[Provider]向[APNS Service]发送消息;
五、[APNS Service]将消息发送给[Client App].
2、消息推送实现:
一、生成*.certSigningRequest文件,步骤以下:
[MacBook-应用程序-实用工具-钥匙串访问-证书助手-从证书机构求证书-证书信息(用户电子邮箱地址{填写您的邮箱,如:your@email.com},经常使用名称{任意,如:PushDemo},请求是:{单选,选择‘存储到磁盘’})-继续-保存],这时会在您指定的地方生成你指定的文件,默认为CertificateSigningRequest.certSigningRequest文件,这里命名为:PushDemo.certSigningRequest.在此*.certSigningRequest已经生成,具体操做步骤如图所示。
若是生成成功,则会在[钥匙串访问|登陆|密钥]栏目中列出与*.certSigningRequest关联的密钥,这里是PushDemo,如图所示:
二、新建一个App ID(在苹果开发者帐号中配置)
(1) 登陆iOS Dev Center,登陆成功后,点击(iOS Provisioning Portal对应连接),如图所示:
(2) 建立New App ID[App IDsàManageàNew App ID]( Description{填写您对此App ID 的描述,如:iShop},Bundle Seed ID(App ID Prefix){选择绑定App ID前缀,如:默认选择Generate New},Bundle Identifier(App ID Suffix){填写绑定App ID后缀,如:com.yourcorp.iShop}),以下图所示:
这样就会生成下面这条记录,如图所示:
(3) 配置上一步中生成的App ID,让其支持消息推送[点击2-6中的Configureà选中Enable for Apple Push Notification serviceà点击Configure],如图所示:
(4) Generate a Certificate Signing Request(生成部署请求认证)[点击2-7中的2ConfigureàContinueà步骤1生成的*certSigningRequest文件(这里是iShop. certSigningRequest)-Generate-生成完成后将其下载下来,命名为:aps_developer.cer],双击aps_developer.cer证书{将证书与密钥关联,并将证书导入到MacBook中},以下图所示:
(5) 建立Development Provisioning Profiles[开发许可配置文件](Provisioning| Development|New Profile),具体操做流程以下图所示:
点击图中Submit,生成Development Provisioning Profiles[开发许可配置文件],这里是:iShopDevprofile.mobileprovision以下图所示:
下载此开发许可证书(用于联机调试)。
总结,到如今为止,咱们已经生成:A:*.certSigningRequest文件(在步骤(4)中使用,用于生成证书B)、B:aps_developer_identity.cer证书(在Provider[Push服务器]服务端应用使用)、C:*..mobileprovision开发许可配置文件(在Client App客户端应用联机调试使用)。
三、新建一个项目
1. 建立一个"single view application" project,为省事,你设置的"Company Identifier" + "Production“必须和step 5建立的App ID的"bundle identifier"一致。
2. 在AppDelegate.m file的"didFinishLaunchingWithOptions" method里,添加下列代码 (用于为app register push notification feature):
// Let the device know we want to receive push notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
3. 在AppDelegate.m file里添加下列2个methods (用来handle register remote notification with device token和register error的events)
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSLog(@"My token is: %@", deviceToken);
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(@"Failed to get token, error: %@", error);
}
4. 运行该app in real device (simulator doesn't support push notification)。这时你会在device上看到一个popup window (该窗口只会出现一次,重装app不会再出现),提示你该app会send push notification给你,若是赞成则clickOK,不一样意则click "Now allow”。若是选择了OK,那么在"Setting > Notifications“里会有你的app在list里。并且这时你的Xcode output console会显示你的device token。
5: export "PushDemo" private key to a ".p12" file(该文件会在后面生成apns provider的.p12 or .pem file时用到)
1). right click "PushDemo“ private key and select "Export ..."PushDemo
2). Save the private key as “PushDemoKey.p12” file, click Save button
3). 这时会让你输入2次用于加密该.p12 file的密码,例如用"123321",接着会要求你输入一次your mac account password
6: 在5中生成的“PushDemoKey.p12” file和step 6生成的"aps_development.cer" file是用于APNS provider side的源文件,APNS Provider side进行push message时要用到的"cert + key" file就是经过这2个file来生成。该Step就是用来生成for APNS provider side (php version)要用到这个"cert + key" pem file.
1) open Terminal, go to Desktop (假设这2个file都在desktop里)
2) 执行下列命令来生成和apns cer file对应的pem file "PushDemoCert.pem"
openssl x509 -in aps_development.cer -inform der -out PushDemoCert.pem
3) 执行下列命令来生成和private key .p12 file对应的pem file "PushDemoKey.pem" (注意:执行过程会要求你输入"PushDemoKey.p12"建立时设置的密码,以及设置"PushDemoKey.pem”的密码)
openssl pkcs12 -nocerts -out PushDemoKey.pem -in PushDemoKey.p12
4) 执行下列命令把step 11.2生成的cert pem file和step 11.3生成的key pem file合成为一个pem file "PushDemoCK.pem"
cat PushDemoCert.pem PushDemoKey.pem > PushDemoCK.pem
7: 在5生成的“PushDemoKey.p12” file和step 6生成的"aps_development.cer" file是用于APNS provider side的源文件,该step是简单测试这2个file是否有效
1) open Terminal, go to Desktop (假设这2个file都在desktop里)
2) 执行下列命令来测试是否可以connect apple提供的不经加密(即不需使用任何证书!)的APNS server
telnet gateway.sandbox.push.apple.com 2195
若是你看到下列输出,则表示你的电脑能够connect APNS. 若是出现error,那么check你的firewall是否容许outgoing connections on port 2195。
Trying 17.172.233.65...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.
Press Ctrl+C to close the connection.
3) 执行下列命令来测试是否可以connect apple提供的经加密(需使用2) and 3)生成的2个pem file!)的APNS "sandbox“ server for development.
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushDemoCert.pem -key PushDemoKey.pem
执行过程当中会要你输入PushDemoKey.pem生成时设置的密码。若是connect server成功,就会等待你输入字串,你能够输入任意字串,而后回车,就会disconnect server。若是链接不成功,则openssl会显示错误信息。
注意:实际上有2个APNS servers: the “sandbox” server (用于testing) the live server(用于production mode)。咱们这里测试的是sandbox server。live apns server的操做相似。
8: 建立provider server side (php version)
1). Download SimplePush PHP code to your mac machine and then unzip it.
2). 去掉SimplePush folder里的pk.pem (它没用),把step 11.4生成的"PushDemoCK.pem" copy toSimplePush folder
3). 修改simplepush.php file下面几行:
// Put your device token here (without spaces):
//device token来自Step 10的第4点,在output console获取,注意:要去掉先后的尖括号,和中间的全部空格
$deviceToken = '43fcc3cff12965bc45bf842bf9166fa60e8240c575d0aeb0bf395fb7ff86b465';
// Put your private key's passphrase here:
//该值是 3)生成PushDemoKey.pem时设置的密码
$passphrase = '123456';
// Put your alert message here:
$message = 'My first push notification!';
//.....stream_context_set_option($ctx, 'ssl', 'local_cert', 'PushDemoCK.pem');
4). 在terminal window里,go to the simplepush folder,而后执行下列命令,你的iPhone应该会收到一条push message。
php simplepush.php
注意:若是你的app在iphone里是正在运行,并且app是在front end时,当它收到push message时是不会出如今iPhone顶部的notification area的!
参考文章:http://mmz06.blog.163.com/blog/static/121416962011111710934946/
http://user.qzone.qq.com/75869071/infocenter%23!app=2&via=QZ.HashRefresh&pos=1351564081#!app=2&via=QZ.HashRefresh&pos=1351564081
APNS的推送机制
与Android上咱们本身实现的推送服务不同,Apple对设备的控制很是严格,消息推送的流程必需要通过APNs:
这里 Provider 是指某个应用的Developer,固然若是开发者使用AVOS Cloud的服务,把发送消息的请求委托给咱们,那么这里的Provider就是AVOS Cloud的推送服务程序了。上图能够分为三步:
第一步:AVOS Cloud推送服务程序把要发送的消息、目的设备的惟一标识打包,发给APNs。
第二步:APNs在自身的已注册Push服务的应用列表中,查找有相应标识的设备,并把消息发送到设备。
第三步:iOS系统把发来的消息传递给相应的应用程序,而且按照设定弹出Push通知
为了实现消息推送,有两点很是重要:
1,App的推送证书
要可以完整实现一条消息推送,须要咱们在App ID中打开Push Notifications,须要咱们准备好Provisioning Profile和SSL证书,而且必定要注意Development和Distribution环境是须要分开的。最后,把SSL证书导入到AVOS Cloud平台,就能够尝试远程消息推送了。具体的操做流程能够参考咱们的使用指南:iOS推送证书设置指南。
2,设备标识DeviceToken
知道了谁要推送,或者说要推送给哪一个App以后,APNs还须要知道推到哪台设备上,这就是设备标识的做用。获取设备标识的流程以下:
第一步:App打开推送开关,用户要确认TA但愿得到该App的推送消息
第二步:App得到一个DeviceToken
第三步:App将DeviceToken保存起来,这里就是经过[AVInstallation saveInBackground]将DeviceToken保存到AVOS Cloud
第四步:当某些特定事件发生,开发者委托AVOS Cloud来发送推送消息,这时候AVOS Cloud的推送服务器就会给APNs发送一则推送消息,APNs最后消息送到用户设备
推送相关的几个概念
消息类型
一条消息推送过来,能够有以下几种表现形式:
1. 显示一个alert或者banner,展示具体内容
2. 在应用icon上提示一个新到消息数
3. 播放一段声音
开发者能够在每次推送的时候设置,在推送达到用户设备时开发者也能够选择不一样的提示方式。
本地消息通知
iOS上有两种消息通知,一种是本地消息(Local Notification),一种是远程消息(Push Notification,也叫Remote Notification),设计这两种通知的目的都是为了提醒用户,如今有些什么新鲜的事情发生了,吸引用户从新打开应用。
本地消息何时有用呢?譬如你正在作一个To-do的工具类应用,对于用户加入的每个事项,都会有一个完成的时间点,用户能够要求这个To-do应用在事项过时以前的某一个时间点提醒一下TA。为了达到这一目的,App就能够调度一个本地通知,在时间点到了以后发出一个Alert消息或者其余提示。
咱们在处理推送消息的时候,也能够综合运用这两种方式。
代码里面如何实现推送
首先,咱们要获取DeviceToken。
App须要每次启动的时候都去注册远程通知——经过调用UIApplication的registerForRemoteNotificationTypes:方法,传递给它你但愿支持的消息类型参数便可,例如:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // do some initiale working ... [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound]; return YES; }
若是注册成功,APNs会返回给你设备的token,iOS系统会把它传递给app delegate代理——application:didRegisterForRemoteNotificationsWithDeviceToken:方法,你应该在这个方法里面把token保存到AVOS Cloud后台,例如:
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSLog(@"Receive DeviceToken: %@", deviceToken); AVInstallation *currentInstallation = [AVInstallation currentInstallation]; [currentInstallation setDeviceTokenFromData:deviceToken]; [currentInstallation saveInBackground]; }
若是注册失败,application:didFailToRegisterForRemoteNotificationsWithError:方法会被调用,经过NSError参数你能够看到具体的出错信息,例如:
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { NSLog(@"注册失败,没法获取设备ID, 具体错误: %@", error); }
请注意:注册流程须要在app每次启动时调用,这并不不会带来额外的负担,由于iOS操做系统在第一次得到了有效的device token以后,会本地缓存起来,之后app再调用registerForRemoteNotificationTypes:的时候会马上返回,并不会再进行网络请求。另外,app层面不该该对device token进行缓存,由于device token也有可能变化——若是用户重装了操做系统,那么APNs再次给出的device token就会和以前的不同,又或者是,用户restore了原来的backup到新的设备上,那么原来的device token也会失效。
其次,咱们要处理收到消息以后的回调
咱们能够设想一下消息通知的几种使用场景:
1,在app没有被启动的时候,接收到了消息通知。这时候操做系统会按照默认的方式来展示一个alert消息,在app icon上标记一个数字,甚至播放一段声音。
2,用户看到消息以后,点击了一下action按钮或者点击了应用图标。若是action按钮被点击了,系统会经过调用application:didFinishLaunchingWithOptions:这个代理方法来启动应用,而且会把notification的payload数据传递进去。若是应用图标被点击了,系统也同样会调用application:didFinishLaunchingWithOptions:这个代理方法来启动应用,惟一不一样的是这时候启动参数里面不会有任何notification的信息。
示例代码以下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // do initializing works ... if (launchOptions) { // do something else ... [AVAnalytics trackAppOpenedWithLaunchOptions:launchOptions]; } [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound]; return YES; }
3,若是远程消息发送过来的时候,app正在运行,这时候会发生什么呢?
app代理的application:didReceiveRemoteNotification:方法会被调用,同时远程消息中的payload数据会做为参数传递进去。
示例代码以下:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { if (application.applicationState == UIApplicationStateActive) { // 转换成一个本地通知,显示到通知栏,你也能够直接显示出一个alertView,只是那样稍显aggressive:) UILocalNotification *localNotification = [[UILocalNotification alloc] init]; localNotification.userInfo = userInfo; localNotification.soundName = UILocalNotificationDefaultSoundName; localNotification.alertBody = [[userInfo objectForKey:@"aps"] objectForKey:@"alert"]; localNotification.fireDate = [NSDate date]; [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; } else { [AVAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo]; } }
常见问题FAQ
1. 我能推送长消息吗?
不能,APNs限制了每一个notification的payload最大长度是256字节,超长的消息是不能发送的。
2. 推送怎么加声音提醒?
消息推送是能够指定声音的。譬如你能够对正面的反馈使用欢快的声音,对负面的反馈使用低沉一点的声音,均可以达到别出心裁让人眼前一亮的目的。
你须要先放一些aiff、wav或者caf音频文件到app的资源文件中,而后在推送的时候指定不一样的音频文件名就能够了。
3. 推送的Badge是怎么回事?
推送并不必定会致使应用图标上红色数字增长,是否显示这一数字,显示成多少,都取决于开发者本身。
在发送推送消息的时候,咱们能够选择是否递增这一数字;若是不选择这一项,那么消息推送并不会致使应用图标上红色数字的出现。
好,如今问题来了,这个数字若是搞出来了,怎么让它消失掉呢?
其实咱们只须要在任什么时候候设置 UIApplication.applicationIconBadgeNumber 属性为0,就可让这个数字消失掉。
通常咱们会选择在应用启动的时候(application:didFinishLaunchingWithOptions:方法中),或者干脆一点,在应用每次被切换到前台的时候(applicationWillEnterForeground:方法中),调用这一行代码,便可马上清除掉Badge数字了。
4. AVOS Cloud平台发出去的通知格式到底是什么样子的
对于每一条推送消息,都包含一个payload,一般是组成了一个JSON的Dictionary,这其中必不可少的是aps属性,它对应的value也是一个Dictionary,包含下面一些内容:
1)alert消息(文本或Dictionary)
2)应用图标上的红色数字
3)播放的声音文件名
在由推送激活的app打开事件中,application:didFinishLaunchingWithOptions:的options参数就是这个大的Dictionary对象。
{ aps = { alert = "hello, everyone"; badge = 2; sound = default; }; }
这里要注意的时alert部分,它的值能够是一个String(文本消息),也能够是一个JSON的Dictionary。当它是文本消息的时候,系统就会把这些文字显示到一个alertview中;若是它也是由一个JSON Dictionary组成的话,其格式以下:
* body
* action-loc-key
* loc-key
* loc-args
* launch-image
body部分就是alertView中将要展示出来的文本消息,loc-属性主要是用来实现本地化消息,launch-image只是app主bundle里的一个图片文件的名称,通常来讲咱们不指定这一属性。
5. 如何显示本地化的消息
有两种办法能够实现推送消息的本地化:
1)在推送的payload中使用loc-key和loc-args来指定进行本地化,这样Provider方只须要按照统一的格式来发送便可,消息的解析和组装则由客户端来完成。
2)若是推送的payload里面不包含loc-key/loc-args信息,那么Provider方就须要本身作本地化处理,而后给不一样的device发送不一样的消息,为了作到这一点,还须要app在上传device token的时候也把用户的语言设置信息传回来。
目前,由于AVOS Cloud主要就是瞄准中国大陆市场和海外中文用户,因此咱们在推送上还不提供多语言支持。
6. 应用该怎么响应推送消息
上面说的处理流程,只能简单展现一下远程消息,激活用户让他们从新回到app中来。可是有时候,咱们但愿带给用户更好的使用体验,譬如若是咱们告诉用户:张三刚刚评论了你的照片。这时候用户若是点击action按钮进入app,咱们是展现具体的评论页面为好,仍是展现一般的启动页面而后让用户本身去找张三的评论好?我想负责任的开发者都会选择前者。
要作到灵活响应不一样类型的通知消息,咱们须要在通知的payload中增长更多信息,而不能仅仅只有alert出来的文字信息。对于AVOS Cloud消息推送平台来说,就须要开发者使用更高级功能的JSON格式。譬如咱们发送这样的json字符串{"action":{"type":4},"alert":"hello, everyone”} 最终在app内会收到这样的UserInfo Dictionary:
{ action = { type = 4; }; aps = { alert = "hello, everyone"; badge = 4; }; }
“hello, everyone”会显示到alertView中,可是整个Dictionary会经过launchOptions传递给application: didFinishLaunchingWithOptions: 方法,这样咱们在程序里面就能够对不一样的消息实现不一样的跳转了。