2017-12-28 00:51:14 kuangdacaikuang 阅读数 509

1. 本地通知 iOS10.0

本地通知 iOS10.0demo下载链接

iOS8.0 本地推送通知和接收通知及其跳转控制总结

1.1. 发送推送通知

//
//  ViewController.m
//  iOS10.0本地推送通知
//
//  Created by zhouyu on 2017/12/28.
//  Copyright © 2017年 zhouyu. All rights reserved.
//

#import "ViewController.h"
#import <UserNotifications/UserNotifications.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"ios10.0之后本地通知";
    [self setUpUI];
}


//- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//    // 使用 UNUserNotificationCenter 来管理通知
//    UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
//
//    //需创建一个包含待通知内容的 UNMutableNotificationContent 对象,注意不是 UNNotificationContent ,此对象为不可变对象。
//    UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
//    content.title = [NSString localizedUserNotificationStringForKey:@"本地推送Title" arguments:nil];
//    content.body = [NSString localizedUserNotificationStringForKey:@"本地推送Body" arguments:nil];
//    content.sound = [UNNotificationSound defaultSound];
//
//    // 在 设定时间 后推送本地推送
//    UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
//                                                  triggerWithTimeInterval:5 repeats:NO];
//
//    UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"FiveSecond"
//                                                                          content:content trigger:trigger];
//
//    //添加推送成功后的处理!
//    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
//        NSLog(@"推送成功了");
//    }];
//}

- (void)setUpUI{
    UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 300, 150, 60)];
    [btn1 setTitle:@"跳转红色控制器" forState:UIControlStateNormal];
    [btn1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [btn1 addTarget:self action:@selector(red) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn1];

    UIButton *btn2 = [[UIButton alloc] initWithFrame:CGRectMake(100, 400, 150, 60)];
    [btn2 setTitle:@"跳转蓝色控制器" forState:UIControlStateNormal];
    [btn2 setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [btn2 addTarget:self action:@selector(blue) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn2];
}

- (void)red{
    [self pushUNUserNotificationCenterWithRequestIdentifier:@"red" contentTitle:@"红色控制器" contentBody:@"跳转到红色控制器"];
}

- (void)blue{
    [self pushUNUserNotificationCenterWithRequestIdentifier:@"blue" contentTitle:@"蓝色控制器" contentBody:@"跳转到蓝色控制器"];
}

- (void)pushUNUserNotificationCenterWithRequestIdentifier:(NSString *)identifier contentTitle:(NSString *)title contentBody:(NSString *)body{
    // 使用 UNUserNotificationCenter 来管理通知
    UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];

    //需创建一个包含待通知内容的 UNMutableNotificationContent 对象,注意不是 UNNotificationContent ,此对象为不可变对象。
    UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
    content.title = [NSString localizedUserNotificationStringForKey:title arguments:nil];
    content.body = [NSString localizedUserNotificationStringForKey:body arguments:nil];
    content.sound = [UNNotificationSound defaultSound];

    // 在 设定时间 后推送本地推送
    UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
                                                  triggerWithTimeInterval:5 repeats:NO];

    UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:identifier
                                                                          content:content trigger:trigger];

    //添加推送成功后的处理!
    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
        NSLog(@"推送成功了");
    }];
}

@end

1.2. 注册和接收推送通知,并进行逻辑处理

//
//  AppDelegate.m
//  iOS10.0本地推送通知
//
//  Created by zhouyu on 2017/12/28.
//  Copyright © 2017年 zhouyu. All rights reserved.
//

#import "AppDelegate.h"
#import <UserNotifications/UserNotifications.h>
#import "ViewController.h"
#import "RedController.h"
#import "BlueController.h"

@interface AppDelegate ()<UNUserNotificationCenterDelegate>

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
    [self.window makeKeyAndVisible];
    self.window.backgroundColor = [UIColor whiteColor];

    // 使用 UNUserNotificationCenter 来管理通知
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    //监听回调事件
    center.delegate = self;

    //iOS 10 使用以下方法注册,才能得到授权
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
                              NSLog(@"error = %@",error);
                          }];

    return YES;
}

