iOS 7中的静默推送通知无法正常工作

88
在 WWDC 2013 的“多任务处理的新功能”演示中,有一个关于静默推送通知的部分。这似乎很简单。根据演示,如果您只发送带有 content-available 设置为1 的 APS 负载,则用户不会收到通知。
// A. This doesn't work
{ 
  aps: { 
          content-available: 1 
       }
}

我的测试显示这不起作用,因为没有收到推送。但是如果我包括声音属性但不包括警报属性,它就可以工作(虽然不再是静音的)。

// B. This works
{ 
  aps: {
          content-available: 1,
          sound: "default"
       }
}

然而,如果我将声音属性更改为播放静音音频,则可以模拟静默推送。
// C. This works too.
{ 
  aps: {
          content-available: 1,
          sound: "silence.wav"
       }
}

有人知道吗:

  1. 这是一个bug吗?
  2. 如果B或C被视为远程通知(而不是需要声音属性的静默推送的错误),那么这是否正确?如果是,这意味着它不像Silent Pushes那样受到速率限制...这是苹果可能会修复的。因此,我可能不应该依赖它。
  3. 速率限制是什么(每个X秒的N次推送等)?

使用更多信息进行编辑

对于A,应用程序的状态并不重要。永远不会收到通知。

如果您在引号中括住属性和值,似乎B和C才可以正常工作,如下所示。

{"aps":{"content-available": 1, "sound":"silent.wav"}}

无论应用程序处于什么状态,通知都会在 application:didReceiveRemoteNotification:fetchCompletionHandler: 中到达。


它在任何应用程序状态下都无法工作吗?对我来说,“A”只要应用程序在前台运行(didReceiveRemoteNotification被调用),就可以工作。但是当应用程序没有运行时,应用程序不会收到通知(当我尝试“B”时,我只听到声音)。当您使用“B”或“C”时,您的应用程序是否在后台被唤醒(didReceiveRemoteNotification)? - DerBernie
我看到了类似的行为,我认为这可能是因为我尝试了一段时间,一开始没有正确设置应用程序,所以在我正确设置之前,苹果可能已经对我进行了限制。 - nickthedude
4
兄弟...我希望我能给你10个投票。 - Michael Wiles
请检查项目能力>后台模式中的后台获取复选框,因为第一个选项应该可以工作。静默推送不需要声音属性,并且始终在application:didReceiveRemoteNotification:fetchCompletionHandler:中到达,即使应用程序在后台/前台运行或未运行。 - IgniteCoders
已经是2021年了,我一直在开发我的应用程序,并打算使用静默推送通知,但直到我偶然看到这篇文章之前,我都无法接收到它。很奇怪,但在有效载荷中有“声音”关键字确实起了作用。感谢您将此分享给社区。希望有人能够在某个时候提供一个合理的解释。致敬。 - Amit Khetan
11个回答

73

这个也可以工作,并且在到达时不播放声音:

{
    aps = {
        "content-available" : 1,
        sound : ""
    };
}

编辑

遇到此问题的人可能希望查看此链接。我一直在参与一些关于应用程序状态以及何时接收和不接收静默推送的讨论,而这个链接涵盖了所有这些内容,该讨论在苹果的开发者论坛上。


谢谢提供的链接。ADC论坛上有多个主题讨论了这个问题。总之就是设备重启后有一个bug,苹果代表承认会在更新中修复(最终)。 - SG1
3
即使没有声音/提醒键,在iOS7中它的表现非常好。 content-available是足够的关键字!但在iOS8中,即使我们设置了带有非空字符串的提醒键并添加了"content-available":1,我们仍然会得到只有"alert"字符串的横幅通知,但由于某些原因,"content-available"被忽略了,这是一种非常奇怪的行为。 - malex
我已经成功地通过通知启动应用程序,无论是否添加了声音。也许,设置声音、警报或徽章(空的或非空的)会将默认通知优先级提高到10,从而增加其可靠性。请参阅苹果关于 pans-priority 的说明: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/APNsProviderAPI.html 默认优先级为10(高),但仅使用 content-available 键的推送通知使用此优先级是错误的。因此,如果仅设置了 content-available 键,则默认值可能设置为5。 - emem
1
无法在iOS10上运行。我必须将某些东西推送到“声音”。 - Stony
1
编辑中的苹果开发者论坛帖子链接似乎已经失效。我知道这已经是很久以前的事了,但是有没有人恰好有更新后的链接(或该帖子的标题)? - Evan Kirkwood
显示剩余2条评论

30

昨天我刚碰到了这个问题,尝试将音频设置为空字符串作为有效信息发送,但它仍然会在设备上造成振动和声音。最终,我偶然发现Urban Airship的一篇博客文章中建议需要发送以下内容:

{ priority: 5 }

在我从未见过的推送通知中,我浏览了一下苹果的推送通知文档,然后偶然发现了这个页面:

https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html

该页面指出应将优先级设置为“5”或“10”,并解释了如下内容:

通知的优先级,请提供以下值之一:

10:立即发送推送消息。

该推送通知必须在设备上触发警报、声音或徽章。对于仅包含content-available键的推送,使用此优先级是错误的。

5:在节省接收设备电量的时间发送推送消息。

最终,我们使用以下格式使静默推送通知与徽章计数(我猜你甚至可以使用警报来实现同样的效果)一起正常工作:

    aps =     {
        badge = 7;
        "content-available" = 1;
        priority = 5;
    };

太棒了,Dave!允许使用优先级5,但“对于只包含content-available键的推送,使用此优先级[10]是错误的。” https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html - rjobidon
4
优先级是否应该包含在有效载荷中?在我看来,它可以作为一个单独的字节在您发送的推送消息中发送。 - Foriger
6
优先级不会在有效载荷中设置,而是在二进制通知中设置。 - Sandy D.

10

我曾尝试将警报属性设置为空字符串,也能正常工作:

{
    aps =     {
        "content-available" = 1;
        "alert" = "";
    };
}

看起来APNS正在检查这些属性的存在,以验证推送负载。有趣的是,它们并没有检查实际内容。尽管这似乎有点不正规...


这个在负载中使用alert=""的解决方案对我在iOS 9.0上也起作用了。相反,sound=""没有起作用。 - loretoparisi

6

我使用工具-Knuff 将推送通知发送到我的设备。

它看起来像这样: enter image description here

然后,我尝试了这些示例。

它们都有效!但你必须将优先级设置为10!

所以如果你不使用这个工具,也要注意一下。


示例:

  • 没有警报,没有声音

{
    "aps":{
        "content-available":1,
    }
}

  • 仅弹出提醒窗口

{
    "aps":{
        "content-available":1,
        "alert":""
    }
}

  • 仅声音

{
    "aps":{
        "content-available":1,
        "sound":""
    }
}


4
这对我有用:
注:此处为html标签,请勿删除。
{ 
  aps: { 
          content-available: 1 
       }
}

如果您在项目功能>后台模式中勾选了后台获取复选框,则会发生以下情况:


2

我也遇到了同样的问题。如果我发送一个具有 "content-available":1 但没有设置其他属性的推送通知,那么该通知将永远不会被接收到。当我添加任何其他属性时,它就可以正常工作。

作为临时解决办法,我添加了 badge 属性,因为这不会以任何方式提醒用户,只是将徽章添加到图标上。

如果你找到了更好的解决方案,请让我知道。


1

优先级应该在二进制流中设置为一个项目,而不是在有效负载JSON字符串中设置。显然,只有最新的类型2格式可以用于按以下方式设置优先级:

$token      = chr(1) . pack('n', 32)     . pack('H*', $deviceToken);
$payload    = chr(2) . pack('n', strlen($json)) . $json;
$identifier = chr(3) . pack('n', 4)      . pack('N', $notification);
$expiration = chr(4) . pack('n', 4)      . pack('N', time()+86400);
$priority   = chr(5) . pack('n', 1)      . chr($priority);

$frame_data = $token.$payload.$identifier.$expiration.$priority;
$frame_length = strlen(bin2hex($frame_data))/2;

$msg = chr(2) . pack('N', $frame_length) . $frame_data;

远程通知二进制消息的格式类型(第一个字节):

0 - 简单(旧版) 1 - 增强(旧版) 2 - 最新的,带有更多参数(新版)


0
我们遇到了同样的问题,即没有传递通知。在我们的情况下,我们使用静默推送来更新徽章数字。当我们将警报(正文和标题)和声音设置为空字符串时,它可以工作,但如果任何键不存在,则会失败。以下是有效的方法,使用无声或警报更新徽章(在didReceiveRemoteNotification中的userInfo字典日志中):
{
    aps =     {
        alert =         {
            body = "";
            title = "";
        };
        badge = 103;
        "content-available" = 1;
        sound = "";
    };
}

0

啊!我也快被逼疯了——这不是一个答案,只是另一个例子,说明这个有效负载并不起作用。即使设备处于睡眠状态,didReceiveRemoteNotification方法也从未被调用,但警报文本确实会显示。

 {"aps":
    {  "alert":"alert!",
       "sound":"default",
       "content-available" : 1},
    "content-id":21482,
    "apt":"1"
}

"

"apt"是我们用来指示通知类型的自定义字段。

"

2
如果应用程序在后台,并且您删除了“alert”属性,则应在application:didReceiveRemoteNotification:fetchCompletionHandler:回调中接收到通知。 - evalsyrelec
@mkwon 如果我想在后台时看到警报(常规推送)+调用application:didReceiveRemoteNotification:fetchCompletionHandler:?谢谢 - DaNLtR

0

将“声音”设置为0对我有用... :)


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