本地通知

一、简介

1、概念

本地通知,local notification,用于基于时间行为的通知,比如有关日历或者todo列表的小应用。作用是让它们的用户或得相关消息通知的方式。消息通知可能是一条消息,即将发生的日历时间,或远程服务器的新数据。也可以显示一个警告消息或在应用程序的图标上面现在一个徽标,也可以在警告窗或徽标显示时播放一段声音。另外,应用如果在后台执行,iOS允许它在受限的时间内运行,它也会发现本地通知有用。比如,一个应用,在后台运行,向应用的服务器端取信息,当消息到达时,通过本地通知机制通知用户。

2、起源

本地通知:是本地iPhone、iPad、或iPod touch上面的应用发起的。

3、理论

本地通知:应用程序需要创建一个UILocalNotification对象,并给它设置发送的时间和日期,指定细节,并调用它。
当操作系统发送一个本地通知(只有iOS支持),如果此时应用程序没有运行在前台,它将会显示通知(警告窗、图标徽标、声音)。如果显示一个通知警告窗并且用户轻击或单击动作按钮(或移动动作滑块),相应的应用程序将会加载启动并调用本地通知对象相应方法。如果通知到达的时候应用程序正运行在前台,应用程序的委托接受一个本地通知。

二、本地通知深度

本地通知:由同一设备上面的应用自己调度和传递;只能在iOS上面可用。

1、本地通知显示效果

在iOS上面,一个应用指定提示信息或徽标数字时也可以指定一个声音文件。该声音文件应该包含一个短的,有特色的声音。在iOS显示提示窗或图标上显示徽标的时候,它会播放该声音文件的声音来告知通知已经到达

通知提示消息可以只包含一个按钮。当动作按钮被取消,用户只隐藏该提示窗。

操作系统传递一个本地通知,无论应用的程序此时是否运行在前台。如果过在通知达到的时候应用程序正在运行,没有提示窗或图标徽标或声音播放,即使此时设备是锁屏的。相反,应用的委托会被告知该通知以便其直接处理该通知。

2、更多关于本地通知

本地通知(仅在iOS上面支持)非常适合基于时间的行为,包括简单的日历事件或To-Do列表应用。本地通知对iOS允许的特定时间内运行后台的应用程序也非常有帮助。本地通知是UILocalNotification的一个实例,包含了3个通用的属性:

  • ①、调度时间:你必须制定操作系统传递通知的日期和时间,及通常认为的开始时间。你可以需要按照特定的时区时间指定日期以便操作系统可以在用户旅行的时候调整相应地开始时间。你也可以要求操作系统以特定的间隔来重新调度该通知(每周、每月等)。
  • ②、通知类型:该类别包含了提示信息,动作按钮的标题,应用程序图标的徽标数字,和要播放的声音等。
  • ③、自定义数据:本地通知可以包含一个自定义数据的字典。
    注意:一旦应用程序创建了本地通知对象,它让操作系统来调度该通知或立即显示。设备上面的每个应用程序最大调度的本地通知数64个。超出最大限制时操作系统丢弃超出的通知。通常一个重复的通知可以作为一个通知来对待。

三、调度、注册、处理通知

1、准备好自定义的警告声音

对于iOS上面的远程通知,你可以在显示某个应用的本地或远程通知时指定一个自定义的声音来播放。但是声音文件必须在客户端程序的主目录下面(即main bundle)。因为自定义的警告声音由iOS的声音系统设备播放,所以它必须是一下的任意格式的音频文件:

  • ①、Linera PCM;
  • ②、MA4(IMA/ADPCM);
  • ③、μLaw;
  • ④、aLaw。

然后可以把音频文件打包为aiff、wav、或caf文件,在Xcode里边把声音文件添加到你的工程里面作为程序目录的一个并非本地化的资源。

注意:自定义的声音文件播放时必须在30秒以内。如果一个自定义的声音文件播放超过30秒的限制,那将会被系统的声音替换

2、调度本地通知