/*
 typedef NS_OPTIONS(NSUInteger, UNNotificationPresentationOptions) {
     UNNotificationPresentationOptionBadge   = (1 << 0),
     UNNotificationPresentationOptionSound   = (1 << 1),
     UNNotificationPresentationOptionAlert   = (1 << 2),
 }
 */
//当应用在前台的时候,收到本地通知,是用什么方式来展现。系统给了三种形式:
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{
    NSLog(@"%@",notification.request);

    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Title" message:@"APP在前台" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
    [alert show];

    // 处理完成后条用 completionHandler ,用于指示在前台显示通知的形式
    completionHandler(UNNotificationPresentationOptionSound);
}

//在后台或者程序被杀死的时候,点击通知栏调用的,在前台的时候不会被调用
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler{
    NSLog(@"%@",response);
//    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Title" message:@"APP在后台或者被杀死后唤醒至前台" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
//    [alert show];

    [self jumpToControllerWithUNNotificationResponse:response];

    completionHandler();
}

//判断跳转
- (void)jumpToControllerWithUNNotificationResponse:(UNNotificationResponse *)response{
    UINavigationController *nav = (UINavigationController *)self.window.rootViewController;
    if ([response.notification.request.identifier isEqualToString:@"red"]) {
        [nav pushViewController:[[RedController alloc] init] animated:YES];
    } else {
        [nav pushViewController:[[BlueController alloc] init] animated:YES];
    }
}


@end

这里写图片描述

这里写图片描述

这里写图片描述

2017-12-27 23:53:00 kuangdacaikuang 阅读数 2581

1. 本地通知 iOS8.0

本地推送通知demo下载链接

iOS 本地通知推送 iOS10.0 新API使用总结

1.1. 本地通知发送

***iOS8.0之后才能用
    //本地通知
    UILocalNotification *locationNo = [[UILocalNotification alloc] init];
    //触发时间
    locationNo.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];
    //通知内容
    locationNo.alertBody = @"这是本地通知";
    //iOS8.2之后可见,一般不用
    if (@available(iOS 8.2,*)) {
        locationNo.alertTitle = @"哈哈,本地推送";
    }
    //锁屏(黑屏状态下,"滑动来"后面的字)--iOS10.0之后,没有滑动解锁功能了,这个属性也就不存在了
    locationNo.alertAction = @"查看这个本地推送";
    locationNo.hasAction = YES;
    //通知过来时的声音
    locationNo.soundName = UILocalNotificationDefaultSoundName;
    //应用图标提示--默认是0,没有改变,设置为负数,通知到达时图标提示就会消失
    locationNo.applicationIconBadgeNumber = -1;

    //直接设置应用图标提示为0,代表隐藏,和上面效果一致
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;

    //MARK: 额外信息--对于用户不重要,对于开发者很重要,用于接收通知时处理相应逻辑
    locationNo.userInfo = @{@"name":@"周玉",@"job":@"iOS开发工程师"};

    //加入到调度池---有可能有多个通知---取决于触发时间
    [[UIApplication sharedApplication] scheduleLocalNotification:locationNo];

1.2. 本地通知接收

//#import "AppDelegate.h" 注册通知
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    /*
     UIUserNotificationTypeNone    = 0,      
     UIUserNotificationTypeBadge   徽章标记
     UIUserNotificationTypeSound   声音
     UIUserNotificationTypeAlert   弹出效果
     */
    //注册通知
    //本地通知设置
    UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:setting];

    //当程序被杀死的情况下,接收到通知并执行事情--
    UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
    if (notification) {
        NSLog(@"localNo = %@",notification.userInfo);//NSLog不会再打印
        //用测测试是否接收到通知
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
        label.backgroundColor = [UIColor redColor];
        [self.window.rootViewController.view addSubview:label];

    return YES;
}
// 程序没有被杀死时,接收到本地通知时调用--点击通知时会执行这个方法,如果程序被杀死时,这个方法不再走,在application: didFinishLaunchingWithOptions:方法中获取
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    NSLog(@"notification.userInfo = %@",notification.userInfo);

这里写图片描述

这里写图片描述

//锁屏(黑屏状态下,”滑动来”后面的字)–iOS10.0之后,没有滑动解锁功能了,这个属性也就不存在了
locationNo.alertAction = @”查看这个本地推送”;
locationNo.hasAction = YES;

