iOS 通知 Notification

iOS 通知 Notification

参考资料 :

前言

最近项目需要对交易H5下载进行优化,根据资料查找,iOS7以前大家大多使用无声播放来保证APP在后台继续运行,iOS7需要使用NSURLSession替换NSURLConnection,并且使用NSURLSessionTask添加后台下载功能,解决不管是前台还是后台都能正常的下载完成。那么结合后台下载,需要使用本地通知来告知用户下载结束情况,优化用户的体验。

iOS 通知

1. 远程通知 APNs

2. 本地通知 LocalNotification

远程通知,就是苹果的推送服务APNs(APP Push Notification Service):

苹果的APNs允许设备和苹果的推送通知服务器保持连接,支持开发者推送消息给用户设备对应的应用程序。

远程推送原理

image

远程推送步骤

  1. 注册:为应用程序申请消息推送服务。此时你的设备会向APNs服务器发送注册请求。
  2. APNs服务器接受请求,并将deviceToken返给你设备上的应用程序
  3. 客户端应用程序将deviceToken发送给后台服务器程序,后台接收并储存。
  4. 后台服务器向APNs服务器发送推送消息
  5. APNs服务器将消息发给deviceToken对应设备上的应用程序

推送服务支持

想要收到推送消息,就必须要有后台服务器向APNs的服务器发请求。 1. 公司自己开发后台服务器程序 2. 采用第三方的后台服务程序,比如:百度云推送、极光推送、友盟推送

代码实现

1. 注册远程推送
// 设置要注册的通知类型,iOS8以后配置授权
    if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
        UIUserNotificationType type = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    } else {
        // 如果是iOS8以前,设置要注册的通知类型
        UIRemoteNotificationType type = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:type];
    }
2. 远程推送注册完毕, 服务器返回Token时, 调用此方法,把Token传给本地或者三方推送服务器(极光等)
/**
 *  应用程序注册APNS消息推送,获取devicetoken,然后应用程序将devicetoken发送给程序的PUSH服务端程序
 *
 *  @param application
 *  @param deviceToken
 */
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"Device Token: %@", deviceToken);
    [self saveDeviceToken:deviceToken];
    [KDS_PushService registerDeviceToken:deviceToken];
}

/**
 *  注册APNS失败
 *
 *  @param application
 *  @param error
 */
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}
3. 服务端程序向APNS服务发送消息, APNS服务将消息发送给iPhone应用程序
/**
 *  服务端程序向APNS服务发送消息, APNS服务将消息发送给iPhone应用程序
 *
 *  @param application
 *  @param userInfo    推送收到消息
 */
//如果App状态为正在前台或者后台运行,将调用此函数,可通过AppDelegate中的applicationState是否为UIApplicationStateActive 判断程序是否在前台运行
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
#ifdef  __SUPPORT__KDS__PUSH
#else
    // 处理推送消息
    [KDS_PushService handleRemoteNotification:userInfo];
    NSLog(@"收到通知:%@", [self receivePushMessage:userInfo]);
#endif
}

/**
 *  App在运行时收到推送消息
 *
 *  @param application
 *  @param userInfo          消息内容
 *  @param completionHandler
 */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
#ifdef __SUPPORT__KDS__PUSH
    //    [KDS_PushService handleRemoteNotification:userInfo];
    [self kds_webSocketDidReceivePushMessage:userInfo];
#else
    [KDS_PushService handleRemoteNotification:userInfo];
    
    //保存未读信息
    KDS_MessagePushRes *res = [[KDS_MessagePushRes alloc] init];
    [res unpackInforPushDataWithDictionary:userInfo];
    
    if (res.newsId) {
        [KDS_WarnPushManager saveUnReadMessage:res.newsId];
    }
    NSLog(@"收到通知:%@", [self receivePushMessage:userInfo]);
    
#endif
    completionHandler(UIBackgroundFetchResultNewData);
}

本地通知

1. iOS10 以前UILocalNotification本地通知

2. iOS10 以后UserNofications框架本地通知

UILocalNotification本地通知

简介

In iOS 8.0 and later, your application must register for user notifications using -[UIApplication registerUserNotificationSettings:] before being able to schedule and present UILocalNotifications

在 iOS8上,APP必须使用UIApplication registerUserNotificationSettings:]注册本地通知,才能得到授权

