iOS 15 Notifications

通知摘要

通知摘要是一项可选功能,允许用户停止接收特定应用程序的实时推送通知。相反,系统会存储为这些应用程序收到的通知,并在锁屏上的摘要中显示它们。系统可以在一天中的不同时刻显示这些摘要,具体取决于用户的偏好。

iOS 不会自动将应用程序添加到通知摘要中。首次启用该功能时,用户需要从系统设置中手动添加:

image

打开通知摘要后,推送权限提示将提供两个选项来处理应用程序的通知:

  • Allow Immediate Notifications”:收到通知后立即显示。

  • Add to Scheduled Summary”:收到通知后稍后显示在通知摘要中。

image

请注意,iOS 不提供检测用户选择的哪种通知处理方式(立即通知与预定摘要)。

新增 API

专注模式

iOS 15 的新专注模式是当前勿扰模式的改进和扩展。用户可以创建不同的“专注模式”来过滤他们在活动期间(如:工作、驾驶等)收到的通知。从系统设置中,用户可以创建“工作”焦点并将其设置在同事、家人和特定应用程序通知到达时立即通知。

image

专注模式激活时,其他联系人和应用程序的通知将仅显示在通知中心,如下所示:

image

相关 API

新的通知中断级别

除了新的通知摘要和专注模式之外,iOS 15 还为推送通知引入了两个新的中断级别:passivetime-sensitive

总共有四个不同的中断级别:

  • Passive 被动:对不需要立即关注的通知使用被动模式(如:营销活动等)。被动通知不会触发声音、振动和亮屏。

  • Active 活动:这是默认的中断级别(如:新闻等)。

  • Time-Sensitive 时间敏感:对需要立即关注的通知(如:帐户安全问题、快递送达等)使用时间敏感中断级别。该中断级别不要用于发送营销通知,因为这些通知可能会突破系统控制(通知摘要和专注模式)。

  • Critical 严重:严重中断级别用于需要立即关注的非常重要的通知(如:恶劣天气等)。这种使用必须由 Apple 明确允许并具有特殊权利。

image

请注意,时间敏感严重中断级别都可以突破通知摘要任何专注模式。iOS 将显示刚刚收到的通知:

image

如果 App 的时间敏感通知不经常交互,iOS 会从锁定屏幕提示用户,让用户为 App 禁用时间敏感的通知。用户也可以从系统设置中禁用:

image

发送时间敏感的通知

先决条件

为了使用时间敏感通知,App 需要将“时间敏感通知”功能添加到 Xcode 项目中。

image

设置推送通知数据

时间敏感的中断级别可以使用“interruption-level” payload key:

{"aps":{"interruption-level":"time-sensitive"}}

新增 API

通知操作图标

通知操作现在可以包含图标以更好的表达相关操作。这些图标可以是 SFSymbol 系统图像,也可以是 App 提供的自定义图像。为了添加图标,Apple 提供了新的 API UNNotificationActionIcon 对象。Action Icon 对象可以使用系统或模板图像名称进行初始化,然后使用包含 icon 参数的新初始化方法添加到相应的 UNNotificationAction 中。您不需要在名称中指定文件扩展名或大小修饰符,因为会根据系统和可用图像资源自动检索正确的大小。

image
image

通讯通知

Apple 添加了将应用程序的通知区分为通信通知的功能。这些通知现在将包含发送它们的联系人的图像或头像,并且可以与 SiriKit 集成,以便 Siri 可以根据常用联系人智能地为通信操作提供快捷方式和建议。例如,当用户为焦点模式设置允许的联系人或从您的应用拨打电话时。 Siri 将根据您的应用程序提供的意图数据智能地推荐联系人。

要使用通信通知,应用程序需要在 Xcode 中向其应用程序添加 Communication Notifications 功能,并使用实现了 UNNotificationContentProviding 协议的 Intent 对象更新 App Notification Service Extension 的通知内容。目前两个可用的实现是 INSendMessageIntentINStartCallIntent

image

APNs 实现通讯通知

项目中添加 Notification Service Extension,将以下 key value 添加到 Notification Service Extension 的 Info.plist 中。

image

NotificationService.didReceive 中编写代码向通知对象添加附加信息。(每次 Apple APNs 在通知用户前,都会调用此方法)

import UserNotifications
import Intents
import UIKit
class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        if let bestAttemptContent = bestAttemptContent {
            // ...
        }
    }
}

需要使用 INPerson 装载发送者信息,这些信息可以通过 APNs 通知传给 App。如:

{
    "aps": {
        "alert": {
            "body": "Hello world! This is a test message.",
            "title": "@Neko"
        },
    },
    "sender_id": "1",
    "sender_name": "NekoNeko",
    "sender_image_url": "https://xxxx.com/xxx.jpg",
    "sender_nickname": "@Neko",
    "sender_email": "Neko@Neko.Neko",
    "chat_session_id": "chat_1"
} 

然后,可以通过使用 INPersonINSendMessageIntent 将发送者信息添加到推送通知中。

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        if let bestAttemptContent = bestAttemptContent {
            // Modify the notification content here...
            bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"

            /* Use the custom information included in this notification from the chat server to retrive the chat participant's information. - This is the information of the sender of the message. - Providing a user's accruate name helps the iOS system match this user with a contact in the system contact app. */
            if let senderAccountID = bestAttemptContent.userInfo["sender_id"] as? String,
               let senderName = bestAttemptContent.userInfo["sender_name"] as? String,
               let senderImageURLString = bestAttemptContent.userInfo["sender_image_url"] as? String,
               let senderImageURL = URL(string: senderImageURLString),
               let senderDisplayName = bestAttemptContent.userInfo["sender_nickname"] as? String,
               let senderEmailAddr = bestAttemptContent.userInfo["sender_email"] as? String,
               let chatSessionID = bestAttemptContent.userInfo["chat_session_id"] as? String
            {

                // You can also use the sender's phone number to initialize the `INPersonHandle` object. This will help the iOS system to match this sender with a contact.
                // TODO: - Here you need to download the image data from the URL. In this demo, we are using a system image instead.
                let messageSender = INPerson(
                    // email or phone number
                    personHandle: INPersonHandle(value: senderEmailAddr, type: .emailAddress),
                    nameComponents: try? PersonNameComponents(senderName),
                    displayName: senderDisplayName,
                    image: INImage(imageData: UIImage(systemName: "applelogo")!.pngData()!),
                    contactIdentifier: nil,
                    customIdentifier: senderAccountID,
                    isMe: false,
                    suggestionType: .instantMessageAddress
                )

                let intent = INSendMessageIntent(recipients: nil,
                                                 outgoingMessageType: .outgoingMessageText,
                                                 content: bestAttemptContent.body,
                                                 speakableGroupName: INSpeakableString(spokenPhrase: senderDisplayName),
                                                 conversationIdentifier: chatSessionID,
                                                 serviceName: nil,
                                                 sender: messageSender,
                                                 attachments: nil)

                let interaction = INInteraction(intent: intent, response: nil)
                interaction.direction = .incoming
                interaction.donate(completion: nil)
                do {
                    let messageContent = try request.content.updating(from: intent)
                    contentHandler(messageContent)
                } catch {
                    print(error.localizedDescription)
                }

            }

            contentHandler(bestAttemptContent)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }

}

相关资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容