这里写图片描述

这里写图片描述

2. 本地通知逻辑处理 iOS8.0

2.1. 发送推送通知

//  发送通知
//  ViewController.m
//  本地推送
//
//  Created by zhouyu on 2017/12/27.
//  Copyright © 2017年 zhouyu. All rights reserved.
//

#import "ViewController.h"
#import "RedController.h"
#import "BlueController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"本地推送";

    [self setUpUI];
}


- (void)setUpUI{
    UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 300, 150, 60)];
    [btn1 setTitle:@"跳转红色控制器" forState:UIControlStateNormal];
    [btn1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [btn1 addTarget:self action:@selector(red) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn1];

    UIButton *btn2 = [[UIButton alloc] initWithFrame:CGRectMake(100, 400, 150, 60)];
    [btn2 setTitle:@"跳转蓝色控制器" forState:UIControlStateNormal];
    [btn2 setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [btn2 addTarget:self action:@selector(blue) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn2];
}

- (void)red{
    [self pushLocationNotificationWithAlertBody:@"跳转红色控制器" userInfo:@{@"key":@"red"}];
}

- (void)blue{
    [self pushLocationNotificationWithAlertBody:@"跳转蓝色控制器" userInfo:@{@"key":@"blue"}];
}

- (void)pushLocationNotificationWithAlertBody:(NSString *)body userInfo:(NSDictionary *)userInfo{
    //本地通知
    UILocalNotification *locationNo = [[UILocalNotification alloc] init];
    //触发时间
    locationNo.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];
    //通知内容
    locationNo.alertBody = body;
    //通知过来时的声音
    locationNo.soundName = UILocalNotificationDefaultSoundName;
    //应用图标提示--默认是0,没有改变,设置为负数,通知到达时图标提示就会消失
    locationNo.applicationIconBadgeNumber = -1;

    //直接设置应用图标提示为0,代表隐藏,和上面效果一致
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;

    //MARK: 额外信息--对于用户不重要,对于开发者很重要
    locationNo.userInfo = userInfo;

    //加入到调度池---有可能有多个通知---取决于触发时间
    [[UIApplication sharedApplication] scheduleLocalNotification:locationNo];
}

@end

2.2. AppDelegate接收推送通知进行逻辑处理

//  接收通知并进行逻辑处理
//  AppDelegate.m
//  本地推送
//
//  Created by zhouyu on 2017/12/27.
//  Copyright © 2017年 zhouyu. All rights reserved.
//

#import "AppDelegate.h"
#import "ViewController.h"
#import "RedController.h"
#import "BlueController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
    [self.window makeKeyAndVisible];
    self.window.backgroundColor = [UIColor whiteColor];

    /*
     UIUserNotificationTypeNone    = 0,      
     UIUserNotificationTypeBadge   徽章标记
     UIUserNotificationTypeSound   声音
     UIUserNotificationTypeAlert   弹出效果
     */
    //注册通知
    //本地通知设置
    UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:setting];

    //当程序被杀死的情况下,如何接收到通知并执行事情--ios10.0之后废弃,需要用10.0之前版本测试
    UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
    if (notification) {
        NSLog(@"localNo = %@",notification.userInfo);//NSLog不会再打印
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
        label.backgroundColor = [UIColor redColor];
        [self.window.rootViewController.view addSubview:label];

        [self jumpToControllerWithLocationNotification:notification];
    }

    return YES;
}

// 程序没有被杀死时,接收到本地通知时调用--点击通知时会执行这个方法,如果程序被杀死时,这个方法不再走,在application: didFinishLaunchingWithOptions:方法中获取
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    NSLog(@"notification.userInfo = %@",notification.userInfo);
    [self jumpToControllerWithLocationNotification:notification];
}

- (void)jumpToControllerWithLocationNotification:(UILocalNotification *)localNo{

    //如果APP在前台,就不用走通知的方法了
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        return;
    }

    //获取userInfo
    NSDictionary *userInfo = localNo.userInfo;
    UINavigationController *nav = (UINavigationController *)self.window.rootViewController;
    //判断跳转
    if ([userInfo[@"key"] isEqualToString:@"red"]) {
        [nav pushViewController:[[RedController alloc] init] animated:YES];
    } else if([userInfo[@"key"] isEqualToString:@"blue"]) {
        [nav pushViewController:[[BlueController alloc] init] animated:YES];
    }

}