UILocalNotification(本地推送通知),是通知的一种,属于UIKit。它是一种基于时间行为的通知形式,系统能在具体的时间触发它,而不用app来触发。本地通知触发后,会显示在通知中心中,并根据配置,显示横幅和播放声音,然后再对应的app的icon上显示通知的条数。

本地推送通知在项目中的运用很有特点,大多都和时间相关。如:备忘录、闹钟(自定义闹钟)、生日提醒等等。

如果实现了通知,用户在第一次打开app的时候,会提示是否打开通知,如果用户选不允许,就不能使用通知这个功能,除非用户去设置中再次进行设置。虽然本地通知能够提示用户来使用app,但是也不要频繁的通知,对本地通知的数量限制是最多数量64个。超过限制的本地通知将被iOS忽略。

UILocalNotification的详解

UILocalNotification的属性有fireDate、timeZone、repeatInterval、repeatCalendar、alertBody、alertAction、hasAction、alertLaunchImage、applicationIconBadgeNumber、soundName和userInfo。

  • 调度本地通知 设置通知出发时间
// timer-based scheduling
@property(nullable, nonatomic,copy) NSDate *fireDate;
//例如
notification.fireDate=[NSDate dateWithTimeIntervalSinceNow:10.0];//通知触发的时间,10s以后  
  • 设置本地时区
@property(nonatomic, copy) NSTimeZone *timeZone  
//例如
notification.timeZone = [NSTimeZone defaultTimeZone]; // 使用本地时区    
  • 设置重复间隔 @property(nonatomic) NSCalendarUnit repeatInterval //例如 notification.repeatInterval = kCFCalendarUnitDay; repeatInterval是UILocalNotification被重复激发之间的时间差,不过时间差是完全根据日历单位(NSCalendarUnit)的,例如每周激发的单位,NSWeekCalendarUnit,如果不设置的话,将不会重复激发。 其主要的值有: 具体可以查看 CFCalendar Reference
NSCalendarUnitEra                = kCFCalendarUnitEra,  
NSCalendarUnitYear               = kCFCalendarUnitYear,  
NSCalendarUnitMonth              = kCFCalendarUnitMonth,  
NSCalendarUnitDay                = kCFCalendarUnitDay,  
NSCalendarUnitHour               = kCFCalendarUnitHour,  
NSCalendarUnitMinute             = kCFCalendarUnitMinute,  
NSCalendarUnitSecond             = kCFCalendarUnitSecond,  
NSCalendarUnitWeekday            = kCFCalendarUnitWeekday,  
NSCalendarUnitWeekdayOrdinal     = kCFCalendarUnitWeekdayOrdinal, 
  • 重复激发所使用的日历单位需要参考的日历
@property(nonatomic, copy) NSCalendar *repeatCalendar  
  • 设置出发通知的地理区域
@property(nonatomic, copy) CLRegion *region 
  • 构成推送的内容,推送文字内容
@property(nonatomic, copy) NSString *alertBody  
  • 锁屏时显示的滑块slide to后面的文字内容
@property(nonatomic, copy) NSString *alertAction  
  • 推送内容的短描述
@property(nonatomic, copy) NSString *alertTitle  
  • 是否显示控制按钮
@property(nonatomic) BOOL hasAction 
  • 送提醒加载的图片
@property(nonatomic, copy) NSString *alertLaunchImage  
  • 推送组类别的名称
@property(nonatomic, copy) NSString *category  
  • 配置通知的其他部分,设置应用程序右上角的提醒个数
@property(nonatomic) NSInteger applicationIconBadgeNumber  
  • 通知声音
@property(nonatomic, copy) NSString *soundName  
  • 设置通知用户信息
@property(nonatomic, copy) NSDictionary *userInfo  

UILocalNotification本地通知代码实现

1. 创建本地推送,设置属性
例如
- (void)initLocalNotification {
    self.localNotification = [[UILocalNotification alloc] init];
    self.localNotification.fireDate = [[NSDate date] dateByAddingTimeInterval:5];
    self.localNotification.alertAction = nil;
    self.localNotification.soundName = UILocalNotificationDefaultSoundName;
    self.localNotification.alertBody = @"下载完成了!";
    self.localNotification.applicationIconBadgeNumber = 1;
    self.localNotification.repeatInterval = 0;
}
2. 注册授权
// ios8后,需要添加这个注册,才能得到授权
    if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        UIUserNotificationType type =  UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type
                                                                                 categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        // 通知重复提示的单位,可以是天、周、月
        self.localNotification.repeatInterval = 0;
    } else {
        // 通知重复提示的单位,可以是天、周、月
        self.localNotification.repeatInterval = 0;
    }
