推送通知(远程推送)

来源:互联网 发布:windows没有视频设备 编辑:程序博客网 时间:2024/05/16 19:48

一、简介

1、概念

本地通知和推送通知是在没有运行在前台的应用程序可以让它们的用户或得相关消息通知的方式。消息通知可能是一条消息,即将发生的日历时间,或远程服务器的新数据。当被操作系统显示时,本地通知和推送通知看起来一样。它们也可以显示一个警告消息或在应用程序的图标上面现在一个徽标。它们也可以在警告窗或徽标显示时播放一段声音。

2、起源

推送通知(远程通知):是从其他设备上面到达的。它来自一个远程设备——应用程序的提供者——并在有新的消息需要查看或新的数据需要下载的时候被推送到本地设备上面的应用(通过苹果的推送通知服务——Apple Push Notafication service)。

3、理论

推送通知:应用程序必须接受通知并把它从操作系统获得的一个设备令牌环传递给它的通知提供者。
当操作系统发送一个推送通知(iOS或Mac OS X都支持)时,如果此时应用程序没有运行在前台,它将会显示通知(警告窗、图标徽标、声音)。如果显示一个通知警告窗并且用户轻击或单击动作按钮(或移动动作滑块),相应的应用程序将会加载启动并调用远程通知载体传递的相应方法。如果通知到达的时候应用程序正运行在前台,应用程序的委托接受一个推送通知。

4、苹果推送通知服务(APNS)

苹果推送通知服务(APNS)是推送通知的网关。其负责把通知消息传递到已经有应用注册监听这些通知的设备上面。每个设备和APNS建立一个认证和加密的IP连接,并接受这一持久连接的通知。当监听到有需要发送到这些客户端设备的通知到来时,通知提供者和APNS通过一个持久和安全的通道建立连接。当新的数据到达时,提供者准备并通过这条和APNS之间的通道把通知发送到设备,即把通知推送到目标设备上面。

5、推送通知获取授权

为了给提供者这边开发和配置推送通知,你必须从开发者中心(即苹果官网DevCenter)取得SSL授权证书。每个授权证书限制必须对应一个单独的应用,由应用的Bundle ID标识。而且授权证书也被限制用于以下两个环境之一,沙箱环境(用于开发和测试)和生产环境。这些环境都拥有自己的IP地址,而且需要它们自己的授权证书。你必须同时获得这些环境的配置文件(即Provisioning profiles)。

6、提供者和APNS之间的二进制接口通信

二进制接口是异步的,而且它使用TCP方式通过sock连接把二进制内容的推送通知发给APNS。沙箱和生产环境都有自己独立的接口,每个都有它自己的地址和端口。对于每个接口,你需要使用TLS(或SSL)和已经拿到的SSL授权证书来建立一条到APNS的安全通信通道。提供者把推送通知打包并通过该通道发送给APNS。

APNS包含了一个反馈服务,它负责维护每个应用的传递通知失败的设备列表(即APNS当前无法把推送通知传递到这些设备上面对应的应用)。提供者应该周期性的连接到反馈服务来查看推送失败的设备以便它可以把之前失败的通知重复发送过去。

二、推送通知深度

推送通知(远程通知):由应用的远程服务器(即提供者)发送给苹果推送服务(APNS),它负责把推送发送到该应用的设备上。在iOS和Mac OS X v10.7(Lion)之后都支持。

1、本地通知显示效果

在iOS上面,一个应用指定提示信息或徽标数字时也可以指定一个声音文件。该声音文件应该包含一个短的,有特色的声音。在iOS显示提示窗或图标上显示徽标的时候,它会播放该声音文件的声音来告知通知已经到达

通知提示消息可以只包含一个按钮。当动作按钮被取消,用户只隐藏该提示窗
Mac OS X 注意:当前在 Mac OS X 上面非运行的应用的可用推送消息类型仅为徽标。换而言之, 如果应用当前没有运行它只会在 Dock 里面相应的应用打上徽标。如果用户没有把应用的图标显 示在 Dock 上面,系统会自动的把应用图标插入到 Dock 里面以便它可以给它打上徽标(当程序再次退出的时候会从 Dock 里面自动删除)。运行的应用程序可能核查其他类型的通知载体(提示和 声音),并相应的处理它们 。

2、更多关于推送通知