@end

//如果APP在前台,就不用走通知的方法了
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
return;
}

这里写图片描述

这里写图片描述

这里写图片描述

2018-12-30 23:25:23 weixin_42857581 阅读数 996


实现快捷创建简单的定时重复提醒推送功能。

主要实现原理

iOS10及以上

1.获取通知权限

iOS10及以上要先请求通知权限

UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
    //请求获取通知权限(角标,声音,弹框)
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge |
                                             UNAuthorizationOptionSound |
                                             UNAuthorizationOptionAlert)
                          completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            //获取用户是否同意开启通知
            NSLog(@"开启通知成功!");

        }
    }];
    

2.创建通知

UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
    content.title = attribute[ZBNotificationAlertTitle];
//    content.subtitle = @"本地通知副标题";
    content.body = @"body";
    //角标数量
    content.badge = @1;
    content.userInfo = userInfo;

	//设置通知声音
    UNNotificationSound *sound = [UNNotificationSound defaultSound];
    content.sound = sound;
    

创建 UNNotificationRequest :

//设置时间容器:传人date中所有时间元素放入时间容器
NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitYear |
                                     NSCalendarUnitMonth |
                                     NSCalendarUnitWeekday |
                                     NSCalendarUnitDay |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
//设置UNCalendarNotificationTrigger
//repeats: 设置是否重复
UNCalendarNotificationTrigger * trigger = [UNCalendarNotificationTrigger 
											triggerWithDateMatchingComponents:components 
											repeats:repeat];
//设置UNNotificationRequest
//identifer:设置通知标识符或者说通知名字
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifer content:content trigger:trigger];

3.添加通知

//把通知加到UNUserNotificationCenter, 到指定触发点会被触发
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
    if (error) {
        NSLog(@"通知添加失败:%@",error);
    } else {
        NSLog(@"通知添加成功");
    }
}];

4.重复提醒

如果repeats为YES时为重复提醒
约定在特定时间提醒时我们用时间容器来实现

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitYear |
                                     NSCalendarUnitMonth |
                                     NSCalendarUnitWeekday |
                                     NSCalendarUnitDay |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
                                     

比如设置一个每天都提醒的推送,传入的时间设置为:

NSDateFormatter * formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate * date = [formatter dateFromString:@"2019-01-01 08:00:00"];

每天8点 进行推送提醒的 时间容器 为:

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitHour |
                                     			NSCalendarUnitMinute |
                                     			NSCalendarUnitSecond
                                     fromDate:date];
                                     

每周二8点 (19年1月1号为周二) 进行推送提醒的 时间容器 为:

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitWeekday |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
                                     

每月1号8点 进行推送提醒的 时间容器 为:

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitDay |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
                                     

每年1月1号8点 进行推送提醒的 时间容器 为:

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitMonth |
                                     NSCalendarUnitDay |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
                                     

以此类推…
如果有需求是要 周一到周五的每天8点 提醒时,我的做法是用for循环创建5个通知:

//因为周日是一星期第一天,1代表周日,所以周一从2开始
for (NSInteger i = 2; i <= 6; i++) {
//这里时间容器创建和以上每周提醒的一样,省略。
        components.weekday = i;
        
//然后用这个components去添加通知就可以实现重复通知了
}

5.取消通知

