Local Notification

简介:

大家都知道Push Notification,这个东西需要联网才可以用。iOS4起,苹果引入了一种可以在设备内部引发的notification。不需要复杂的服务器编程,或其他复杂的配置。这个技术就是Local Notification。

Local notificaton可以在用户设定里定时触发。甚至,你可以设定重发。下面,我们就来研究下Local Notification,看看如何设定,查看和处理Local Notification。

1. 创建项目

    总体来说是这么个效果:

    

一共分三层,最上面一层是DatePicker。用于选择出发Local Notification的时间。第二层是一个TextField,用于设定Notification的title。最后是设定过的Notification都放在一个TableView里。看看都有什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 44, 320, 160)];
[ self .view addSubview:datePicker];
 
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 227, 150, 40)];
[ self .view addSubview:textField];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.placeholder = @ "Input Text" ;
self .textField = textField;
 
UIButton *saveButton = [[UIButton alloc] initWithFrame:CGRectMake(155, 227, 160, 40)];
[ self .view addSubview:saveButton];
saveButton.backgroundColor = [UIColor orangeColor];
[saveButton setTitle:@ " SAVE "  forState:UIControlStateNormal];
[saveButton addTarget: self  action: @selector (saveAction:) forControlEvents:UIControlEventTouchUpInside];
 
CGFloat height = [UIScreen mainScreen].bounds.size.height - 242;
UITableView *notiTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 268, 320, height)];
[ self .view addSubview:notiTableView];
notiTableView.delegate =  self ;
notiTableView.dataSource =  self ;

与UI元素对应的,我们这里有三层,四个界面元素。同事还有Button的一个action。同事需要注意的是,我们需要在Controller里实现UITableViewDelegate和UITableViewDataSource这两个protocol。要是用UITableView这两个protocol必须实现。

其他还要做一些必要的操作。比如创建一个空的设定notification的方法,等。

复制代码
#pragma mark - Private methods

- (void)saveAction:(id)sender{
    DLog(@"");
    [self.textField resignFirstResponder];
}

#pragma mark - UITableViewDelegate & datasource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 1;
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    
    return cell;
}
复制代码

在saveAction方法中,设定notification时退出textfield的编辑状态并隐藏键盘。所以,需要调用resignFirestResponder方法,[self.textField resignFirstResponder]

后面的UITableView相关的protocol中,暂时指定返回的行数为1,并在返回Cell的方法中返回没有设定任何内容的行。这样,代码就可以正常运行。否则,会因为没有实现必要的protocol方法而crash。

这个时候,在运行app之后就会出现上面给出的效果图。(注意:这里用的是真机运行的app)

 

2. 设定notification

这里是全教程的核心所在了。折腾完全文也都是基于这里所讲的内容。