推送通知服务器和桌面系统的后台应用很类似,但是它没有增加额外的消耗。对于当前没有正在运行的应用层程序,或者在iOS上的话即是没有运行在前台的应用程序,通知是间接发生的。操作系统接受一个应用程序的推送通知并提醒给用户。一旦用户提醒完成,用户可能选择加载启动应用程序,然后应用程序会从提供者上面下载最新的数据。如果一个应用程序在推送通知到来的时候正在运行,应用程序可以选择直接处理通知。

重要:在 iOS 上,Wi-Fi 仅在蜂窝网络无法连通或设备是 iPod touch 时才会用于推送通知。对于 一些通过 Wi-Fi 接收推送通知的设备,设备的显示器必须是开着的(也就是它不能处于休眠状态), 或者必须是插入的。相反,在 iPad 上当设备休眠的时候它仍然保持则 Wi-Fi 连接,所以仍然可以 传递推送通知。无线 Wi-Fi 唤醒任何传入主机的流量 。

三、调度、注册、处理通知

1、准备好自定义的警告声音

对于iOS上面的远程通知,你可以在显示某个应用的本地或远程通知时指定一个自定义的声音来播放。但是声音文件必须在客户端程序的主目录下面(即main bundle)。因为自定义的警告声音由iOS的声音系统设备播放,所以它必须是一下的任意格式的音频文件:

  • ①、Linera PCM;
  • ②、MA4(IMA/ADPCM);
  • ③、μLaw;
  • ④、aLaw。
    然后可以把音频文件打包为aiff、wav、或caf文件,在Xcode里边把声音文件添加到你的工程里面作为程序目录的一个并非本地化的资源。
    注意:自定义的声音文件播放时必须在30秒以内。如果一个自定义的声音文件播放超过30秒的限制,那将会被系统的声音替换

2、注册远程通知

一个应用程序必须在设备(iOS设备或Mac电脑)上面注册了苹果推送通知服务才能接收来自程序提供者的远程通知。

注册过程包括以下三个步骤:

  1. 程序调用registerForRemoteNotificationTypes:方法。
  2. 委托实现application:didRegisterForRemoteNotificationsWithDeviceToken:方法来接受设备令牌。
  3. 把设备令牌作为非对象(二进制值)传递给程序提供者。

应用程序应该在每次它启动的时候注册,并把最新获得的设备令牌发送给它的提供者。它通过调用 registerForRemoteNotificationTypes:方法来揭开注册的过程。此方法的参数需要一个UIRemoteNotificationType(在Mac OS X 上为NSRemoteNotificationType)位掩码,它指定应用程序希望得到的初始通知类型,比如图标数字、声音、但不包含警告信息等。在iOS上,之后用户可以在应用设置的通知中心修改已启用的通知类型。在iOS和Mac OS X上面,你可以通过调用enableRemoteNotificationTypes方法获得当前可用的通知类型。如果这些通知类型的任何一个不被启用,那么操作系统将不会标记图标数字,显示警告信息,或播放警告声音等,即使在通知负载里面已经指定了相应地内容。

如果注册成功,APNS会返回一个设备令牌给设备,iOS把令牌通过应用的委托方法application:didRegisterForRemoteNotificationsWithDeviceToken:返回。应用程序应该连接到它的提供者并把令牌作为二进制传递给它。如果在获取令牌的时候发生任何异常,操作系统将会通过调委托的:application:didFailToRegisterForRemoteNotificationsWithError方法来通知应用程序。该方法的参数NSError清晰的描述了错误的原因。

iOS注意:如果设备的蜂窝连接或Wi-Fi连接都不可用,则application:didRegisterForRemoteNotificationsWithDeviceToken:方法或application:didFailToRegisterForRemoteNotificationWithError:方法都不会调用。在Wi-Fi环境下,有时候发生在设备无法连接到APNS的端口5223.如果发生这样的情况的话,用户可以在iPhone,iPad等设备上面连接其他没有阻塞该端口的Wi-Fi网络,等待直到蜂窝数据服务可用。在任何一种情况下,连接成功的话,委托的任一个方法将会被调用。

通过程序每次启动的时候请求最新设备令牌并把令牌发送给它的提供者,你可以确保提供者拥有当前设备的可用令牌。如果用户恢复设备或电脑到不是为它创建的备份(比如,用户移动数据到一个新的设备或地电脑),那么他必须起码启动并加载一次应用程序一遍它可以再次接收远程通知。如果用户恢复备份数据到一个新的设备或电脑,或重新安装操作系统,设备的令牌都会改变。此外,不要缓存一个设备令牌并把她发送给提供者,要记住总是在你需要设备令牌的时候总是从操作系统获取最新的令牌。如果你的应用之前已经注册了通知,那么调用registerForRemoteNotificationTypes:的时候会立即返回设备的令牌给委托,而不会造成任何的额外负载。
实例1:

