iOS 本地推送
概念
1.推送通知有5种不同的呈现效果
- 在屏幕顶部显示一块横幅(显示具体内容)
- 在屏幕中间弹出一个UIAlertView(显示具体内容)
- 在锁屏界面显示一块横幅(锁屏状态下,显示具体内容)
- 更新app图标的数字(说明新内容的数量)
- 播放音效(提醒作用)
2.用户也可以决定是否要开启以下4个功能:
- 显示App图标数字
- 播放音效
- 锁屏显示
- 显示在“通知中心”
3、注意:
- 发送推送通知时,如果程序正在前台执行,那么推送通知就不会被呈现出来,但是微信在前台的时候也能推送消息,方法是:创建一个view,仿造系统消息通知的样式向下出现,点击后回到根控制器再进行跳转(注意压栈)
- 点击通知会打开该通知的app
- 不管程序打开还是关闭,推送都能如期发出
步骤:
1.创建本地通知对象
UILocalNotification *localNotifi = [UILocalNotification new];
2、设置属性,参照下面
3、调度本地通知 (将本地通知加入本地通知调度池,iOS 7 到这一步完毕,不需要授权)
[[UIApplication sharedApplication] scheduleLocalNotification:localNotifi];
4、 注册通知权限(多个通知只需一次, 建议放在AppDelegate 的
didFinishLaunchingWithOptions
方法中) ,iOS8以后必须需要用户授权才可以发送通知
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
参数:
settingsForTypes 通知需要更改的东西,可以修改多个地方,UIUserNotificationType 枚举:
UIUserNotificationTypeNone = 0,
UIUserNotificationTypeBadge = 1 << 0, //图标标记
UIUserNotificationTypeSound = 1 << 1, //声音
UIUserNotificationTypeAlert = 1 << 2, //提醒
categories:用于添加下拉快速回复功能,下面有介绍
5、删除通知(如果设置了 repeatInterval 重复属性,注意手动删除通知对象)
两种方式:
(1)删除当前程序注册的所有通知,不重复的也会被取消
[[UIApplication sharedApplication] cancelAllLocalNotifications];
(2) 删除指定的通知,一般用于取消重复的通知或者还没有被调用的通知,先获取通知,再遍历根据条件去删除(条件是 UserInfo 的值,是发送通知时所携带的参数)
NSArray *notifiArray = [[UIApplication sharedApplication] scheduledLocalNotifications];
for (UILocalNotification *local in notifiArray) {
//将来可以根据UserInfo的值,来查看这个是否是你想要删除的通知
if (local.userInfo) {
//删除单个通知
[[UIApplication sharedApplication]cancelLocalNotification:local];
}
}
UIApplication 方法
1、调度本地推送通知(调度完毕后,推送通知会在特定的时间fireDate发出)
[[UIApplication sharedApplication] scheduleLocalNotification:localNotifi];
2、获取被调度的所有本地推送通知
注意:已经发出且过期的推送通知就算调度结束,会自动从这个数组中移除
@property(nullable,nonatomic,copy) NSArray<UILocalNotification *> *scheduledLocalNotifications;
3、取消调度本地推送通知
- (void)cancelAllLocalNotifications;
- (void)cancelLocalNotification:(UILocalNotification *)notification;
4、立即发出本地推送通知
[[UIApplication sharedApplication]presentLocalNotificationNow:localNotifi];
属性:
1、通知触发时间
@property(nullable, nonatomic,copy) NSDate *fireDate;
例子:每隔3秒发送一个通知
localNotifi.fireDate = [NSDate dateWithTimeIntervalSinceNow:3];
2、设置提醒内容
@property(nullable, nonatomic,copy) NSString *alertBody;
例子:
localNotifi.alertBody = @"今天不适合敲代码";
3、设置推送声音,值为声音文件名,默认值为 UILocalNotificationDefaultSoundName ,模拟器无效
@property(nullable, nonatomic,copy) NSString *soundName;
例子:
localNotifi.soundName = UILocalNotificationDefaultSoundName;
4、设置提醒后应用程序右上角图标标记
@property(nonatomic) NSInteger applicationIconBadgeNumber;
例子:
localNotifi.applicationIconBadgeNumber = 5;
5、是否显示锁屏时 slider 文字,默认为YES,以及提醒的按钮文字
@property(nonatomic) BOOL hasAction;
设置提醒的按钮文字 / 锁屏时界面底部的闪光文字(滑动来...)
@property(nullable, nonatomic,copy) NSString *alertAction;
锁屏界面默认的是回复来查看
锁屏界面效果
注意:这个值会改变两个地方,还会改变提醒的按钮文字
提醒Alter效果6、设置时区,一般设置为 [NSTimeZone defaultTimeZone],跟随手机的时区
@property(nullable, nonatomic,copy) NSTimeZone *timeZone;
7、 设置重复,每隔多久重复发一次推送通知,单位是日历组件,最小单位是分钟,0代表不重复,如果此属性设置了, 那么调度池不会用完释放!需要手动删除通知对象
@property(nonatomic) NSCalendarUnit repeatInterval;
localNotifi.repeatInterval = NSCalendarUnitMinute;
8、设置依赖的日历历法,默认就是跟随系统走,历法不一样每月重复间隔时间也不一样(如农历是30天)
@property(nullable, nonatomic,copy) NSCalendar *repeatCalendar;
例子:更改为按农历时间重复
localNotifi.repeatCalendar = [NSCalendar calendarWithIdentifier:@"NSCalendarIdentifierChinese"];
9、在哪个区域发送通知, 进入这个区域就发送这个通知
可以进来调一次,出去调一次
@property(nullable, nonatomic,copy) CLRegion *region NS_AVAILABLE_IOS(8_0);
区域是否只检测一次
@property(nonatomic,assign) BOOL regionTriggersOnce NS_AVAILABLE_IOS(8_0);
10、设置启动图,点击推送通知打开app时显示的启动图片
@property(nullable, nonatomic,copy) NSString *alertLaunchImage;
11、设置弹出框的标题
@property(nullable, nonatomic,copy) NSString *alertTitle NS_AVAILABLE_IOS(8_2);
12、设置通知推送携带的参数,一般用于点击通知打开指定控制器页面
@property(nullable, nonatomic,copy) NSDictionary *userInfo;
例子: 发送通知时,带一个索引2的参数,点击通知打开程序后自动跳到第三个控制器(TabBarController)
localNotifi.userInfo = @{@"selectIndex" : @(2)};
13、设置分类,用于添加下拉快速回复功能,下面有介绍
@property (nullable, nonatomic, copy) NSString *category NS_AVAILABLE_IOS(8_0);
点击通知跳到指定控制器界面
案例结构,tabBarController的索引分别为0 1 21、接收到本地通知后调用(AppDelegate中),该方法只有程序前台或后台的时候才有用,退出无法接收到消息即无法跳转,如需要在程序退出时推送通知,注意配合下面方式一起使用
(notification 参数中可获取 userInfo 参数来做一些事情)
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
2、程序退出获取本地通知的方法(重要)
原理:程序退出前发送通知给系统(加入调度池),并传出 userInfo 信息,然后退出,当触发通知时会唤醒AppDelegate的 didFinishLaunchingWithOptions 方法,系统又将 userInfo 信息传给程序,并通过方法的launchOptions 参数获取到本地通知对象
UILocalNotification *localNotifi = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
注意,控制台无法直接打印通知对象,因为编译程序已关闭,只能通过程序查看,可以创建一个label放在页面上,接收到通知后,将通知信息显示在label上
还要注意,程序在前台运行时,通知一样会发送来(虽然上面没有显示),程序接到通知会自动发生跳转(相当于自动点击了通知),这时候我们需要对程序的状态进行判断,如果在前台接收到通知不进行任何操作或提示用户是否进行跳转
UIApplication 单例的一个方法可以查看程序当前的状态
@property(nonatomic,readonly) UIApplicationState applicationState;
判断用户当前是否是激活状态 ,枚举值:
UIApplicationStateActive, 激活
UIApplicationStateInactive, 将要激活
UIApplicationStateBackground 后台
AppDelegate 中完整代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 请求用户授权
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
// 处理退出后通知的点击,程序启动后获取通知对象,如果是首次启动还没有发送通知,那第一次通知对象为空,没必要去处理通知(如跳转到指定页面)
if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
UILocalNotification *localNotifi = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
[self changeLocalNotifi:localNotifi];
}
return YES;
}
#pragma mark - 处理后台和前台通知点击
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
[self changeLocalNotifi:notification];
}
- (void)changeLocalNotifi:(UILocalNotification *)localNotifi{
// 如果在前台直接返回
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
return;
}
// 获取通知信息
NSString *selectIndex = localNotifi.userInfo[@"selectIndex"];
// 获取根控制器TabBarController
UITabBarController *rootController = (UITabBarController *)self.window.rootViewController;
// 跳转到指定控制器
rootController.selectedIndex = [selectIndex intValue];
}
快捷回复功能(iOS 8以后可用), category 属性的使用方法
如QQ的功能:触发通知后,点击下拉出现,点击“好的”两个字当做消息回复回去
QQ自动回复效果图
案例的效果:
案例效果设置快捷回复之后锁屏左滑会出现如下样式
锁屏左滑效果步骤:
1、发送通知时,给通知对象设置一个 category 标识符,用于AppDelegate中的配置
localNotifi.category = @"category";
2、在AppDelegate中配置注册授权信息
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 创建分类,注意使用可变子类
UIMutableUserNotificationCategory *category = [UIMutableUserNotificationCategory new];
// 设置标识符,注意与发送通知设置的category标识符一致~!
category.identifier = @"category";
// 设置按钮,注意使用可变子类UIMutableUserNotificationAction
// 设置前台按钮,点击后能使程序回到前台的叫做前台按钮
UIMutableUserNotificationAction *action1 = [UIMutableUserNotificationAction new];
action1.identifier = @"qiantai";
action1.activationMode = UIUserNotificationActivationModeForeground;
// 设置按钮的标题,即按钮显示的文字
action1.title = @"呵呵";
// 设置后台按钮,点击后程序还在后台执行,如QQ的消息
UIMutableUserNotificationAction *action2 = [UIMutableUserNotificationAction new];
action2.identifier = @"houtai";
action2.activationMode = UIUserNotificationActivationModeBackground;
// 设置按钮的标题,即按钮显示的文字
action1.title = @"后台呵呵";
// 给分类设置按钮
[category setActions:@[action1,action2] forContext:UIUserNotificationActionContextDefault];
// 注册,请求授权的时候将分类设置给授权,注意是 NSSet 集合
NSSet *categorySet = [NSSet setWithObject:category];
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:categorySet];
// 注册通知
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
3、点击分类按钮后进行回复消息处理
分类按钮点击后执行的方法
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler{
// 我们可以在这里获取标识符,根据标识符进行判断是前台按钮还是后台按钮还是神马按钮,进行相关逻辑处理(如回复消息)
NSLog(@"identifier : %@",identifier);
// 一旦接受必须调用的方法(告诉系统什么时候结束,系统自己对内部进行资源调配)
completionHandler();
}
注意:该方法会有警告
警告界面
警告说completionHandler这个回调没调用,系统希望知道你什么时候做完,系统到时自己内部进行资源调配