3. 执行调度
//在规定的日期触发通知  
   [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
//在有些时候,应用可能需要直接激发一个Notification而不是等一段时间在激发,应用可以以下的方式直接触发已设好的通知
   [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
4. 处理UILocalNotification
//在提醒框动作按钮被点击后,应用开始运行时,可以在-(BOOL)application:didFinishLaunchingWithOptions:这个Application delegate方法中处理。可以通过以下方式来加载为最近未处理的Notification
   UILocalNotification * localNotif=[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
//如果应用正在运行时,可以通过覆盖在Application Delegate中的方法-(void)application:didReceiveLocalNotification:来处理Notification。作为方法的第二个参数为UILocalNotification对象,只需处理对象携带的userInfo来处理响应的动作。
5. 取消UILocalNotification
//可以使用以下两个方式来取消一个已经登记的Notification,第一个方式可以直接取消一个指定的Notification,第二个方式将会把该应用已登记的Notification一起取消
   [[UIApplication sharedApplication] cancelLocalNotification:localNotification];
   [[UIApplication sharedApplication] cancelAllLocalNotification];

UserNofications框架本地通知

在iOS10上,苹果将原来散落在UIKit中各处的用户通知相关的代码进行重构,剥离,打造了一个全新的通知框架-UserNotifications。在此基础上,Apple 还增加了撤回单条通知,更新已展示通知,中途修改通知内容,在通知中展示图片视频,自定义通知 UI 等一系列新功能,非常强大。

Notification 历史和现状

碎片化时间是移动设备用户在使用应用时的一大特点,用户希望随时拿起手机就能查看资讯,处理事务,而通知可以在重要的事件和信息发生时提醒用户。完美的通知展示可以很好地帮助用户使用应用,体现出应用的价值,进而有很大可能将用户带回应用,提高活跃度。正因如此,不论是 Apple 还是第三方开发者们,都很重视通知相关的开发工作,而通知也成为了很多应用的必备功能,开发者们都希望通知能带来更好地体验和更多的用户。

但是理想的丰满并不能弥补现实的骨感。自从在 * iOS 3 引入 Push Notification 后,之后几乎每个版本 Apple 都在加强这方面的功能。我们可以回顾一下整个历程和相关的主要 API:

  • iOS 3 - 引入推送通知 UIApplication 的 registerForRemoteNotificationTypes 与 UIApplicationDelegate 的 application(:didRegisterForRemoteNotificationsWithDeviceToken:),application(:didReceiveRemoteNotification:)
  • iOS 4 - 引入本地通知 scheduleLocalNotification,presentLocalNotificationNow:, application(_:didReceive:)
  • iOS 5 - 加入通知中心页面
  • iOS 6 - 通知中心页面与 iCloud 同步
  • iOS 7 - 后台静默推送 application(_:didReceiveRemoteNotification:fetchCompletionHandle:)
  • iOS 8 - 重新设计 notification 权限请求,Actionable 通知 registerUserNotificationSettings(:),UIUserNotificationAction 与 UIUserNotificationCategory,application(:handleActionWithIdentifier:forRemoteNotification:completionHandler:) 等
  • iOS 9 - Text Input action,基于 HTTP/2 的推送请求 UIUserNotificationActionBehavior,全新的 Provider API 等

UserNotifications 框架解析

首先,对于通知框架,其框架功能包括以下四类

  • 申请权限/注册配置
  • 发送本地通知
  • 展示和响应本地/远程通知
  • App Extension

在UserNotifications框架中,最核心的类是UNUserNotificationCenter,这个类的是这三项功能的管理类,通过注入到currentNotificationCenter进行对消息的管理。而在之前,大部分操作的管理者UIApplication的单例。

申请权限/注册配置

iOS 8 之前,本地推送 (UILocalNotification) 和远程推送 (Remote Notification) 是区分对待的,应用只需要在进行远程推送时获取用户同意。iOS 8 对这一行为进行了规范,因为无论是本地推送还是远程推送,其实在用户看来表现是一致的,都是打断用户的行为。因此从 iOS 8 开始,这两种通知都需要申请权限。iOS 10 里进一步消除了本地通知和推送通知的区别。向用户申请通知权限非常简单:

[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:... completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            //...如果被授权了
        }
}];
//同时,增加一个callback将授权后的状态返回,就像分散型网络请求一般。

第一次调用这个方法时,会弹出一个系统弹窗。 image 要注意的是,一旦用户拒绝了这个请求,再次调用该方法也不会再进行弹窗,想要应用有机会接收到通知的话,用户必须自行前往系统的设置中为你的应用打开通知,如果不是杀手级应用,想让用户主动去在茫茫多 app 中找到你的那个并专门为你开启通知,往往是不可能的。因此,在合适的时候弹出请求窗,在请求权限前预先进行说明,以此增加通过的概率应该是开发者和策划人员的必修课。相比与直接简单粗暴地在启动的时候就进行弹窗,耐心诱导会是更明智的选择。

对于远程通知,还需要一个获取用户token的操作,并使用这个token进行APNs推送。但是奇怪的是,对于申请token这个操作,新框架中却没有对应的Api,沿用旧的Api。

[[UIApplication sharedApplication] registerForRemoteNotifications];
 
//AppDelegate
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
  ....
}
配置Category并注册