//找到要取消的通知名字
NSMutableArray * names = [[NSMutableArray alloc]initWithObjects:notificationName, nil];
//批量取消这些通知
[[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:names];

iOS10以下

1.创建通知

UILocalNotification *localNotification = [[UILocalNotification alloc]init];
    
    // 设置触发时间
    localNotification.fireDate = date;
    // 设置时区  以当前手机运行的时区为准
    localNotification.timeZone = [NSTimeZone localTimeZone];
    // 设置推送 显示的内容
    localNotification.alertTitle = @"title";
    localNotification.alertBody = @"body";
    // 设置 角标
    localNotification.applicationIconBadgeNumber = 1;
    // 不设置此属性,则默认不重复
    localNotification.repeatInterval =  repeatInterval;
    
    // 设置推送的声音
    localNotification.soundName =  UILocalNotificationDefaultSoundName;
    
    
    localNotification.userInfo = userInfo;
 	//添加到通知
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    

2.重复提醒

重复提醒通过设置 repeatInterval 就可以

value effect
NSCalendarUnitDay 每天
NSCalendarUnitWeekday 每周
NSCalendarUnitMonth 每月
NSCalendarUnitYear 每年

等等…
同样如果有需求是周一到周五某时提醒也用循环创建五个通知

for (NSInteger i = 2; i <= 6; i++) {
//同样用NSDateComponents设置weekday来实现星期几的提醒
//先用传入的date创建时间容器,然后修改weekday后再转为NSDate
	NSDateComponents * components = [[NSCalendar currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:date];
    components.weekday = i;
    NSDate * newDate = [[NSCalendar currentCalendar] dateFromComponents:components];
//吧newDate再赋值给fireDate
}

3.取消通知

//获取所有通知
NSArray * localNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
    for (UILocalNotification * notification in localNotifications) {
    	//找到和要删除的通知同名的通知删除
        if ([notification.userInfo[@"notificationName"] hasPrefix:notificationName]) {
        	//删除通知
            [[UIApplication sharedApplication] cancelLocalNotification:notification];

        }
    }
    

注册通知

//注册通知
[[UIApplication sharedApplication] registerForRemoteNotifications];
    

快捷使用

封装了一个可以直接使用的类:ZBLocalNotification

//提醒重复类型
typedef NS_ENUM(NSInteger, ZBLocalNotificationRepeat) {
    ZBLocalNotificationRepeatNone,			//不重复
    ZBLocalNotificationRepeatEveryDay,		//每天
    ZBLocalNotificationRepeatEveryWeek,		//每周
    ZBLocalNotificationRepeatEveryMonth,	//每月
    ZBLocalNotificationRepeatEveryYear,		//每年
    ZBLocalNotificationRepeatEveryWorkDay	//每周一到周五(工作日)
};

//标识通知属性的key
typedef NSString * ZBLocalNotificationKey;
//标识通知声音文件名字的key
typedef NSString * ZBLocalNotificationSoundName;

extern ZBLocalNotificationKey const ZBNotificationFireDate;		//标识提醒时间
extern ZBLocalNotificationKey const ZBNotificationAlertTitle;	//标识标题
extern ZBLocalNotificationKey const ZBNotificationAlertBody;	//标识提醒内容
extern ZBLocalNotificationKey const ZBNotificationAlertAction;	//标识按钮
extern ZBLocalNotificationKey const ZBNotificationSoundName;	//标识声音
extern ZBLocalNotificationKey const ZBNotificationUserInfoName;	//标识通知名字
extern ZBLocalNotificationKey const ZBNotificationPriority;		//标识通知优先级
extern ZBLocalNotificationKey const ZBNotificationRepeat;		//标识通知重复
extern ZBLocalNotificationSoundName const ZBNotificationSoundAlarm;	//标识声音为提醒
extern ZBLocalNotificationSoundName const ZBNotificationSoundOther;	//标识声音为其他

@interface ZBLocalNotification : NSObject

/**
 创建本地通知

 @param attribute 通知的属性
 */
+ (void)createLocalNotificationWithAttribute:(NSDictionary *)attribute;

/**
 取消通知

 @param notificationName 通知名字
 */
+ (void)cancelLocalNotificationWithName:(NSString *)notificationName;

#ifdef NSFoundationVersionNumber_iOS_9_x_Max

/**
 注册通知
 */
+ (void)requestUNUserNotificationAuthorization;

#endif

@end

创建时间为date的每天重复提醒例子:
导入#import "ZBLocalNotification.h"

[ZBLocalNotification createLocalNotificationWithAttribute:
                                @{ZBNotificationUserInfoName:@"notificationName",
                                  ZBNotificationSoundName:ZBNotificationSoundAlarm,
                                  ZBNotificationAlertBody:@"提醒内容",
                                  ZBNotificationAlertTitle:@"提醒标题",
                                  ZBNotificationFireDate:date,
                                  ZBNotificationPriority:@(0),
                                  ZBNotificationRepeat:@(ZBLocalNotificationRepeatEveryDay)
                                  }];
                                  

取消名字为 “notificationName” 的通知:

[ZBLocalNotification cancelLocalNotificationWithName:@"notificationName"];

通知优先级问题

如果设置了多个推送通知,并且时间都在同一个时刻时,就是同时收到多个推送通知时,想要只显示优先级最高的一个,我是在AppDelegate里这样处理的(希望有更好的方法能不吝赐教 ? ):
先创建一个userInfo容器,保存同一时间收到的通知
self.userInfos = [[NSMutableArray alloc]init];

//处理接收到的通知信息
- (void)filteredUserInfo {
    if (self.userInfos.count == 0) {
        return;
    }
    //选出你希望显示的通知信息,以下方法是显示优先级高的,你可以判断不同的条件
    //排序所有收到的通知信息,对比优先级,把优先级最高的放首位
    [self.userInfos sortUsingComparator:^NSComparisonResult(NSDictionary * obj1, NSDictionary * obj2) {
        if ([obj1[ZBNotificationPriority] integerValue] < [obj2[ZBNotificationPriority] integerValue]) {
            return NSOrderedDescending;
        }
        return NSOrderedSame;
    }];
    
    //自定义展示推送内容
    [self showAlarmAlertWithUserInfo:self.userInfos.firstObject];
    //重置userInfo容器
    [self.userInfos removeAllObjects];
}
//添加通知到userInfo容器
- (void)waitMultipleUserInfo:(NSDictionary *)userInfo {
    [self.userInfos addObject:userInfo];
    //创建信号量,设置为0
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(quene, ^{
        
        if (self.userInfos.count == 1) {
        	//信号量为0时,那么这个函数就阻塞当前线程等待timeout,时间到后继续执行
        	//0.3秒内第一次进入则等待0.3秒,0.3秒后对本时间段内提醒提取优先级最高的一个
        	//就是保存在极短时间内(我这里设置为0.3s)收到的所有通知,然后进行处理
            dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC));
            dispatch_async(dispatch_get_main_queue(), ^{
                [self filteredUserInfo];
            });
        }
    });
    
}