在iOS上面创建和调度本地通知需要你完成下面几个简单的步骤:

  1. 创建并初始化一个UILocalNotification对象;
  2. 设置系统应该处理该通知的日期和时间,即fireDate属性;如果你设置了本地的NSTimeZone的timeZone属性,当设备跨越不同的时区(或被重置时)系统将会自动调整触发时间(系统计算一个给定的日历或者日期值时,时区影响日期的属性——即天、月、小时、年、分钟等)。你也可以循环的调度一个通知(每天、每周、每月等)。
  3. 配置通知的实体内容:警告、图标数字、声音等;
    • ①、警告有一个消息的属性(alertBody属性)和动作按钮或滑块的标题(alertAction);这两个属性的字符串都可以国际化为用户当前的偏好语言。
    • ②、你可以通过applicationIconBadgeNumber属性来设置应用程序图片上面显示的数字;
    • ③、你可以为soundName属性赋值一个当前应用主目录下本地化的自定义声音文件名。为了过去系统默认的声音文件,给该属性赋值。
  4. 可选的:你可以通过userInfo属性来放入自定义的数据到通知里面。userInfo的键和值必须是属性列表对象。
  5. 调度本地通知以便处理:
    • ①、通过调用UIApplication的方法scheduleLocalNotification:来调度一个本地通知。程序通过UILocalNotification对象指定的触发日期来调度它。
    • ②、通过调用presentLocalNotificationNow:方法来立即显示一个通知。
      实例1:
      创建和调度一个本地通知来告知用户未来一个任务列表。

注意:对于alertBody和alertAction属性,它从主目录的本地化字符串里面获取用户偏好语言的相应字符(通过NSLocalizadString)。它同时把任务列表的相关名词赋值到userInfo属性里面。

例1:

- (void)scheduleNotification{
    //本地通知
    /* * 本地推送,最多支持64个 * @param fireDate 本地推送触发的时间 * @param timeZone 本地推送的时区 * @param alertBody 本地推送需要显示的内容 * @param badge 角标的数字。如果不需要改变角标传-1 * @param alertAction 弹框的按钮显示的内容(IOS 8默认为"打开",其他默认为"启动") * @param soundName 自定义通知声音,设置为nil为默认声音 * @param userInfo 自定义参数,可以用来标识推送和增加附加信息 * @param notificationKey 本地推送标示符 * IOS8新参数 * @param region 自定义参数 * @param regionTriggersOnce 自定义参数 * @param category 自定义参数 */
    UILocalNotification *newNotification = [[UILocalNotification alloc] init];
    if (newNotification) {
        //获取当前时区
        NSTimeZone* zone = [NSTimeZone defaultTimeZone];
        NSDate *date = [NSDate date];
        //和格林尼治时间差
        NSInteger timeOff = [zone secondsFromGMT];
        //获取当前时间
        NSDate *timeOffDate = [date dateByAddingTimeInterval:timeOff];
// NSLog(@"date = %@",timeOffDate);
        //本地推送的时区
        newNotification.timeZone = zone;
        //本地推送触发的时间---10秒后
        newNotification.fireDate=[timeOffDate dateByAddingTimeInterval:10];
        //推送内容
        newNotification.alertBody = @"信号报警";
        //应用右上角红色图标数字
        newNotification.applicationIconBadgeNumber = 1;
        //弹框的按钮显示的内容(IOS 8默认为"打开",其他默认为"启动")
        newNotification.alertAction = @"open";
        //soundName 自定义通知声音,设置为nil为默认声音
        newNotification.soundName = UILocalNotificationDefaultSoundName;
        //add key 给这个通知增加key 便于半路取消。nfkey这个key是我自己随便起的。
        // 假如你的通知不会在还没到时间的时候手动取消 那下面的两行代码你可以不用写了。
        NSDictionary *dict =[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1],@"nfkey",nil];
        newNotification.userInfo = dict;
        //启动这个通知
        [[UIApplication sharedApplication]   scheduleLocalNotification:newNotification];
    }
}

你可以通过调用程序的cancelLocalNotification:方法来取消一个指定的已经调度的通知,甚至你可以通过调用cancelAllLocalNotifications方法来取消所有已调度的通知。这两个方法都可以隐藏当前已经显示的通知警告窗口。

例如:

[[UIApplication sharedApplication] cancelLocalNotification:newNotification];
[[UIApplication sharedApplication] cancelAllLocalNotifications];

实例2:

当应用程序运行在后台的时候,一些用户感兴趣的消息,数据,或其他项抵达时,此时本地通知就会非常有帮助。在这种情况下,他们应该通过使用UIApplication的方法presentLocalNotificationNow:来立即显示通知(iOS给定有限的时间让应用程序在后台执行)。此处有不懂的地方

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    NSLog(@"Application entered background state.");
    bgTask is instance variable
    NSAssert(self->bgTask == UIInvalidBackgroundTask, nil);
    bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [application endBackgroundTask:self->bgTask];
            self->bgTask = UIInvalidBackgroundTask;
        });
    }];
    dispatch_async(dispatch_get_main_queue(), ^{
        while ([application backgroundTimeRemaining] > 1.0) {
            NSString* friend;
            if (friend) {
                UILocalNotification *localNotif = [[UILocalNotification alloc] init];
                if (localNotif) {
                    localNotif.alertBody =  @"信号报警";
                    localNotif.alertAction = @"open";
                    localNotif.soundName = @"alarmsound.caf";
                    localNotif.applicationIconBadgeNumber = 1;
                    friend = nil;
                    break;
                }
            }
        }
        [application endBackgroundTask:self->bgTask];
        self->bgTask = UIInvalidBackgroundTask;
    });
}

3、处理本地通知

  • (1)、无论应用是否运行在前台,通知都会被提供。在这种情况下,系统展示通知,显示一个警告,在图标上面显示数字,可能播放一个声音。
  • (2)、通知展示的结果是,用户点击警告窗口的动作按钮或点击应用程序的图标。如果运行iOS的设备应用程序的图标被点击,该应用程序会调用相同的方法,但是不会提供任何关于通知的信息。

iOS注意:应用的委托可以实现applicationDidFinishLaunching:方法,而不是application:didFinishLaunchingWithOptions: ,但是强烈不建议这样做。后一种方法允许应用程序接收和它启动相关的信息,这些信息不仅仅包括通知。

  • (3)、当应用运行在前台的时候,通知被提交。应用程序调用它委托的application:didReceiveLocalNotification:方法(对于本地通知而言),并传递本地通知对象给方法的参数。
    应用程序可以使用在iOS上面的UILocalNotification对象来帮组设置上下处理和通知相关项目。对于iOS,它必须通过UIApplicationDelegate,并实现application:didFinishLaunchingWithOptions:方法和application:didiReceiveLocalNotification:方法。

iOS注意:在iOS上,你可以通过确定应用程序的状态来确定是否是应用程序由于用户点击了动作按钮而启动,或通知被提交给已经运行的应用。通过委托实现application:didReceiveLocalNotification:方法,获取应用程序的applicationState属性值并判定它。如果值为UIApplicationStateInactive,表明用户单击了动作按钮。如果值为UIApplicationStateAction,表明应用收到此通知的时候已经运行在前台。

实例3:

iOS应用程序的委托了application:didFinishLaunchingWithOptions:方法来处理本地通知。它使用键UIApplicationLaunchOptionsLocalNotificationKey从加载选项里面的字典获取了一个相关的UILocalNotification对象。从UILocalNotification对象的userInfo字典里面。它获取任何项目(这是通知的目的),并使用它来设置程序的初始化上下文。在该实例中,作为通知的一部分,你应该正确地重置应用程序图标的数字,或者如果没有额外的任务时把它移除。

//声音播放
static SystemSoundID shake_sound_male_id = 0;
#pragma mark 播放声音
- (void)playSound{
    NSString* sound = [[NSUserDefaults standardUserDefaults]objectForKey:@"sound"];
    NSArray* soundArr = [sound componentsSeparatedByString:@"."];
    NSString *path = [[NSBundle mainBundle] pathForResource:[soundArr objectAtIndex:0] ofType:[soundArr objectAtIndex:1]];
    if (path) {
        //注册声音到系统
        AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path],&shake_sound_male_id);
        //播放注册的声音,(此句代码,可以在本类中的任意位置调用,不限于本方法中)
        AudioServicesPlaySystemSound(shake_sound_male_id);
    }
    //让手机震动
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}
//app在前台运行,通知时间到了,调用的方法
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    if (notification)
    {
        application.applicationIconBadgeNumber = 0;
        application.applicationIconBadgeNumber = 1;
        application.applicationIconBadgeNumber = 0;
        UIApplicationState state = application.applicationState;
        if (state == UIApplicationStateActive){
            //当程序处于活跃状态时
            [self playSound];
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"时间提醒" message:notification.alertBody delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
            [alert show];
        }else if(state == UIApplicationStateInactive){
            //程序运行在后台时,点击启动程序按钮时
            NSLog(@"后台点击进入");
        }
    }
}
#pragma mark -UIAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    //停止播放声音
    AudioServicesDisposeSystemSoundID(shake_sound_male_id);
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
    application.applicationIconBadgeNumber = 1;
    application.applicationIconBadgeNumber = 0;
}

