在后台时的 didReceiveRemoteNotification

发布于 2024-10-18 09:28:17 字数 302 浏览 3 评论 0原文

此类问题已被问过多次,但我遇到了一些具体情况。

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

但是,当我的应用程序位于后台并且推送到达时,用户必须单击“查看/打开”按钮才能调用 didReceiveRemoteNotification 并且 didFinishLaunchingWithOptions 是之后打电话。

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

任何帮助将不胜感激,

These kind of question has been asked a number of times but i have some specific situation going on.

When my application is active and I receive a PUSH message i'm successfully able to parse the custom payloads and such.

However when my application is in the background and the PUSH arrives the user has to click on the 'View/Open' button in order to get the didReceiveRemoteNotification called and the didFinishLaunchingWithOptions is called after that.

I need to have my application decide if they have to prompt the user with an UIAlert when in the background or suppress the push message based on some local settings.

Any help would be appreciated,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

原谅过去的我 2024-10-25 09:28:17

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

  • 您的应用程序刚刚启动

  • 您的应用程序刚刚从后台转到前台

  • 您的应用程序已在前台运行

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

您可以使用以下代码在 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
    ...
}

You app needs to handle all the possible push notification delivery states:

  • Your app was just launched

  • Your app was just brought from background to foreground

  • Your app was already running in the foreground

You do not get to choose at delivery time what presentation method is used to present the push notification, that is encoded in the notification itself (optional alert, badge number, sound). But since you presumably are in control of both the app and the payload of the push notification, you can specify in the payload whether or not there was an alert view and message already presented to the user. Only in the case of the app is already running in the foreground do you know that the user did not just launch your app through an alert or regularly from the home screen.

You can tell whether your app was just brought to the foreground or not in didReceiveRemoteNotification using this bit of code:

- (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
    ...
}
携君以终年 2024-10-25 09:28:17

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

首先,在服务器端,您必须设置 {"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。

我希望它会有用。 Apple 对此进行了解释

You have to do several things in order to manage the received push notification when the app is in background.

First, in your server side, you have to set {"aps":{"content-available" : 1... / $body['aps']['content-available'] =1; in the push notification payload.

Second, in your Xcode project, yo have to habilitate "remote notifications". It is made by going to the project's target -> capabilities, then enable the capabilities switch, and check the remote notifications checkbox.

Third, instead of using didReceiveRemoteNotification, you have to call application:didReceiveRemoteNotification:fetchCompletionHandler:, this will allow you to do the tasks that you want in the background, at the moment of receiving the notification:

- (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);
     }
 }

Finally, you have to add this notification type: UIRemoteNotificationTypeNewsstandContentAvailability to the notifications settings when you set it.

Apart from this, if your app was closed when the notification arrived, you have to manage this in didFinishLaunchingWithOptions , and just if the user taps on the push notification: The way of do it is:

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

    if (dictionary != nil)
    {
        NSLog(@"Launched from push notification: %@", dictionary);
        [self manageRemoteNotification:dictionary];
    }
}

launchOptions is != nil when you launch the app by tapping on the push notification, if you access it by tapping on the icon, launchOptions will be == nil.

I hope it will be useful. Here it is explained by Apple.

淤浪 2024-10-25 09:28:17

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

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

Pass content-available = 1 with your payload, and will invoke didReceiveRemoteNotification even in background. e.g.

{
    "alert" : "",
    "badge" : "0",
    "content-available" : "1",
    "sound" : ""
}
感性 2024-10-25 09:28:17

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

One thing to keep in mind, when your push message arrives at the user's iPhone and they click "cancel", except for the icon badge number (they'll be taken care of by the OS), there would be no way for your in-the-background app to know about this push event and take any further actions.

鸠魁 2024-10-25 09:28:17

警告语

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

因为 文档还指出这是最佳实践。因为 Apple 并不保证您的推送通知能够 100% 被收到。

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

但是,如果您想要获得一些指示,例如徽章是否已更改,而不依赖于用户通过单击徽章打开应用程序,您可以这样做:

A. 您添加一个 (正确)徽章编号添加到服务器发送的推送通知的有效负载中。例如,它可能如下所示:

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

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

然后在 applicationDidBecomeActive 中可以将 UIApplicationapplicationIconBadgeNumber 属性与您之前存储的徽章计数进行比较,看看它是否增加或减少并进行一些更新基于此。

 - (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
        }

    }

Word of warning

I think your app logic is basing behavior on custom data in your push notification. This is not what push notifications are intended for. What you should alternatively do on didbecomeactive in your application is just ask your server for the data you need and was sending as payload anyway, and rely on that instead of your payload.

Because the documentation also states that as best practice. Because Apple does not guarantee your push notification from being received 100% of the times anyway.

Important: Delivery of notifications is a “best effort”, not
guaranteed. It is not intended to deliver data to your app, only to
notify the user that there is new data available.

However, if you want to have some indication of whether for instance the badge has been changed without relying on a user opening the app by clicking on the badge you could something like this:

A. you add a (correct) badge number to the payload of the push notification sent by your server. It for instance could look like this:

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

B. you keep track of that badge number persistently in your app, for instance by storing it in NSUserDefaults.

Then in applicationDidBecomeActive can compare the applicationIconBadgeNumber property of UIApplication with your previously stored badge count and see if it has been increased or decreased and do some updates based on that.

 - (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
        }

    }
滿滿的愛 2024-10-25 09:28:17

从最近的 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
    }
}

As of recent iOS - I think 8 - if you've got remote notifications enabled as a background mode, one trick is to track whether you're entering the foreground as a flag.

@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
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文