Local and Remote Notification Programming Guide

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 action
acceptAction.identifier = @"ACCEPT_IDENTIFIER";
 
// Localized string displayed in the action button
acceptAction.title = @"Accept";
 
// If you need to show UI, choose foreground
acceptAction.activationMode = UIUserNotificationActivationModeBackground;
 
// Destructive actions display in red
acceptAction.destructive = NO;
 
// Set whether the action requires the user to authenticate
acceptAction.authenticationRequired = NO;

Group Action Into  a category

创建UIMutableUserNotificationCategory对象

// First create the category
UIMutableUserNotificationCategory *inviteCategory =
        [[UIMutableUserNotificationCategory alloc] init];
 
// Identifier to include in your push payload and local notification
inviteCategory.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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值