Local and Remote Notification Programming Guide

来源:互联网 发布:java重装机兵机甲咆哮 编辑:程序博客网 时间:2024/06/04 08:59

Apple文档:文档

如果app在前台运行,当收到本地or远程通知的时候,app代理方法application:didReceiveRemoteNotification: 或者application:didReceiveLocalNotification:方法将会被调用. 如果app不在前台或者没有运行,可以在app代方法application:didFinishLaunchingWithOptions: 中通过options dictionary 中的UIApplicationLaunchOptionsLocalNotificationKey 或者 UIApplicationLaunchOptionsRemoteNotificationKey 这两个键来处理通知. 

本地通知

本地通知是 UILocalNotification 或者 NSUserNotification 的一个实例,有三种主要的属性:

  • scheduled time,时间周期,用来指定iOS系统发送通知的日期和时间,例如fire date;
  • notification type,通知类型,包括警告信息、动作按钮的标题、应用图标上的badge(数字标记)和播放的声音,在iOS8后还可以包括custom actions;
  • Custom data,本地通知可以包含一个dictionary类型的本地数据。

注册通知类型

在iOS8及以后,apps使用本地or远程通知时必须注册通知的类型。使用 UIApplication 的 registerUserNotificationSettings: 方法来注册通知类型。

UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];[[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];

注意上述代码中的categories参数. 一个category是一组与一个通知结合在一起的,可显示的actions 。

在第一次调用registerUserNotificationSettings:方法时,会弹出一个dialog,让用户允许使用通知。当用户做出回应后,iOS会异步的调用 UIApplicationDelegate 的 application:didRegisterUserNotificationSettings: 方法,UIUserNotificationType对象会显示用户允许的通知类型。因为用户能随时的更改初始设置,在展示一个通知之前,调用currentUserNotificationSettings方法来做一些准备工作。

在iOS8及以后,registerUserNotificationSettings: 方法对本地和远程通知都适用。在iOS8中registerForRemoteNotificationTypes:方法被deprecated。

安排本地通知
在iOS中, 创建 UILocalNotification 对象,使用UIApplication的 scheduleLocalNotification:方法来安排和发送通知。在iOS中,创建和发送通知,需遵循如下的步骤:

1.在iOS8以及,先注册通知类型,如上。如果已经注册,则调用 currentUserNotificationSettings 方法来得到用户允许app的通知类型。

2.创建并初始化UILocalNotification对象。

3.设置系统发送通知的date和time,通过属性fireDate

4.配置警告信息、应用图标上的badge(数字标记)和播放的声音

  • 警告信息:alertBody 属性警告的信息,alertAction 设置action 按钮或者slider的标题。
  • badge:applicationIconBadgeNumber 设置badge。
  • 声音:soundName属性。系统默认的声音是UILocalNotificationDefaultSoundName

5.可选,使用userInfo属性,来附加上自定义的数据。

6.可选,在iOS8及以后,可以自定义action,来与用户交互。

7.安排并发送通知。

通过scheduleLocalNotification:方法来安排一个通知,app使用UILocalNotification对象的fireDate属性来指定推送的时刻。使用presentLocalNotificationNow: 方法来立即推送。

- (void)scheduleNotificationWithItem:(ToDoItem *)item interval:(int)minutesBefore {    NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];    NSDateComponents *dateComps = [[NSDateComponents alloc] init];    [dateComps setDay:item.day];    [dateComps setMonth:item.month];    [dateComps setYear:item.year];    [dateComps setHour:item.hour];    [dateComps setMinute:item.minute];    NSDate *itemDate = [calendar dateFromComponents:dateComps];     UILocalNotification *localNotif = [[UILocalNotification alloc] init];    if (localNotif == nil)        return;    localNotif.fireDate = [itemDate dateByAddingTimeIntervalInterval:-(minutesBefore*60)];    localNotif.timeZone = [NSTimeZone defaultTimeZone];     localNotif.alertBody = [NSString stringWithFormat:NSLocalizedString(@"%@ in %i minutes.", nil),         item.eventName, minutesBefore];    localNotif.alertAction = NSLocalizedString(@"View Details", nil);     localNotif.soundName = UILocalNotificationDefaultSoundName;    localNotif.applicationIconBadgeNumber = 1;     NSDictionary *infoDict = [NSDictionary dictionaryWithObject:item.eventName forKey:ToDoItemKey];    localNotif.userInfo = infoDict;     [[UIApplication sharedApplication] scheduleLocalNotification:localNotif];}


可以通过cancelLocalNotification: 方法来取消某个特定的通知,通过cancelAllLocalNotifications方法来取消所有的通知。


远程通知注册

app必须注册苹果推送服务(APNs)来接收由app推送方发出的远程的通知。在iOS8及以后,注册有4步:

1.注册app支持的通知类型,使用registerUserNotificationSettings:方法。

2.调用registerForRemoteNotifications方法,来注册接收通过APNs推送的通知。

3.成功注册后,在app的代理中保存设备的token,或者优雅的处理注册失败。

4.把设备的token提供给app的推送方。

(在iOS7, 使用UIApplication的registerForRemoteNotificationTypes: 方法,来代替前两步。在OS X中,通过调用NSApplication的registerForRemoteNotificationTypes:方法来代替)。步骤如下图所示:

设备的token能被改变,因此app在每次加载时都要注册。

如果注册成功,APNs返回一个设备的token到设备,iOS把这个token传递到app代理的application:didRegisterForRemoteNotificationsWithDeviceToken:方法中。app传递的token,是二进制编码的,来提供给provider。如果在获取token的过程中,出现了问题,操作系统会调用代理的application:didFailToRegisterForRemoteNotificationsWithError:方法(在OS X中会调用application:didFailToRegisterForRemoteNotificationsWithError: 方法)。方法中的这个NSError对象,描述了错误的原因。这个错误可能是,例如:一个错误的aps-environment值,在配置概要文件中。你应该视错误为一个短暂的状态,而不是试图解析它。

iOS注意:如果移动蜂窝网或者Wi-Fi连接不可用,application:didRegisterForRemoteNotificationsWithDeviceToken: 或者application:didFailToRegisterForRemoteNotificationsWithError:将会被调用。对于Wi-Fi连接,出现这种状况有时是因为设备不能通过APNs的5223端口来连接。如果出现这种情况,用户可以切换到另一个不会阻塞这个端口的Wi-Fi网络。在其他的情况,设备是应该能连接上的,上述代理中的一个将会被调用。

每次app加载的时候,请求设备token,并把它传递给provider。确保provider拥有设备当前的token。否则,推送方可能不会找到用户的设备。如果用户恢复设备或电脑备份,此备份并不是其对应创建的备份(例如,用户数据迁移到新的设备或电脑),用户必须至少一次启动应用程序以再次接收通知。如果用户给新的设备或者电脑恢复备份的数据,或者重装操作系统,设备的token将会改变。而且,一定不要缓冲一个设备token,让后把它提供个provider。无论何时永远要从系统获取token。如果app以前注册过,调用registerForRemoteNotifications方法会使操作系统把设备的token立即传递个代理,不会有额外的开销。另外也要注意在任何时候,设备的token变化的时候,代理方法可能会被调用,并不仅仅是app注册或者再次注册时。

下面的例子,展示了如何在iOSapp中注册远程通知,对于Mac app也类似:

- (void)applicationDidFinishLaunching:(UIApplication *)app {   // other setup tasks here....    UIUserNotificationType types = UIUserNotificationTypeBadge |                 UIUserNotificationTypeSound | UIUserNotificationTypeAlert;     UIUserNotificationSettings *mySettings =                [UIUserNotificationSettings settingsForTypes:types categories:nil];     [[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];    [app.registerForRemoteNotifications];} // Delegation methods- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {    const void *devTokenBytes = [devToken bytes];    self.registered = YES;    [self sendProviderDeviceToken:devTokenBytes]; // custom method} - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {    NSLog(@"Error in registration. Error: %@", err);}

在 application:didFailToRegisterForRemoteNotificationsWithError:中,你需要合理的处理错误,取消app接收远程通知相关的逻辑。


处理本地和远程通知

让我们回顾下,当系统分发一个本地或者远程的通知时可能出现的场景。

通知被发送时app没在前台运行。在这种情况下,系统展示通知,显示alert,icon上的badge,也许还会播放声音,可能还会显示一个多个action按钮。

在iOS8的通知中,用户点击自定义的action按钮,iOS调用application:handleActionWithIdentifier:forRemoteNotification:completionHandler: 或者 application:handleActionWithIdentifier:forLocalNotification:completionHandler: 方法。在两个方法中,可以得到action的标示符,因此可以知道哪个button被用户点击。也可以得到通知的对象,用来得到处理action的信息。

用户点击alert上button或者app的图标。如果默认的action按钮被点击(在iOS的设备上),系统会加载app,app调用代理方法,application:didFinishLaunchingWithOptions: 传递通知负载(远程通知)or 本地通知对象(本地通知)。虽然application:didFinishLaunchingWithOptions:方法并不是处理通知的最好的地方,但是这让你有机会在处理方法被调用之前来开始更新process。

如果通知是远程的,系统也会调用application:didReceiveRemoteNotification:fetchCompletionHandler: 方法。

如果在OS X上点击了app图标,app会调用代理的applicationDidFinishLaunching: 方法,在这个方法中可以包含一个远程通知的payload。如果在iOS上app图标被点击,app也会调用同样的方法,但是没有提供关于通知的信息。

通知发送时app在前台运行。app调用UIApplicationDelegate 的application:didReceiveLocalNotification: 或者 application:didReceiveRemoteNotification:fetchCompletionHandler: 方法(如果application:didReceiveRemoteNotification:fetchCompletionHandler: 方法没实现,系统会调用application:didReceiveRemoteNotification:)在OS X中,系统会调用application:didReceiveRemoteNotification:方法。

app能使用传递过来的远程通知的payload,或者在iOS中,使用UILocalNotification对象来帮助设置处理与通知有关的context。理想情况下,代理方法会如下处理远程或者本地的通知,根据不同的平台:

  • 对于OS X,代理应该采用NSApplicationDelegate协议,实现application:didReceiveRemoteNotification: 方法。
  • 对于iOS,代理应该采用UIApplicationDelegate协议,实现application:didReceiveRemoteNotification:fetchCompletionHandler: 或者application:didReceiveLocalNotification:方法。处理通知的actions,实现application:handleActionWithIdentifier:forLocalNotification:completionHandler: 或者application:handleActionWithIdentifier:forRemoteNotification:completionHandler: 方法。

下面的例子,使用application:didFinishLaunchingWithOptions:方法来处理一个本地的通知。通过UIApplicationLaunchOptionsLocalNotificationKey 得到 UILocalNotification 对象。

- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    UILocalNotification *localNotif =        [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];    if (localNotif) {        NSString *itemName = [localNotif.userInfo objectForKey:ToDoItemKey];        [viewController displayItem:itemName];  // custom method        app.applicationIconBadgeNumber = localNotif.applicationIconBadgeNumber-1;    }    [window addSubview:viewController.view];    [window makeKeyAndVisible];    return YES;}

远程通知也类似,除了你将会用到一个特别声明的常量在不同的平台上,用来作为一个key来得到通知的payload。

  • iOS, 代理对象实现application:didFinishLaunchingWithOptions: 方法, 使用 UIApplicationLaunchOptionsRemoteNotificationKey 键
  • OS X, 代理对象实现 applicationDidFinishLaunching: method, 使用 NSApplicationLaunchRemoteNotificationKey 键

下面的代码,当app运行在前台时,调用application:didReceiveLocalNotification: 方法 

- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif {    NSString *itemName = [notif.userInfo objectForKey:ToDoItemKey];    [viewController displayItem:itemName];  // custom method    app.applicationIconBadgeNumber = notification.applicationIconBadgeNumber - 1;}

如果你想要app,在前台正在运行时来捕获远程的通知,app代理需实现如下的方法application:didReceiveRemoteNotification:fetchCompletionHandler:。


在iOS中使用通知Actions

OS X 和 早于iOS8的iOS中,通知只有一个默认的action。在iOS8及以后,通知可以有额外的自定义的actions。两个actions能显示在锁屏的界面上,在banner上,和在通知中心上。在modal alert,通知可以显示最多四个action,供用户点击。在程序中使用通知actions,需要注册actions,安排本地通知或者推送远程通知,处理用户选择的action。

注册通知actions

为了使用通知actions,你必须定义actions,把它们放在categories组中,然后使用UIApplication注册。

为了定义一个通知action,首先必须创建并初始化一个通知action,一般是UIMutableUserNotificationAction。然后定义一个标示符,然后设置activation 模式。

UIMutableUserNotificationAction *acceptAction =            [[UIMutableUserNotificationAction alloc] init]; // Define an ID string to be passed back to your app when you handle the actionacceptAction.identifier = @"ACCEPT_IDENTIFIER"; // Localized string displayed in the action buttonacceptAction.title = @"Accept"; // If you need to show UI, choose foregroundacceptAction.activationMode = UIUserNotificationActivationModeBackground; // Destructive actions display in redacceptAction.destructive = NO; // Set whether the action requires the user to authenticateacceptAction.authenticationRequired = NO;

Group Action Into a category

创建UIMutableUserNotificationCategory对象

// First create the categoryUIMutableUserNotificationCategory *inviteCategory =        [[UIMutableUserNotificationCategory alloc] init]; // Identifier to include in your push payload and local notificationinviteCategory.identifier = @"INVITE_CATEGORY"; // Add the actions to the category and set the action context[inviteCategory setActions:@[acceptAction, maybeAction, declineAction]    forContext:UIUserNotificationActionContextDefault]; // Set the actions to present in a minimal context[inviteCategory setActions:@[acceptAction, declineAction]    forContext:UIUserNotificationActionContextMinimal];

注册Actions

NSSet *categories = [NSSet setWithObjects:inviteCategory, alarmCategory, ... UIUserNotificationSettings *settings =       [UIUserNotificationSettings settingsForTypes:types categories:categories]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings];

0 0