#pragma mark - localNotification
// iOS10以下 在前台收到推送回调
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    [self waitMultipleUserInfo:notification.userInfo];
}

#ifdef NSFoundationVersionNumber_iOS_9_x_Max

#pragma mark - UNUserNotificationCenterDelegate
// iOS10 在前台收到推送回调
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(nonnull UNNotification *)notification withCompletionHandler:(nonnull void (^)(UNNotificationPresentationOptions))completionHandler{
    UNNotificationRequest *request = notification.request; // 收到推送的请求
    UNNotificationContent *content = request.content; //收到推送消息的全部内容
    
    if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        NSLog(@"iOS10 收到远程通知");
    }else{
        NSLog(@"ios10 收到本地通知userInfo:%@",content.userInfo);
        [self waitMultipleUserInfo:content.userInfo];
    }
    completionHandler(UNNotificationPresentationOptionBadge |
                      UNNotificationPresentationOptionSound
                       );
    
}

#endif

代码下载

ZBLocalNotification类下载地址:
·iOS本地推送封装(定时推送、重复提醒)
·iOS本地推送封装(定时推送、重复提醒)

疑问

比如需求是可以自定义重复的时间:

  • 每隔两周的周二早上8点提醒
  • 每隔三个月的7号早上8点提醒

这种时候的怎么实现,NSDateComponents需要怎么设置?

谢谢!

欢迎讨论,未完待续


2015-09-09 19:52:25 free_heart_fly 阅读数 255

推送通知

注意:这里说的推送通知跟NSNotification有所区别
NSNotification是抽象的,不可见的
推送通知是可见的(能用肉眼看到)

iOS中提供了2种推送通知
本地推送通知(Local Notification)
远程推送通知(Remote Notification)

推送通知的作用

推送通知的作用
可以让不在前台运行的app,告知用户app内部发生了什么事情

推送通知的呈现效果总结

在屏幕顶部显示一块横幅(显示具体内容)
在屏幕中间弹出一个UIAlertView(显示具体内容)
在锁屏界面显示一块横幅(锁屏状态下,显示具体内容)
更新app图标的数字(说明新内容的数量)
播放音效(提醒作用)

