当应用程序在后台运行时,通过推送通知更新徽章。

99

我已经成功实现了推送通知,并且在应用程序回到前台时成功更新了图标徽章计数。

但是,我有些困惑...iPhone接收到通知后,弹出消息似乎激活了我的应用程序,并且仅在我启动应用程序后才更新了徽章。

从用户体验的角度来看,这听起来不太对。我理解徽章计数应该通过递增的计数通知用户需要采取行动的内容,但是在应用程序处于后台时发生这种情况似乎不可能。

那么有没有一种方法可以告诉应用程序在接收到推送通知并处于后台时更新其徽章计数呢?

请注意,我的应用程序不使用位置信息,并且在通知注册请求中使用了UIRemoteNotificationTypeBadge

12个回答

97

由于推送通知是由iOS处理而不是您的应用程序,因此您无法在接收到推送通知时更改应用程序徽章。

但是,您可以在推送通知的有效负载中发送徽章数字,但是您需要在服务器端进行计算。

您应该阅读本地和远程通知编程指南,特别是通知有效负载

有效载荷可能如下所示:

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

现在应用程序徽章图标将显示9。


4
我已经在做这件事情了...但这个值只有在我的应用程序被带到前台时才会被检索出来,然后我使用它来更新徽章值,使用 [UIApplication sharedApplication].applicationIconBadgeNumber = count;。 - Abolfoooud
7
不,你需要在推送通知负载中设置徽章号码。 - rckoenes
13
我再次查看了我的有效载荷结构,似乎我将徽章参数的值作为字符串'4'传递,而不是整数4!!!现在它可以工作了...感谢帮助。 - Abolfoooud
1
@wod 你的意思是什么:更改有效载荷结构徽章? - rckoenes
2
实际上,在iOS 10中,应用程序已经完全支持此功能。请查看下面我的回答。https://dev59.com/hGYq5IYBdhLWcg3wui0z#53159748 - Gkiokan
显示剩余3条评论

28

实际上,在iOS 10中,远程通知会自动调用您的AppDelegate中的didReceiveRemoteNotification方法。

您有两种方法可以在后台更新标记计数。
我也为我的当前应用程序完成了这项工作。 您不需要使用通知服务扩展。

第一种方式:

将APS标记键与有效负载一起发送到APN。
这将根据有效负载中的整数值更新标记计数。例如:

// Payload for remote Notification to APN
{
    "aps": {
        "content-available": 1,
        "alert": "Hallo, this is a Test.",
        "badge": 2, // This is your Int which will appear as badge number,
        "sound": default
    }
}

第二种方法:

当应用程序处于.background状态时,您可以切换应用程序的applicationState并更新您的徽章计数。但是,在向APN发送通知负载时,请注意不要设置徽章键参数。

// Payload to APN as silent push notification
{
    "aps": {
        "content-available": 1
    }
}

根据应用程序状态处理徽章更新:

这里是我的工作代码,用于在APN负载中没有徽章密钥的情况下更新徽章计数。

func application(_ application: UIApplication, didReceiveRemoteNotification 
   userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    print("APN recieved")
    // print(userInfo)
    
    let state = application.applicationState
    switch state {
        
    case .inactive:
        print("Inactive")
        
    case .background:
        print("Background")
        // update badge count here
        application.applicationIconBadgeNumber = application.applicationIconBadgeNumber + 1
        
    case .active:
        print("Active")

    }
}

重置徽章计数:

当您的应用程序恢复到活动状态时,请不要忘记重置您的徽章计数。

func applicationDidBecomeActive(_ application: UIApplication) {
    // reset badge count
    application.applicationIconBadgeNumber = 0
}

