iOS 中有哪些不同类型的通知以及如何正确配置它们?

What are different types of notifications in iOS and how to configure them correctly?

当我阅读 Apple Docs 时,他们提到了 3 种类型的通知:本地、远程和静默。

本地通知可以从名称推断出来,由应用在本地发送。

但是,其他两种有什么区别呢?

推送通知会让用户知道他们收到了通知(例如显示通知弹出窗口)。静默通知将更新,但用户不会收到有关它的通知。 在任何情况下,您都可以在收到静默通知时执行操作,就好像它是推送通知一样。唯一的区别是用户不会收到弹出通知。

有推送通知:

无提示通知:

区别在于负载:

推送通知:

     aps {
       content-available: 1
       alert: {...}
     }

静默通知:

    aps {
      content-available: 0
      alert: {...}
    }

并且您必须在 Capabilities 中设置您选择的背景模式。

静默推送通知到达设备,用户对通知一无所知,但他的应用程序收到通知,应用程序将有一些时间下载新内容并将其呈现给用户,无论应用程序的状态如何(即 运行 或不 运行)

仅当您的应用 运行 时才会调用远程推送通知方法。如果应用挂起或未挂起 运行,则系统会唤醒或启动您的应用并将其置于后台 运行 状态,然后再调用该方法。 此方法用于向 user.When 显示更新的内容,调用此方法后,您的应用程序有最多 30 秒的 wall-clock 时间来执行下载操作并调用指定的完成处理程序块。如果没有及时调用处理程序,您的应用将被暂停。

有关更多技术细节,您可以访问此链接:

Apple Notifications

Silent Notifications

编辑: 虽然此答案完全适用,但 iOS 中的通知有一些 补充 (不是更改) 12. 我强烈推荐观看 WWDC 2018: What’s New in User Notifications and read this amazing and must read article.

主要变化是:

  • 分组通知和摘要格式
  • 临时通知,即未经用户许可直接在通知中心显示通知
  • 忽略'do not disturb'或'mute'
  • 的重要通知
  • 能够与扩展中的通知进行交互
  • 能够完全重置或更新操作
  • 能够从 phone 的通知中心
  • 深入link 应用程序的通知设置

重要说明: 不确定从什么时候开始,但从 Apple 文档中,'silent notification' 已 重命名 为 'background notification'

需要设置太多设置才能正常工作。我将尝试剖析它们并使它们更容易理解。

总的来说,有几件事很重要。

  • 静默用户通知
  • 之间的总体区别
  • 不同类型的用户通知
  • 如何从您的服务器
  • 配置远程通知,即有效载荷
  • 如何在项目的后台模式下启用推送通知和远程通知
  • 如何使用 APNs 为 remotesilent 通知和 APNs 架构注册您的令牌
  • 如何请求用户通知
  • 的权限
  • 设备
  • 启用'background app refresh'和'notifications'
  • 什么是content-available
  • 了解 iOS 在接收远程通知时 上游 您的应用
  • 如果 OS 在应用已 user-terminated
  • 收到通知时会发生什么
  • 关于可靠性和 APNs 架构的说明

强烈推荐大家观看WWDC 2015: What's new in Notifications的前7分钟。从那里,演示者提到有 2 种主要类型的通知:

静默通知

它们在后台发生,因此您永远看不到任何 alert/badge/sound。在您不知情的情况下下载了一些东西

iOS 11 bug

See here. iOS 11 initial releases were buggy for silent notifications. Make sure you have the latest version for your testing, otherwise, it may not work


用户通知

顾名思义,与用户有关。也就是说,用户将看到 alert/badge 或听到声音。它有两种类型。

本地通知

可以通过 3 种不同的方式触发本地通知:

  • UNLocationNotificationTrigger: 当您靠近沃尔玛商店时,您会看到一条提醒。

  • UNTimeIntervalNotificationTrigger:例如您每 10 分钟会看到一个警报。

  • UNCalendarNotificationTrigger 喜欢 12 月 1 日 1:00PM 2017.