用户也可以决定是否要开启以下4个功能:
显示App图标数字
播放音效
锁屏显示
显示在“通知中心”

推送通知的使用细节

发出推送通知时,如果程序正运行在前台,那么推送通知就不会被呈现出来
点击推送通知后,默认会自动打开发出推送通知的app
不管app打开还是关闭,推送通知都能如期发出

如何发送本地推送

1.创建本地推送对象
UILocalNotification *localNote = [[UILocalNotification alloc]init];
2.设置通知属性

if (localNote != nil) {
        // 设置推送时间
        NSDate *pushDate = [NSDate dateWithTimeIntervalSinceNow:10];
        localNote.fireDate = pushDate;
        // 设置时区(一般设置为[NSTimeZone defaultTimeZone] ,跟随手机的时区)
        localNote.timeZone = [NSTimeZone defaultTimeZone];
        // 设置重复间隔
        localNote.repeatInterval = NSCalendarUnitMinute;
        // 推送音效,格式只能是.aiff、.wav、.caf三种格式,并且声音的长度不能超过30秒
        localNote.soundName = UILocalNotificationDefaultSoundName;
        //localNote.alertLaunchImage = @"";//点击推送通知打开app时显示的启动图片

        // 推送内容
        localNote.alertBody = @"推送内容";
        // 锁屏后动作提示标题(提示滑动的操作目的)
        localNote.alertAction=@"推送内容";
        // 显示在icon上的红色圈中的数子
        localNote.applicationIconBadgeNumber = 1;

        // 设置userinfo 方便在之后需要撤销的时候使用(附加的额外信息)

        NSDictionary *info = [NSDictionary dictionaryWithObject:@"name"forKey:@"key"];
        localNote.userInfo = info;

        //添加推送到UIApplication
        UIApplication *app = [UIApplication sharedApplication];   
        // 判断版本设备,因为iOS8.0以后的版本设置和之前的不一样
        if([[UIDevice currentDevice].systemVersion floatValue] >= 8.0){
            //对通知进行设置
            UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
            [app registerUserNotificationSettings:setting];// 注册设置
        }     
        [app scheduleLocalNotification:localNote];// 启动推送(在规定时间)
    }

3.取消本地推送

 UIApplication *app = [UIApplication sharedApplication];
 [app cancelAllLocalNotifications];// 取消所有本地推送
 // 取消指定本地推送
 // [app cancelLocalNotification:localNote];

4.获得被调度的所有本地推(等待发出还未发出的推送)
已发出且过期的推送算调度结束,会自动从数组中移除

 NSArray *notes = [UIApplication sharedApplication].scheduledLocalNotifications;

5.此方法是立即发送推送(应用场景:程序后台运行时接受到类似于QQ消息后即时推送)

    //即时推送
    [app presentLocalNotificationNow:notification];

点击本地推送通知

当用户点击本地推送通知,会自动打开app,这里有2种情况
app并没有关闭,一直隐藏在后台
让app进入前台,并会调用AppDelegate的下面方法(并非重新启动app)

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;

示例代码:

/**
 *  当用户点击本地通知进入app的时候调用 、通知发出的时候(app当时并没有被关闭)
 */
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
//    self.label.text = [NSString stringWithFormat:@"点击通知再次回到前台---%d", application.applicationState];
    // 程序正处在前台运行,直接返回
    if (application.applicationState == UIApplicationStateActive) return;

    NewViewController *homeVc = [self.window.rootViewController.childViewControllers firstObject];
    [homeVc performSegueWithIdentifier:@"home2detail" sender:notification];
}

app已经被关闭(进程已死)
启动app,启动完毕会调用AppDelegate的下面方法

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    UILabel *label = [[UILabel alloc] init];
    label.backgroundColor = [UIColor redColor];
    label.frame = CGRectMake(0, 100, 200, 100);
    label.font = [UIFont systemFontOfSize:11];
    label.numberOfLines = 0;
    [[[self.window.rootViewController.childViewControllers firstObject] view] addSubview:label];

    // launchOptions参数通过UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知对象
    UILocalNotification *note = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
    if (note) {
        label.text = @"点击本地通知启动的程序";    
        NewViewController *homeVC = [self.window.rootViewController.childViewControllers firstObject];
        [homeVC performSegueWithIdentifier:@"home2detail" sender:note];
    } else {
        label.text = @"直接点击app图标启动的程序";
    }
    self.label = label;
    return YES;
}
2015-03-16 11:06:41 woaifen3344 阅读数 55065

