在后台使用didReceiveRemoteNotification

时间:2011-02-20 11:21:03

标签: iphone ios4 apple-push-notifications

这种问题已被多次询问,但我有一些特定的情况正在发生。

当我的应用程序处于活动状态并且收到PUSH消息时,我已成功解析自定义有效负载等。

但是,当我的应用程序在后台并且PUSH到达时,用户必须单击“查看/打开”按钮才能调用didReceiveRemoteNotification并在此之后调用didFinishLaunchingWithOptions

我需要让我的应用程序决定是否必须在后台提示用户使用UIAlert,或者根据某些本地设置禁止推送消息。

任何帮助将不胜感激,

6 个答案:

答案 0 :(得分:148)

您的应用需要处理所有可能的推送通知递送状态:

  • 您的应用刚刚推出

  • 您的应用只是从背景到前景

  • 您的应用已在前台运行

您无法在交付时选择使用哪种演示方法来呈现推送通知,该推送通知在通知本身中编码(可选警报,徽章编号,声音)。但是,由于您可能控制了推送通知的应用程序和有效负载,因此您可以在有效负载中指定是否已经向用户显示了警报视图和消息。只有在应用程序已经在前台运行的情况下,您才知道用户不是通过警报或定期从主屏幕启动您的应用程序。

您可以使用以下代码判断您的应用是否只是在didReceiveRemoteNotification中被带到了前台:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateActive )
        // app was already in the foreground
    else
        // app was just brought from background to foreground
    ...
}

答案 1 :(得分:13)

content-available = 1与您的有效负载一起传递,即使在后台也会调用didReceiveRemoteNotification。 e.g。

{
    "alert" : "",
    "badge" : "0",
    "content-available" : "1",
    "sound" : ""
}

答案 2 :(得分:12)

当应用程序处于后台时,您必须执行多项操作才能管理收到的推送通知。

首先,在服务器端,您必须在推送通知有效负载中设置{"aps":{"content-available" : 1... / $body['aps']['content-available'] =1;

其次,在您的Xcode项目中,您必须支持“远程通知”。它是通过转到项目的目标 - >功能,然后启用功能切换,并选中远程通知复选框。

第三,不必使用didReceiveRemoteNotification,而是必须致电application:didReceiveRemoteNotification:fetchCompletionHandler:,这样您就可以在收到通知时在后台执行您想要的任务:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler 
{

 if(application.applicationState == UIApplicationStateInactive) {

     NSLog(@"Inactive - the user has tapped in the notification when app was closed or in background");
     //do some tasks
    [self manageRemoteNotification:userInfo];
     completionHandler(UIBackgroundFetchResultNewData);
 }
 else if (application.applicationState == UIApplicationStateBackground) {

     NSLog(@"application Background - notification has arrived when app was in background");
     NSString* contentAvailable = [NSString stringWithFormat:@"%@", [[userInfo valueForKey:@"aps"] valueForKey:@"content-available"]];

     if([contentAvailable isEqualToString:@"1"]) {
         // do tasks
         [self manageRemoteNotification:userInfo];
         NSLog(@"content-available is equal to 1");
         completionHandler(UIBackgroundFetchResultNewData);
     }
 }
 else {
     NSLog(@"application Active - notication has arrived while app was opened");
        //Show an in-app banner
         //do tasks
        [self manageRemoteNotification:userInfo];
         completionHandler(UIBackgroundFetchResultNewData);
     }
 }

最后,您必须在设置时将此通知类型UIRemoteNotificationTypeNewsstandContentAvailability添加到通知设置中。

除此之外,如果您的应用在通知到达时关闭了,您必须在didFinishLaunchingWithOptions中进行管理,并且只需用户点按推送通知:执行此操作的方式是:

if (launchOptions != nil)
{
    NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    if (dictionary != nil)
    {
        NSLog(@"Launched from push notification: %@", dictionary);
        [self manageRemoteNotification:dictionary];
    }
}
当你通过点击推送通知启动应用程序时,

launchOptions是!= nil,如果你通过点击图标来访问它,那么launchOptions将是== nil。

我希望它会有用。 Here it is explained by Apple

答案 3 :(得分:7)

要记住的一件事是,当您的推送消息到达用户的iPhone并且他们点击“取消”时,除了图标徽章编号(他们将由操作系统处理),将无法为您的在线应用程序了解此推送事件并采取任何进一步的操作。

答案 4 :(得分:2)

警告语

我认为您的应用逻辑基于推送通知中的自定义数据行为。这不是推送通知的目的。您应该在应用程序中didbecomeactive上执行的操作只是向您的服务器询问您需要的数据,并且无论如何都要作为有效负载发送,并依赖它而不是您的有效负载。

因为the documentation also states是最佳做法。因为Apple不保证您的推送通知无论如何都会被收到100%的时间。

  

重要提示:发送通知是“尽力而为”,而不是   保证。它不是为了向您的应用提供数据,而只是为了   通知用户有新数据可用。

但是,如果您希望在不依赖用户通过点击徽章打开应用程序的情况下更改徽章是否已更改,则可能会出现以下情况:

A。您将(正确的)徽章编号添加到服务器发送的推送通知的有效内容中。例如,它看起来像这样:

{
    "aps" : {
        "alert" : "You got your emails.",
        "badge" : 9
    }
}

B。您可以在应用中持续跟踪该徽章编号,例如将其存储在NSUserDefaults中。

然后在applicationDidBecomeActive中可以将applicationIconBadgeNumber UIApplication属性与之前存储的徽章计数进行比较,看看它是否已增加或减少,并根据该值进行更新。

 - (void)applicationDidBecomeActive:(UIApplication *)application
    {

        NSNumber *badgecount = [[NSUserDefaults standardUserDefaults] objectForKey:@"badgecount"];
        if (!badgecount) badgecount = @(0);

        if ([UIApplication sharedApplication].applicationIconBadgeNumber != [badgecount integerValue]) {
            //store the new badge count
            badgecount = [NSNumber numberWithInteger:[UIApplication sharedApplication].applicationIconBadgeNumber];
            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
            [defaults setObject:badgecount forKey:@"badgecount"];
            [defaults synchronize];

            // do some stuff here because it's different
        }

    }

答案 5 :(得分:0)

截至最近的iOS - 我认为8 - 如果您已将远程通知作为后台模式启用,则一个技巧是跟踪您是否将前景作为标记进入。

@interface AppDelegate ()

@property (assign, atomic, getter=isEnteringForeground) BOOL enteringForeground;

@end

- (void) applicationWillEnterForeground: (UIApplication *) application
{
    self.enteringForeground = YES;
}

- (void) applicationDidBecomeActive: (UIApplication *) application
{
    self.enteringForeground = NO;
}

- (void) application: (UIApplication *) application didReceiveRemoteNotification: (NSDictionary *) userInfo fetchCompletionHandler: (void (^) (UIBackgroundFetchResult)) completionHandler
{
    const BOOL launchedFromBackground = !(application.applicationState == UIApplicationStateActive);
    const BOOL enteringForeground = self.enteringForeground;

    if (launchedFromBackground && enteringForeground) {
        // The user clicked a push while the app was in the BG
    }
}