对于Category的作用,上文已经有介绍,而Category中目前主要的功能,是对应一组按钮操作。

Category的使用分四步

  1. 创建Category,设置identifer,配置一组按钮(可无)
  2. 将Category注册到UIApplication(旧)/UNNotificationCenter(新)中
  3. 发送本地或远程消息时需要按钮或自定义视图时带上对应的categoryIdentifer
  4. 收到消息进行响应时通过消息中携带的categoryIdentifer进行分类,可以指定不同的操作

旧框架中按钮动作对象UIUserNotificationAction和新的UNNotificationAction差异性不大,主要关心的是

  • 按钮上显示的文字
  • 按钮的identifer,用于区分按钮
  • 是否需要跳转到前台,唤起主App

而差异性在于

  • 旧框架分为可变对象和不可变对象,新框架只有不可变对象加上实例化方法
  • 新框架中,对于可输入操作的按钮,拆分成一个子类,可以使输入操作自定义性和拓展性更强
//新建一个按钮:
UNNotificationAction *callDriverAction = [UNNotificationAction actionWithIdentifier:@"xxx" title:@"呼叫司机" options:UNNotificationActionOptionForeground];
//调用setNotificationCategories方法注册
[[UNUserNotificationCenter currentNotificationCenter]setNotificationCategories:[NSSet setWithObject:self.category]];

在运行app时,原来的set里的categories并不会清空,所以需要将整个Set传进去作为参数,这样会把原来的set完整替换成新的set。每次调用时,整个set替换原来的set。 同时,对于通知设置和Category设置,拆分了两个Api去获取当前的设置。

- (void)getNotificationCategoriesWithCompletionHandler:(void(^)(NSSet *categories))completionHandler;
 
- (void)getNotificationSettingsWithCompletionHandler:(void(^)(UNNotificationSettings *settings))completionHandler;
发送本地通知

在iOS10以前,本地通知的类用的是UILocalNotification。而在UserNotifications框架中,将本地通知和远程通知统一起来,然后将通知拆分成request=content(内容)+trigger(触发器)的模式,十分像网络请求的思路。

1. UNNotificationContent

定制方法如下:

//Local Notification
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = @"Introduction to Notifications";
content.subtitle = @"Session 707";
content.body = @"Woah! These new notifications look amazing! Don’t you agree?";
content.badge = @1;

//Remote Notification
{
"aps" : {
    "alert" : { 
         "title" : "Introduction to Notifications", 
         "subtitle" : "Session 707",         
         "body" : "Woah! These new notifications look amazing! Don’t you agree?"
                },
    "badge" : 1
        },
}
2. UNNotificationTrigger
//2 分钟后提醒
UNTimeIntervalNotificationTrigger *trigger1 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:120 repeats:NO];

//每小时重复 1 次喊我喝水
UNTimeIntervalNotificationTrigger *trigger2 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:3600 repeats:YES];

//每周一早上 8:00 提醒我给老婆做早饭
NSDateComponents *components = [[NSDateComponents alloc] init];
components.weekday = 2;
components.hour = 8;
UNCalendarNotificationTrigger *trigger3 = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES];

