iOS 通知 Notification
iOS 通知 Notification
参考资料 :
- 活久见的重构 - iOS 10 UserNotifications框架解析
- iOS10通知框架UserNotifications学习及兼容笔记
- AppleDocument-PaylodReference
- 玩转 iOS 10 推送 —— UserNotifications Framework
前言
最近项目需要对交易H5下载进行优化,根据资料查找,iOS7以前大家大多使用无声播放来保证APP在后台继续运行,iOS7需要使用NSURLSession替换NSURLConnection,并且使用NSURLSessionTask添加后台下载功能,解决不管是前台还是后台都能正常的下载完成。那么结合后台下载,需要使用本地通知来告知用户下载结束情况,优化用户的体验。
iOS 通知
1. 远程通知 APNs
2. 本地通知 LocalNotification
远程通知,就是苹果的推送服务APNs(APP Push Notification Service):
苹果的APNs允许设备和苹果的推送通知服务器保持连接,支持开发者推送消息给用户设备对应的应用程序。
远程推送原理
远程推送步骤
- 注册:为应用程序申请消息推送服务。此时你的设备会向APNs服务器发送注册请求。
- APNs服务器接受请求,并将deviceToken返给你设备上的应用程序
- 客户端应用程序将deviceToken发送给后台服务器程序,后台接收并储存。
- 后台服务器向APNs服务器发送推送消息
- 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将授权后的状态返回,就像分散型网络请求一般。
第一次调用这个方法时,会弹出一个系统弹窗。 要注意的是,一旦用户拒绝了这个请求,再次调用该方法也不会再进行弹窗,想要应用有机会接收到通知的话,用户必须自行前往系统的设置中为你的应用打开通知,如果不是杀手级应用,想让用户主动去在茫茫多 app 中找到你的那个并专门为你开启通知,往往是不可能的。因此,在合适的时候弹出请求窗,在请求权限前预先进行说明,以此增加通过的概率应该是开发者和策划人员的必修课。相比与直接简单粗暴地在启动的时候就进行弹窗,耐心诱导会是更明智的选择。
对于远程通知,还需要一个获取用户token的操作,并使用这个token进行APNs推送。但是奇怪的是,对于申请token这个操作,新框架中却没有对应的Api,沿用旧的Api。
[[UIApplication sharedApplication] registerForRemoteNotifications];
//AppDelegate
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
....
}
配置Category并注册
对于Category的作用,上文已经有介绍,而Category中目前主要的功能,是对应一组按钮操作。
Category的使用分四步
- 创建Category,设置identifer,配置一组按钮(可无)
- 将Category注册到UIApplication(旧)/UNNotificationCenter(新)中
- 发送本地或远程消息时需要按钮或自定义视图时带上对应的categoryIdentifer
- 收到消息进行响应时通过消息中携带的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();
}