远程通知

它们类似于本地通知,但它们是由服务器触发的,例如包含发件人字段(妈妈)和 body 字段(我爱你!)的 WhatsApp 消息。

令牌注册和 APNs 架构:

要接收静默或远程通知,您需要使用以下方式注册令牌:

application.registerForRemoteNotifications() 

注册不需要用户许可。这使得无声通知变得无缝。参见 this moment of the WWDC video

Silent notifications are enabled by default. The user does not need to approve your -- does not give permission to your app to use them, and you can just start using them without asking the user for permission.

From WWDC

记住 APNs 是由 APNs 而不是您的服务器提供给您的用户的。因此,您的 iOS 代码必须将此令牌发送到您的服务器。因此服务器可以将给定的设备令牌与用户相关联。当你想推送给某个用户时,你的服务器只是告诉 APNs 将有效负载发送到特定的令牌。重要的是要了解您的服务器和 APN 是两个不同的东西

它的流程是这样的:

  1. server/provider 向 APNs
  2. 发送有效载荷
  3. APNs 向给定帐户的所有目标设备发送通知。例如您的 iPhone、Mac 都可以收到 emails/messages.
  4. 的通知
  5. 然后您的 iPhone/Mac 会将该消息传送到应用程序。 APN 不会直接向您的应用程序发送消息。它将它发送到设备。然后 iOS 将其发送到您的应用程序。

有关此内容的更多信息,请参阅文档 APNs Overview and Sending Notification Requests to APNs


为了能够显示 badges/alerts/sounds,您需要向用户请求权限

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
    
    guard error == nil else {
        //Display Error.. Handle Error.. etc..
        return
    }
    
    if granted {
        //Do stuff here..
        
        //Register for RemoteNotifications. Your Remote Notifications can display alerts now :)
        application.registerForRemoteNotifications()
    }
    else {
        //Handle user denying permissions..
    }
}

问题:我是否需要为本地通知请求访问一次,为远程通知请求访问一次?

没有。只需编写上面的代码片段,它就会请求访问 远程和本地。

现在让我们进入棘手的部分 :D


Xcode 项目 +iPhone 设置

我需要启用某些功能来接收静默通知吗?

  1. 您必须从您的 Xcode 功能中启用 推送通知

如果您不启用此功能,您的应用将不会收到令牌。如果没有令牌,服务器将无法识别您。

  1. 为了能够从后台下载内容,您需要启用:远程通知后台模式。

要启用 backgroundModes,您可以 使用 plistXcode能力.

无论哪种方式,你都可以这样做的原因是因为 plist 更接近你的代码并且是旧的方式,也许它是为了遗留支持。 Xcode capabilities 是更新、简单的方法。

plist:

Item 0 只是一个 index,它不是字典的键(你通常在 plist 中看到的东西),UIBackgroundModes 是一个 array 的字符串。字符串只能来自 UIBackgroundModes Array.

接受值

Xcode 能力:

在背景模式下检查Xcode中的Remote Notification如下:

如果您不执行上述任何操作,则通过以下方式关闭通知:

将终止 远程和本地通知


但是,如果您 从 plist 或 Xcode 功能启用后台应用程序刷新,那么即使关闭通知对于应用程序,您仍然会收到静默通知!

如果用户想要禁用静默通知,他将不得不禁用这两个通知并禁用您的应用程序/整个系统的“后台应用程序刷新”。 要在整个系统中禁用 'background app refresh',您必须这样做:

我为什么要说这些?向您解释一下静默通知和推送通知的设置对用户来说是不同的,发送它们的限制也不同。 更多见this moment from the WWDC video. See here instead(之前的link已死):

Silent notifications are enabled by default.

The user does not need to approve your does not give permission to your app to use them, and you can just start using them without asking the user for permission.

But silent notifications are the mechanism behind background app refresh.

At any point you know that the user can go in settings and disable them.

So you can't depend on them always being available.

You don't know if the user the turn them off, and you are not getting a notification anymore.

