# InteractiveNotification **Repository Path**: creeve/InteractiveNotification ## Basic Information - **Project Name**: InteractiveNotification - **Description**: 交互式通知Demo - **Primary Language**: Objective-C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2017-01-18 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #iOS8 通知新特性 ## 实现功能 ![图片](https://s3.amazonaws.com/nrjio/interactive.gif) 可交互的通知:当收到一个推送/本地通知的时候,提供手机观看+电视观看的选项,用户点击手机观看,跳转手机进行观看,当用户点击电视观看的时候,推送到电视观看。 Demo先实现简单的加减处理,实际项目中可以把按键对应的行为改成需要的处理。 ## 实现思路 使用iOS 8提供的通知新API进行:UINotificationAction ## 实现方法 使用`UIMutableUserNotificationAction`类生成通知Action: ``` UIMutableUserNotificationAction *incrementAction = [[UIMutableUserNotificationAction alloc] init]; incrementAction.identifier = @"INCREMENT_ACTION"; incrementAction.title = @"Add +1"; incrementAction.activationMode = UIUserNotificationActivationModeBackground; incrementAction.authenticationRequired = YES; incrementAction.destructive = NO; UIMutableUserNotificationAction *decrementAction ... ``` 使用生成的Action来生成`UIMutableUserNotificationCategory`: ``` UIMutableUserNotificationCategory *countCategory = [[UIMutableUserNotificationCategory alloc] init]; countCategory.identifier = @"COUNT_CATEGORY"; [countCategory setActions:@[incrementAction, decrementAction, resetAction] forContext:UIUserNotificationActionContextDefault]; [countCategory setActions:@[incrementAction, decrementAction] forContext:UIUserNotificationActionContextMinimal]; ``` 用生成的Category来生成UIUserNotificationSettings,并注册UserNotification: ``` UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert; UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:[NSSet setWithObject:countCategory]]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; ``` 然后到触发通知即可,这里以本地通知为例: ``` UILocalNotification *localNoti = [[UILocalNotification alloc] init]; localNoti.alertBody = @"Hey! Update your counter"; localNoti.soundName = UILocalNotificationDefaultSoundName; localNoti.fireDate = [NSDate dateWithTimeIntervalSinceNow:5]; localNoti.category = @"COUNT_CATEGORY"; [[UIApplication sharedApplication] scheduleLocalNotification:localNoti]; ``` 注意Category需要和注册通知的时候的Category一致。远程通知的话,需要在json上加一个category字段,并填上对应的值: ``` "aps" : { "alert" : "Pull down to interact.", "category" : "COUNT_CATEGORY" } ``` 收到本地通知后会回调这个方法: ``` - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler { if ([identifier isEqualToString:@"INCREMENT_ACTION"]) { [Counter increase]; } else if ([identifier isEqualToString:@"DECREMENT_ACTION"]) { [Counter decrease]; } else if ([identifier isEqualToString:@"RESET_ACTION"]) { [Counter reset]; } dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ completionHandler(); }); } ``` 这里根页面注册了一个KVO,监测Counter当前值的变化,收到通知Action后,App会短暂唤醒App,并执行相应的语句。执行完成后`completionHandler();`block来通知已经通知动作处理完,结束App运行。 WWDC的视频上说允许唤醒的时间只有几秒级别,当然这也足够发送一个网络请求了。 远程通知则会跳转: ``` - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler ``` 添加对应的处理就可以了。 ## iOS10的变化 以上是iOS8下的交互式通知的处理过程,如果我们把上面的代码运行在iOS8,iOS9设备上面,可以实现锁屏/通知中心左滑通知,出现两个按键(Add +1,Sub -1)的行为。 但是iOS10上如果在锁屏页面或者通知在通知中心里面,左划是出不来按键的,只能在首次提示的时候下拉通知,或者在支持3D touch的设备上强按通知才能显示自定义的按键。 这点非常蛋疼,不支持3D touch的话,锁屏和通知中心页面是无法呼出自定义按键行为的。这点只能靠苹果改进了(不一定会改,因为不支持3D Touch的设备现在已经停产了)。 此外iOS10之后引入了新的通知中心框架UserNotification,支持更为丰富的通知功能,并统一整个通知系统,但是由于App需要支持iOS8,9,10,所以想用UN的话,需要区分版本进行处理。 具体可以参考:https://onevcat.com/2016/08/notification/ 当然,如果不用iOS10的这些新特性,直接用iOS8的这套通知系统也够了,当然iOS8的方法都是deplecated的。 ##PS:弹出允许通知窗口的时机 由于通知权限大多是在App启动的时候获取,所以大部分App都简单粗暴在App启动的时候获取权限了,部分用户是比较反感这一点的。 比较合理的是提供一个引导页面,提醒用户需要开启通知才能使用某些功能。或者当用户使用到某些需要开启通知功能的时候,才弹出提示。 一旦用户拒绝了通知,想要用户重新打开通知,需要一点Trick: ``` UIAlertAction *action = [UIAlertAction actionWithTitle:@"跳转" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { NSURL *appSettings = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; [[UIApplication sharedApplication] openURL:appSettings]; }]; ``` 这样就能打开App的设置页面了,打开通知中心需要用户操作不多(如果只提示用户到设置去设置,基本上别想了,App列表一多,用户很难找到你的App)。 同理也可以用于相机权限,照片权限等。