//#import <CoreLocation/CoreLocation.h>
//一到麦当劳就喊我下车
CLRegion *region = [[CLRegion alloc] init];
UNLocationNotificationTrigger *trigger4 = [UNLocationNotificationTrigger triggerWithRegion:region repeats:NO];
3. UNNotificationRequest
NSString *requestIdentifier = @"sampleRequest";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifier
                                                                          content:content
                                                                          trigger:trigger1];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {

}];
展示和响应

iOS10 以前分为三类: * 收到通知 * 点击通知本身 * 点击通知的自定义按钮

收到通知

在触发本地通知时,App并不会被唤醒,所以本地只有前台时才有回调。

  • 本地+前台-didReceiveLocalNotification
  • 远程+前台-didReceiveRemoteNotification和didReceiveRemoteNotification:fetchCompletionHandler若有后面则只执行后面那个
  • 远程+后台-唤醒并执行didReceiveRemoteNotification:fetchCompletionHandler
点击通知本身
  • 本地+App存活-didReceiveLocalNotification
  • 本地+App未存活--(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions,其中lanchOptions中UIApplicationLaunchOptionsLocalNotificationKey为UILocalNotification对象
  • 远程+App存活-didReceiveRemoteNotification和didReceiveRemoteNotification:fetchCompletionHandler若有后面则只执行后面那个
  • 远程+App未存活-didReceiveRemoteNotification:fetchCompletionHandler有则执行,无则-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions,其中lanchOptions中UIApplicationLaunchOptionsRemoteNotificationKey 为通知的userInfo
点击自定义按钮
  • iOS9handleActionWithIdentifier,有responseInfo后缀的优先调,无则调用无后缀的
  • iOS8调用无后缀的

iOS 10 新框架单纯拆分为收到消息+点击事件响应,且不再在Api层面区分远程与本地通知,使对待通知的路径变得统一。 * 通知的收到 * 点击通知或按钮的操作响应

通知的收到
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{
    BOOL isRemote = NO;
    if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        isRemote = YES;
    }
    UILocalNotification *localNotification;//从新的转换为旧的本地通知
     
     if (!isRemote && [[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveLocalNotification:)]) {
        [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveLocalNotification:localNotification];
    }
    else if (isRemote) {
        if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]) {
            [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveRemoteNotification:notification.request.content.userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
        }
        else if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveRemoteNotification:)]){
            [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveRemoteNotification:notification.request.content.userInfo];
        }
    }
 
     
    completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionAlert);//决定前台展示形式
}
点击通知或按钮的操作响应
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler{
    BOOL isRemote = NO;
    if ([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        isRemote = YES;
    }
     
    UILocalNotification *localNotification;//从新的转换为旧的本地通知
 
     
    if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier] || [response.actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier]) {
        if (!isRemote && [[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveLocalNotification:)]) {
            [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveLocalNotification:localNotification];
        }
        else if (isRemote) {
            if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]) {
                [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveRemoteNotification:response.notification.request.content.userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
            }
            else if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveRemoteNotification:)]){
                [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveRemoteNotification:response.notification.request.content.userInfo];
            }
        }
    }
    else{
        if (!isRemote) {
            if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler:)]) {
                [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] handleActionWithIdentifier:response.actionIdentifier forLocalNotification:localNotification withResponseInfo:@{} completionHandler:^{}];
            }
            else if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:handleActionWithIdentifier:forLocalNotification:completionHandler:)]){
                [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] handleActionWithIdentifier:response.actionIdentifier forLocalNotification:localNotification completionHandler:^{}];
            }
        }
        else{
            if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler:)]) {
                [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] handleActionWithIdentifier:response.actionIdentifier forRemoteNotification:response.notification.request.content.userInfo withResponseInfo:@{} completionHandler:^{}];
            }
            else if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:handleActionWithIdentifier:forRemoteNotification:completionHandler:)]){
                [[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] handleActionWithIdentifier:response.actionIdentifier forRemoteNotification:response.notification.request.content.userInfo completionHandler:^{}];
            }
           1 
        }
    }
 
    }
    completionHandler();
}
posted @ 2017-10-25 16:34  天生的普通人  阅读(597)  评论(0编辑  收藏  举报