This also means that silent notifications are delivered with the best effort.

That means that when the notification arrives on the user's device, the system is going to make some choices.

It's going to use different signals from the device and from the user behavior, like power or the time of day to decide when it is a good time to deliver the notification and launch your app.

It may try to save battery or it may try to match the user behavior and make the content available when the user is more likely to use it.

另见 here

注意事项: 即使您禁用应用程序后台刷新并禁用允许通知,如果您的应用程序处于前台,您仍然可以收到静默通知。如果您的应用程序在后台运行,则无法交付。


我需要启用某些功能来接收远程通知吗?

您只需要从您的 Xcode 功能中启用 推送通知

如果您不启用此功能,您的应用将不会收到令牌。如果没有令牌,服务器将无法识别您。


APNs 负载结构

好奇...你能告诉我我的负载应该是什么样子吗?

我强烈推荐你看看 Apple§ documentation. It's very clear AND ALSO SEE Sending Notification Requests to APNs。基本上平台对 APNs 进行 HTTP/2 调用并发送所需的有效负载。发送正确的 headers 很重要,否则您的通知将不会发送到设备!

谢谢,但是你能告诉我重要的部分吗?

嗯...好吧,但你知道这是来自 link 我刚才说:

对于静默通知,只有一个标准:

  • 有效负载的 aps 字典必须包含 content-available 键 值为 1.
  • 根据 docs 您可以发送其他字段

If there are user-visible updates that go along with the background update, you can set the alert, sound, or badge keys in the aps dictionary, as appropriate.

示例负载如下所示:

{
    "aps" : {
        "content-available" : 1
    },
    "acme1" : "bar",
    "acme2" : 42
}

acme1、acme2 或只是一些自定义数据!但是对于aps键,你必须遵循Apple的结构,否则,它不会映射正确,你将无法正确读取数据。

注意:我还没有验证这一点,但另一位工程师提到,如果您启用了 临时通知,那么为了确保发送静默通知,您必须包含一个带有空 body。例如:

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

对于用户通知

您的 aps 中需要一个 alert 密钥。

举个例子:

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

还有第三个选项,我将在答案中进一步讨论。

至于固定的 apsalert 字典键是什么,请参阅这些 Apple docs

好的,知道了。什么是 content-available?

很简单。它只是一个标志,告诉您的应用程序您需要唤醒并下载一些东西,因为我有可供下载的内容!有关详细信息,请参阅此 exact moment

默认情况下不包含 content-available 标志,即默认情况下您发送的通知 不会 触发 application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 或执行你的应用程序中的东西。它只会显示通知。如果你想唤醒应用程序(在后台做一些事情),你需要包含 content-available 并将其设置为 1.

§: If you're using Firebase, your payload structure and keys may be slightly different. For example, the key content-available is replaced by content_available. For more, see Firebase documentation and also here.


我知道你告诉我只有在使用静默通知时我才能将某些内容下载到我的应用程序中,但是有没有一种方法可以让我在后台唤醒我的应用程序并下载远程通知的东西?

是的,但是类似于静默通知,您还必须将 content-available 标志设置为 1,这样它就会知道唤醒并下载一些东西。否则,它只会弹出 alert/badge/sound 但不会下载任何内容。

重要说明:

  • 如果您的应用只有静默通知,只需从功能中启用“推送通知”+“远程通知”,并将每个负载的 content-available 设置为 1
  • 如果您的应用只有远程通知,只需从功能中启用“推送通知”。 content-available.
  • 无事可做
  • 但是,如果您希望通知显示 alert/badge/sound 并在后台下载内容,则必须同时启用“远程通知”和“推送通知”+ 将 content-available 设置为1.

(第三个选项)

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

This moment 来自 WWDC 视频提到

引用 Apple 工程师的话:

Now, you can in a user remote notification, you can set the same content available flag that you set in silent notifications, and that allows your app to have some time to download the content or update the content that it wants to be displayed so that when the user taps on the notification, your content is available. And the user sees what it does. This is a way to have a silent notification inside a user notifications like a summary.