//开始注册- (void)applicationDidFinishLaunching:(UIApplication *)application{     [[UIApplication sharedApplication] registerForRemoteNotificationTypes:     (UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound)];}//注册成功- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{    //Token值成功获取的时候走的是这个方法(Token值不能带空格)    const void *devTokenBytes = [deviceToken bytes];    //sendProviderDeviceToken是一个由客户端创建的假象方法,在它里面连接提供者,并把设备令牌发给提供者    //self.registered = YES;    //[self sendProviderDeviceToken:devTokenBytes];}//注册失败- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{    NSLog(@"Error in redistration. Error:%@",error);}

3、处理远程通知

  • (1)、无论应用是否运行在前台,通知都会被提供。在这种情况下,系统展示通知,显示一个警告,在图标上面显示数字,可能播放一个声音。
  • (2)、通知展示的结果是,用户点击警告窗口的动作按钮或点击应用程序的图标。如果运行iOS的设备应用程序的图标被点击,该应用程序会调用相同的方法,但是不会提供任何关于通知的信息。
  • (3)、当应用运行在前台的时候,通知被提交。应用程序调用它委托的application:didReceiveRemoteNotification:方法(对于远程通知而言),并传递通知的负载给方法的参数。

应用程序可以使用传递进来的远程通知负载帮助设置上下处理和通知相关项目。理想情况下,任何时候每个平台上面的委托处理由远程和本地通知传递的所有信息。

  • ①、对于Mac OS X,它应该通过NSApplicationDelegate协议,并实现applicationDidFinishLaunching:方法和application:didReceiveRemoteNotification:方法。
  • ②、对于iOS,它必须通过UIApplicationDelegate,并实现application:didFinishLaunchingWithOptions:方法和application:didReceiveRemoteNotification:方法。

iOS注意:在iOS上,你可以通过确定应用程序的状态来确定是否是应用程序由于用户点击了动作按钮而启动,或通知被提交给已经运行的应用。通过委托实现application:didReceiveRemoteNotification:,获取应用程序的applicationState属性值并判定它。如果值为UIApplicationStateInaction,表明用户单击了动作按钮。如果值为UIApplicationStateAction,表明应用收到此通知的时候已经运行在前台。

实例2:

实现对远程通知的处理和本地通知类似,唯一的区别是你使用一个在每个平台上面已经定义的常量来访问远程通知的负载:

  • ①、在iOS平台上,委托在它的application:didFinishLaunchingWithOptions:方法里面使用UIApplicationLaunchOptionsRemoteNotificationKey来加载选项字典里面获取远程通知的负载。
  • ②、在Mac OS X平台上面,委托在它的applicationDidFinishLaunching:方法的实现里面,使用NSApplicationLaunchRemoteNotificationKey来访问NSNotification对象的userInfo字典里面的负载字典。

负载本身是一个NSDictionary对象,包含了通知的元素——警告语,标记数字,声音等等。它同样也包含了自定义数据,程序可以使用这些自定义数据来设置用户界面的初始化情况。

//应用程序处在打开状态,且服务器有推送消息过来时,以及通过推送打开应用程序,走的是这个方法-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{    for (id key in userInfo) {        NSLog(@"%@:%@",key, [userInfo objectForKey:key]);    }    //Icon推送数量设为0    //application.applicationIconBadgeNumber=0;}//应用程序不处在后台,且通过推送通知打开的时候,如果需要推送下来相关的信息可以在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{    //这里处理应用程序如果没有启动,但是是通过通知消息打开的,此时可以获取到消息.    if (launchOptions != nil) {        NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];        [self PMD_uesPushMessage:userInfo];    }    return YES;}-(void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler{    //在没有启动本App时,收到服务器推送消息,下拉消息会有快捷回复的按钮,点击按钮后调用的方法,根据identifier来判断点击的哪个按钮}
aps =     {    alert = "\U4f60\U597d\Uff0c\U8f66\U6613\U62cd";    badge = 0;    category = "$\U7531\U5ba2\U6237\U7aef\U5b9a\U4e49";    "content-available" = 1;    sound = default;};
0 0
原创粉丝点击