一、 关于本地通知

本地通知,就是应用完成某个任务的时候发送一些提示。在APP打开的情况下,如果不对本地通知做任何界面显示的话,那么看不到界面有任何变化。如果用户点击Home以后,App在后台有3分钟的运行时间的话(即App在后台运行),那么本地通知就会以信息提示栏的形式显示在手机上面,和离线消息推送的效果一样。。如果用户点击Home以后,你的App处于挂起状态,那个发送了的本地通知并不是说永远不会执行了,而是当前你的重新进入应用以后,它还会继续执行。

二、遇到的问题

我的App对本地通知的处理要求:
1.当用户点击Home键以后,App有大概3分钟的后台运行时间。
2.如果用户正在使用App,当有本地通知时,以Alert的形式显示出来。
3.如果用户在使用App的时候点击了Home键,在3分钟内如果有通知到来,那么需要在通知栏中显示本地通知内容。

在实现以上需求时遇到的问题:
当用户点击Home键,在3分钟内有本地通知到达时,如果等本地通知的通知栏消失时,再通过点击app的图标进入app则一切正常。但是,如果点击通知栏进入App时,会有Alert消息弹出来,即本地通知显示了两次。

三、解决方法

把App的状态分为前台(InForeground)和后台(InBackground)两种情况,当发送本地通知的时候,把App的状态作为一个value保存在通知的userInfo字典中。在AppDelegate中判断接收的通知是app在前台发送的还是在后台发送的,如果是在前台发送的,则正常显示alert信息,如果是在后台发送的,那么就直接return。

四、代码

发送通知的代码:

/**
 *  Post a local notification
 *
 *  @param info         info notification content
 *  @param time         How many seconds after sending notification.
 *  @param isBackground YES:app run in background   NO:app run in foreground.
 */
+ (void)postLocalNotificationWithInfo:(NSString *)info andTimeSinceNow:(NSInteger)time inBackground:(BOOL)isBackground
{
    UILocalNotification *localNotification = [[UILocalNotification alloc] init];
    localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:time];
    localNotification.timeZone = [NSTimeZone defaultTimeZone];
    localNotification.alertBody = info;
    localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
    localNotification.soundName = UILocalNotificationDefaultSoundName;

    NSMutableDictionary *userDict = [NSMutableDictionary dictionaryWithObject:info forKey:@"localNofiKey"];
    isBackground ? [userDict setValue:@"inBackground" forKey:@"AppStatus"] : [userDict setValue:@"inForeground" forKey:@"AppStatus"];

    localNotification.userInfo = userDict;

    if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        UIUserNotificationType type =  UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type
                                                                                 categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    }
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}

AppDelegate中对本地通知处理的代码:

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    NSString *statusApp = [notification.userInfo objectForKey:@"AppStatus"];
    if ([statusApp isEqualToString:@"inBackground"]) {
        return;
    }
    NSString *nofiInfo = [notification.userInfo objectForKey:@"localNofiKey"];

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Upload Message"
                                                    message:nofiInfo
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];


    [alert show];
    dispatch_time_t dismissTime = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
    dispatch_after(dismissTime, dispatch_get_main_queue(), ^{
        [alert dismissWithClickedButtonIndex:1 animated:YES];
    });
    [alert release];
}

注意:至于如何判断App是在前台还是在后台,我们可以声明一个int变量,0是后台,1是前台。则通过在AppDelegate中的几个方法中设置这个变量的值。然后在需要发送通知的地方外部引用该变量。