通知和iOS应用程序life-cycle

我对远程通知感到困惑。我以为每当我收到通知时,我的应用程序就会在后台激活并下载一些东西。能解释一下吗?

例如此时此刻:

  • 您的 iPhone 刚刚收到一个 body 为“无发件人”的远程通知。要接收此消息,WhatsApp ** 不必 ** 在后台 运行,即,您不需要从 BackgroundModes 启用“远程通知”。即使您的应用程序 force-quit 或暂停,您仍然会收到通知,因为 进程由 OS 而不是 WhatsApp 应用程序 管理。但是,如果您希望能够将实际消息或其 image/video 下载到 WhatsApp(这样一旦您的用户打开 WhatsApp,视频就会坐在那里等待用户),那么您需要您的应用程序变得活跃。为此,您需要 content-available : 1 并实施 application(_:didReceiveRemoteNotification:fetchCompletionHandler:) .

  • 同样,如果您禁用某个应用的蜂窝数据,您仍然会收到它的通知。但是,通过点击该通知,用户 将无法 为该应用发出任何 网络请求 。他们将只能打开 应用程序。

  • 或者对于另一种类似的情况,如果您连接到的 server/access 点对 WhatsApp 等的访问受到限制,它仍然允许您接收 APNs 通知。但是,通过点击该通知,用户 将无法 为该应用发出任何 网络请求 。他们将只能打开 应用程序。

注意事项: 如果该应用是由用户 force-quit 开发的,那么当您因 above-mentioned 原因收到通知时,您不能采取任何措施使应用程序自动退出终止状态(即使您将 content-available 设置为 1)。 None 的委托方法将被命中。 用户 必须打开应用程序,然后才能访问您的委托方法。


关于可靠性和 APNs 架构的注释:

尽管通知被大量用于向应用程序传送实际内容,但它们在某种程度上并非设计用于向应用程序传送 内容。相反,它们旨在 通知 用户“嘿,有新东西到了(2b 的消息或 50kb 的小图像,或 10MB 的图像或 2GB 的视频)。打开应用程序如果你喜欢的话。顺便说一句,这是它的一小部分(实际消息本身 if 它可以容纳,图像的标题或通知中显示的缩略图,标题视频或视频中显示的缩略图”。有关更多信息,请参见 iOS APNs “best-effort” fallback。重复一遍,您永远不会下载电子邮件中发送的 40MB 附件。您只是收到它存在的通知。您发送的(缩略图)就足够了查看附件)以便用户了解新内容,并可以决定他们是否需要打开应用程序以获取更多信息。当我刚接触 iOS 时,我以为你实际上发送了 image/video 通过推送通知。你没有!

特别是在静默通知的情况下:

When a device receives a background notification, the system may hold and delay the delivery of the notification, which can have the following side effects:

  • When the system receives a new background notification, it discards the older notification and only holds the newest one.

  • If something force quits or kills the app, the system discards the held notification.

  • If the user launches the app, the system immediately delivers the held notification. Pushing Background Updates to Your App docs

  • APNs sends a limited number of silent notifications—notifications with the content-available key—per day. In addition, if the device has already exceeded its power budget for the day, silent notifications are not sent again until the power budget resets, which happens once a day. These limits are disabled when testing your app from Xcode. See Pushing Background Updates to Your App.

Troubleshooting tips for handling errors returned from ANPs

即使是远程用户通知,用户也可能会断开互联网,这可能会导致内容过期,或者如果您发送通知太多或太快,APN 可能会限制您。又见这里

长街简而言之,APN 和 OS 是王者,而你在它之下。因此,您不能依赖它来遵守您的每条命令。话虽如此,从您看到大多数消息传递应用程序成功利用它的意义上来说,它是超级可靠的。

附录如何生成推送通知证书,.p12.pem 以及如何对其进行全面测试?

看看这个terrific answer。它拥有我见过最多的屏幕截图。