如果应用程序没有在后台运行,如何更新徽章? - Nagendra Rao
3
如果您使用带有 content-available 键的 APS 发送通知,则无论应用程序的状态如何,它都会运行 didReceiveRemoteNotification 方法。请尝试在本机设备上测试一下。如果您正在使用 iOS 设备,可以使用此工具将 JSON 对象发送到 APN:https://github.com/noodlewerk/NWPusher - Gkiokan
1
哇,太棒了!那如果我发送一个没有 content-available 的通知呢?(任何非后台通知) didReceiveRemoteNotification 不会被调用。 - StackExploded
第二种方式我仍然可以使用声音和警报吗? - submariner
@submariner 好久不见了,但我记得不行。你必须自己在状态案例中完成这个操作,即 .background。徽章也是如此。如果你将其发送到 aps 对象中,则可能会起作用。如果不行,你只需按照所述自己定义它。 - Gkiokan

12

当我们处于后台状态时,我们可以通过在推送通知包中发送"badge"参数来更改徽章数字。正如@rckoenes所指出的那样,徽章的JSON参数必须为整数

执行相同操作的示例PHP代码

// Create the payload body
$body['aps'] = array(
        'alert' => $message,
        'badge' => 1,
        'sound' => 'default'
        );

徽章 => 1,其中1是一个整数而不是字符串(即没有引号)。


8
    **This is the APNS payload get back from server.**

    {
        "aps" : {
            "alert" : "You got your emails.",
            "badge" : 9,
            "sound" : "bingbong.aiff"
        },
        "acme1" : "bar",
        "acme2" : 42
    }

键为badge的值会自动被视为徽章计数。在iOS应用程序端不需要计算或处理计数。 在上述示例中,9是徽章计数。因此,您的应用程序图标将显示9。

注意:当您的应用程序关闭时,您无法自己处理徽章。这就是为什么我们从APNS负载中使用badge键的原因。 有关通知的更好澄清,请参阅文档。

如果您想自行减少徽章计数。请按如下方式递减计数并更新:


7
如果您正在使用NotificationServiceExtension,则可以在其中更新徽章。
var bestAttemptContent : UNMutableNotificationContent? // 
bestAttemptContent.badge = 0//any no you wanna display

每次您的应用程序收到通知时,都会调用您的服务扩展。将该值保存在用户默认设置中并显示出来。 要在应用程序和扩展之间共享用户默认设置,您需要在应用程序中启用应用程序组。 在此处阅读更多信息

你可以将通知计数保存在服务器上,并与通知一起发送。 - Surjeet Rajput
我使用Firebase云消息传递,你知道怎么做吗? - Ghiggz Pikkoro

5
对于Firebase Cloud Messaging(FCM),应该像这样:
{
  "to": "some_token",

  "notification": {
    "body": "this is a body",
    "title": "this is a title",
    "badge" : 1
  }, 

  "priority": "high", 
}

3

1
在APNS负载中,必须定义"content-available":1以在后台模式下更新徽章计数。
func application(_ application: UIApplication, didReceiveRemoteNotification 
   userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {


// increase badge count, but no need if you include content-available

application.applicationIconBadgeNumber = application.applicationIconBadgeNumber + 1

}

func applicationDidBecomeActive(_ application: UIApplication) {

// reset badge count

application.applicationIconBadgeNumber = 0

}

for eg.

"aps":{
    "alert":"Test",
    "sound":"default",
    "content-available":1

}

content-available = 1 的目的是为了静默通知而不是徽章。 - Manish

1
在旧系统中,它可以工作,“徽章”设置计数。
{
  "to": "token",
  "notification": {
    "title": "Example",
    "body": "Tiene 22 actualizaciones.",
    "badge":278
  },
  "data": {
    "story_id": "story_12345",
    "count_vaca":22
  }
}

0
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

    application.applicationIconBadgeNumber = 0;
    NSLog(@"userInfo %@",userInfo);

    for (id key in userInfo) {
        NSLog(@"key: %@, value: %@", key, [userInfo objectForKey:key]);
    }

    [application setApplicationIconBadgeNumber:[[[userInfo objectForKey:@"aps"] objectForKey:@"badge"] intValue]];
    NSLog(@"Badge %d",[[[userInfo objectForKey:@"aps"] objectForKey:@"badge"] intValue]);
}

你为什么使用intValue而不是一个NSInteger的integerValue?@property (readonly) NSInteger integerValue NS_AVAILABLE(10_5, 2_0); - Alex Zavatone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接