在iOS8之后,以前的本地推送写法可能会出错,接收不到推送的信息,

如果出现以下信息:

1 Attempting to schedule a local notification
2 with an alert but haven't received permission from the user to display alerts
3 with a sound but haven't received permission from the user to play sounds
说明在IOS8下没有注册,所以需要额外添加对IOS8的注册方法,API中有下面这个方法:

// Registering UIUserNotificationSettings more than once results in previous settings being overwritten.
- (void)registerUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings NS_AVAILABLE_IOS(8_0);

这个方法是8.0之后才能使用的,所以需要判断一下系统的版本。

第一步:注册本地通知:

// 设置本地通知
+ (void)registerLocalNotification:(NSInteger)alertTime {
  UILocalNotification *notification = [[UILocalNotification alloc] init];
  // 设置触发通知的时间
  NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:alertTime];
  NSLog(@"fireDate=%@",fireDate);
  
  notification.fireDate = fireDate;
  // 时区
  notification.timeZone = [NSTimeZone defaultTimeZone];
  // 设置重复的间隔
  notification.repeatInterval = kCFCalendarUnitSecond;
  
  // 通知内容
  notification.alertBody =  @"该起床了...";
  notification.applicationIconBadgeNumber = 1;
  // 通知被触发时播放的声音
  notification.soundName = UILocalNotificationDefaultSoundName;
  // 通知参数
  NSDictionary *userDict = [NSDictionary dictionaryWithObject:@"开始学习iOS开发了" forKey:@"key"];
  notification.userInfo = userDict;
  
  // ios8后,需要添加这个注册,才能得到授权
  if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
    UIUserNotificationType type =  UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type
                                                                             categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    // 通知重复提示的单位,可以是天、周、月
    notification.repeatInterval = NSCalendarUnitDay;
  } else {
    // 通知重复提示的单位,可以是天、周、月
    notification.repeatInterval = NSDayCalendarUnit;
  }
  
  // 执行通知注册
  [[UIApplication sharedApplication] scheduleLocalNotification:notification];
}

第二步:处理通知,这个是在appdelegate中的代理 方法回调

// 本地通知回调函数,当应用程序在前台时调用
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
  NSLog(@"noti:%@",notification);
  
  // 这里真实需要处理交互的地方
  // 获取通知所带的数据
  NSString *notMess = [notification.userInfo objectForKey:@"key"];
  UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"本地通知(前台)"
                                                  message:notMess
                                                 delegate:nil
                                        cancelButtonTitle:@"OK"
                                        otherButtonTitles:nil];
  [alert show];
  
  // 更新显示的徽章个数
  NSInteger badge = [UIApplication sharedApplication].applicationIconBadgeNumber;
  badge--;
  badge = badge >= 0 ? badge : 0;
  [UIApplication sharedApplication].applicationIconBadgeNumber = badge;
  
  // 在不需要再推送时,可以取消推送
  [HomeViewController cancelLocalNotificationWithKey:@"key"];
}

第三步:在需要的时候取消某个推送

// 取消某个本地推送通知
+ (void)cancelLocalNotificationWithKey:(NSString *)key {
  // 获取所有本地通知数组
  NSArray *localNotifications = [UIApplication sharedApplication].scheduledLocalNotifications;
  
  for (UILocalNotification *notification in localNotifications) {
    NSDictionary *userInfo = notification.userInfo;
    if (userInfo) {
      // 根据设置通知参数时指定的key来获取通知参数
      NSString *info = userInfo[key];
      
      // 如果找到需要取消的通知,则取消
      if (info != nil) {
        [[UIApplication sharedApplication] cancelLocalNotification:notification];
        break;
      }
    }
  }
}


下载demo:https://github.com/632840804/LocalPush


iOS10 本地推送机制

阅读数 1493

IOS本地推送通知

阅读数 789

没有更多推荐了,返回首页