首先,在DatePicker里设定好时间。之后在设定notification的内容。最后把指定推送在指定的时间引发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- ( void )saveAction:( id )sender{
     DLog(@ "" );
     [ self .textField resignFirstResponder];
     
     NSDate  *pickerDate = [ self .datePicker date];
     
     UILocalNotification *localNotification = [[UILocalNotification alloc] init];
     if  (localNotification) {
         localNotification.fireDate = pickerDate; //fireDate;
         localNotification.timeZone = [ NSTimeZone  defaultTimeZone];
         localNotification.alertBody =  self .textField.text;
         localNotification.alertAction = @ "View" ;
         localNotification.soundName = UILocalNotificationDefaultSoundName;
         localNotification.applicationIconBadgeNumber = 1;
         localNotification.userInfo = @{@ "userId" : @ "best user" , @ "userName" : @ "Jack" };
         [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
         
         [ self .notificationTableView reloadData];
     }
}

就如前文所述,使用NSDate *pickerDate = [self.datePicker date]; 获取到DatePicker中设定的日期,之后在Local notification对象的fireDate属性里赋值。localNotification.alertBody = self.textField.text设定提示的文本。使用localNotification.userInfo = @{@"userId": @"best user", @"userName": @"Jack"}设定用户信息,就是你觉得有用的信息以字典的方式存放在notification对象中,在其他的时候可以获取这个字典。最后,最关键的就是使用[[UIApplication sharedApplication] scheduleLocalNotification:localNotification]设定notification在指定的时间触发。

到这里,就可以指定一个Local notification在给定的时间触发了。但是还有一种场景,在用户做了某个操作的时候,notification立刻触发。这时,再用schecule的方法就会很奇怪,schedule一秒可能赶不上,schedule的秒多了可能错过正确的提示时机。所以API里提供了另一个方法presentNow,提示立刻触发。正确的立刻触发的方法是:[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification]。其他初始化和设定相关属性的方法都没有任何的变化。

 

3. 把设定过的notification都现实在TableView里

之前使用了一些dummy的方法,只是为了能让app正常的运行。这里补全所有必要的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- ( NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:( NSInteger )section{
     return  [[UIApplication sharedApplication] scheduledLocalNotifications].count;
}
 
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath  *)indexPath{
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
     if  (!cell) {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
     }
     
     NSArray  *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
     UILocalNotification *n = notifications[indexPath.row];
     
     cell.textLabel.text = n.alertBody;
     cell.detailTextLabel.text = [n.fireDate description];
     
     return  cell;
}

[[UIApplication sharedApplication] scheduledLocalNotifications]包含了全部的schedule过了的notification数组,count属性就是数量。在- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath中从notification数组中取出对应元素,显示在UITableView的Cell中,分别是:cell.textLabel.text = n.alertBody, cell.detailTextLabel.text = [n.fireDate description]。

 

最后

似乎是一切都完美了。notification也有了,可以通过界面的DatePicker指定时间,可以立即触发,还可以指定提示的内容。而且,还会在“铛”的一声,然后在app的图标上显示一个badge number出来。但是,当你点击了提示之后,进入到app里再出来你会发现。。。。。。badge number还是华丽丽的在那里木有消失。是的本来应该点开了notification之后就消失的,这是为什么呢。处理badge number的代码也需要我们手动的写出来。最后我们来处理这一部分的功能。

这里需要注意到两种情况:1. 设定好了notification的出发时间以后,app退出了。这个退出是说双击home键以后,上滑了这个app,终止了app进程。2. app还在运行着,也许是在触发notification的时候app还在运行中,或者app的进程还在运行中。

第一种情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- ( BOOL )application:(UIApplication *)application didFinishLaunchingWithOptions:( NSDictionary  *)launchOptions
{
     self .window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
     
     BVRootViewController *rootViewController = [[BVRootViewController alloc] init];
     UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:rootViewController];
     self .window.rootViewController = nav;
     
     self .window.backgroundColor = [UIColor whiteColor];
     [ self .window makeKeyAndVisible];
     
     application.applicationIconBadgeNumber = 0;
     
     UILocalNotification *n = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
     if  (n) {
         DLog(@ "Received notification %@" , n);
     }
     
     return  YES ;
}

第二种情况:

1
2
3
4
- ( void )application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
     application.applicationIconBadgeNumber = 0;
     DLog(@ "Received notification %@" , notification);
}

哦了!

 

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 330987132 | Go:217696290 | Python:336880185 | 做人要厚道,转载请注明出处!
相关文章
|
应用服务中间件 nginx
Mac Nginx nginx: [emerg] mkdir() “/usr/local/var/run/nginx/client_body_temp“ failed ...
Mac Nginx nginx: [emerg] mkdir() “/usr/local/var/run/nginx/client_body_temp“ failed ...
328 2
|
应用服务中间件 PHP nginx
PHP ‘group‘ 或 ‘user‘ directive is ignored when FPM is not running as root
PHP ‘group‘ 或 ‘user‘ directive is ignored when FPM is not running as root
406 1
|
数据库
loading local data is disabled; this must be enabled on both the client and server sides
loading local data is disabled; this must be enabled on both the client and server sides
198 0
|
Android开发
【错误记录】前台进程报错 ( Bad notification for startForeground invalid channel for service notification )
【错误记录】前台进程报错 ( Bad notification for startForeground invalid channel for service notification )
1449 0
【错误记录】前台进程报错 ( Bad notification for startForeground invalid channel for service notification )
|
安全 网络协议 数据安全/隐私保护