4、处理本地通知适配iOS8

iOS8拥有了全新的通知中心,有全新的通知机制。当屏幕顶部收到推送时只需要往下拉,就能看到快捷操作界面,并不需要进入该应用才能操作。在锁屏界面,对于推送项目也可以快速处理。基本上就是让用户尽量在不离开当前页面的前提下处理推送信息,再次提高处理效率。能够进行互动的短信、邮件、日历、提醒,第三方应用,可以让你不用进入程序就能进行快捷操作,并专注于手中正在做的事情。但这些的前提下,iOS8需要申请权限,注册通知。

实例4:

//ios8 注册本地通知
if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
    UIUserNotificationSettings *noteSetting =[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:noteSetting];
}

实例6:

添加快捷回复按钮,首先需要注册行为

  • ①、注册接受行为
//接受按钮
UIMutableUserNotificationAction *acceptAction = [[UIMutableUserNotificationAction alloc] init];
acceptAction.identifier = @"acceptAction";//按钮的标示
acceptAction.title = @"接受";//按钮的标题
acceptAction.activationMode = UIUserNotificationActivationModeForeground;//当点击的时候启动程序
  • ②、注册拒绝行为
//拒绝按钮
UIMutableUserNotificationAction *rejectAction = [[UIMutableUserNotificationAction alloc] init];
rejectAction.identifier = @"rejectAction";
rejectAction.title = @"拒绝";
rejectAction.activationMode = UIUserNotificationActivationModeBackground;//当点击的时候不启动程序,在后台处理
rejectAction.authenticationRequired = YES;//需要解锁才能处理,如果action.activationMode = UIUserNotificationActivationModeForeground;则这个属性被忽略;
rejectAction.destructive = YES;
  • ③、创建动作(按钮)的类别集合
UIMutableUserNotificationCategory *categorys = [[UIMutableUserNotificationCategory alloc] init];
categorys.identifier = @"alert";//这组动作的唯一标示
[categorys setActions:@[acceptAction,rejectAction] forContext:(UIUserNotificationActionContextMinimal)];
  • ④、创建UIUserNotificationSettings,并设置消息的显示类类型
UIUserNotificationSettings *uns = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound) categories:[NSSet setWithObjects:categorys,nil]];
  • ⑤、注册推送
 [[UIApplication sharedApplication] registerUserNotificationSettings:noteSetting];
  • ⑥、发起本地推送消息
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.alertBody = @"测试推送的快捷回复";
notification.category = @"alert"; //同上创建类的动作的唯一标识符一样
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
  • ⑦、注册成功
//本地推送通知
-(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    //成功注册registerUserNotificationSettings:后,回调的方法
    NSLog(@"%@",notificationSettings);

}
  • ⑧、收到本地消息
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    //收到本地推送消息后调用的方法
    NSLog(@"%@",notification);
}
  • ⑨、快捷回复按钮
-(void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler { //在非本App界面时收到本地消息,下拉消息会有快捷回复的按钮,点击按钮后调用的方法,根据identifier来判断点击的哪个按钮,notification为消息内容 NSLog(@"%@----%@",identifier,notification); completionHandler();//处理完消息,最后一定要调用这个代码块 }
  • ⑩、取消本地通知
// 获得 UIApplication
UIApplication *app = [UIApplication sharedApplication];
//获取本地推送数组
NSArray *localArray = [app scheduledLocalNotifications];
if (localArray) {
    for (UILocalNotification *noti in localArray) {
        NSDictionary *dict = noti.userInfo;
        if (dict) {
            NSString *inKey = [dict objectForKey:@"key"];
            if ([inKey isEqualToString:@"sound"]) {
                [[UIApplication sharedApplication]cancelLocalNotification:noti];
                break;
            }
        }
    }
}

你可能感兴趣的:(ios,本地通知)