76、iOS 本地通知的使用与管理

iOS 本地通知的使用与管理

1. 通知设置

用户可以针对应用的通知进行多种设置,以下是一些常见的设置项及其取值:
| 设置项 | 取值 |
| — | — |
| soundSetting | .enabled / .disabled / .notSupported |
| badgeSetting | .enabled / .disabled / .notSupported |
| alertSetting | .enabled / .disabled / .notSupported |
| notificationCenterSetting | .enabled / .disabled / .notSupported |
| lockScreenSetting | .enabled / .disabled / .notSupported |
| alertStyle | .banner / .alert / .none |
| showPreviewsSetting | .always / .whenAuthenticated / .never |
| providesAppNotificationSettings | 取决于应用请求授权时是否包含 .provideAppNotificationSettings |

2. 通知类别

通知类别是一个较为模糊的概念,它包含了与单个通知相关的各种可能设置。你可以向用户通知中心注册所需的类别,每个类别都有一个任意的字符串标识符。后续创建通知时,可通过该字符串标识符将通知与之前注册的类别关联起来。

2.1 类别初始化

UNNotificationCategory 现在有三个初始化方法,参数越来越多,最全的形式如下:

init(identifier:actions:intentIdentifiers:hiddenPreviewsBodyPlaceholder:categorySummaryFormat:options:)
  • identifier :后续通知将通过此标识符与该类别匹配。
  • intentIdentifiers :与 SiriKit 相关,这里暂不讨论。

2.2 注册类别

要使类别生效,可调用 setNotificationCategories 方法将其注册到用户通知中心,示例代码如下:

let cat1 = UNNotificationCategory(identifier: /* ... */)
let cat2 = UNNotificationCategory(identifier: /* ... */)
let cat3 = UNNotificationCategory(identifier: /* ... */)
let center = UNUserNotificationCenter.current()
center.setNotificationCategories([cat1, cat2, cat3])

2.3 管理类别

虽然没有直接添加或删除单个类别的管理命令,但类别以集合形式维护。这意味着多次注册相同的类别不会有问题,并且可以获取现有类别,添加新类别后再次设置,示例代码如下:

let center = UNUserNotificationCenter.current()
center.getNotificationCategories { cats in
    var cats = cats
    let newcat = UNNotificationCategory(identifier: /* ... */)
    cats.insert(newcat)
    center.setNotificationCategories(cats)
}

2.4 使用通知类别的目的

  • 希望通知的二级界面显示自定义操作。
  • 希望在用户关闭通知时收到应用的通知。
  • 希望在用户抑制预览时自定义通知文本。
  • 希望在通知分组时自定义通知摘要文本。

2.5 自定义操作

自定义操作本质上是出现在通知二级界面的按钮。在 iOS 12 之前,只能通过通知类别实现;iOS 12 之后,也可以在通知上下文扩展中创建自定义操作。

2.5.1 自定义操作初始化

UNNotificationAction 的初始化方法如下:

init(identifier:title:options:)
  • identifier :任意字符串,用于区分用户点击的按钮。
  • title :按钮上显示的文本。
  • options UNNotificationActionOptions 位掩码,常见选项及含义如下:
  • .foreground :点击此按钮会将应用调至前台,否则应用将在后台响应,响应后会被挂起。
  • .destructive :此按钮在界面上会标记为危险(显示为红色)。
  • .authenticationRequired :若不是 .foreground 按钮,且用户设备需要身份验证(如密码)才能解锁屏幕,在锁屏界面点击此按钮也需要进行身份验证,以防止用户在未解锁屏幕的情况下执行该操作。
2.5.2 文本输入操作

除了普通按钮,还可以创建文本输入操作,使用 UNTextInputNotificationAction 类,其初始化方法如下:

init(identifier:title:options:textInputButtonTitle:textInputPlaceholder:)

创建操作后,将操作数组作为 actions 参数初始化 UNNotificationCategory

2.6 关闭操作

用户可以在不与通知进行其他交互的情况下关闭本地通知,默认情况下应用不会收到任何事件。若要在这种情况下收到事件通知,可在 UNNotificationCategory 初始化时,在 options 参数中包含 .customDismissAction

2.7 预览设置

通知可能会意外弹出,包括在锁屏界面。为保护隐私,用户可能希望在通知最初出现时抑制其文本显示,仅在通知的二级界面可见。用户可以在设置应用中进行此操作。本地通知最初出现时的文本称为通知预览,有三种预览显示设置:始终显示、仅在手机解锁时显示、从不显示。

默认情况下,若预览关闭,通知的标题和副标题会被隐藏,正文文本会被替换为占位符“Notification”。你可以在 UNNotificationCategory 初始化时,通过 hiddenPreviewsBodyPlaceholder 参数设置自定义占位符。若通知的标题和副标题不包含敏感信息,可在初始化 UNNotificationCategory 时,在 options 参数中包含 .hiddenPreviewsShowTitle .hiddenPreviewsShowSubtitle ,使它们在预览关闭时仍显示。

3. 安排本地通知

3.1 创建通知请求

要安排通知,需创建 UNNotificationRequest 对象,调用其指定的初始化方法:

init(identifier:content:trigger:)
  • identifier :任意字符串,用于区分不同的通知,还可避免通知混乱。若安排的通知标识符与已安排的通知相同,之前的通知将被删除;若通知触发时,通知中心已有相同标识符的通知,之前的通知也会被删除。
  • content :通知的核心内容,即通知要显示的内容和携带的信息,也称为通知的有效负载。它是 UNNotificationContent 对象,但该类是不可变的,需先实例化其可变子类 UNMutableNotificationContent ,然后为其属性赋值,常见属性如下:
  • title subtitle body :通知提醒中可见的文本。
  • attachments UNNotificationAttachment 对象数组,附件通过调用其指定的初始化方法创建:
init(identifier:url:options:)
- `identifier`:任意字符串。
- `url`:附件本身,必须是指向磁盘上图像文件、音频文件或视频文件的文件 URL,文件需较小,因为系统会在通知触发后将其复制到私有安全区域。
  • sound :通知触发时播放的声音,可通过名称指定应用包中的声音文件( UNNotificationSoundName ),或调用 default 指定默认声音,示例如下:
content.sound = UNNotificationSound(named: UNNotificationSoundName("test.aif"))
  • badge :通知触发后应用图标上显示的数字,指定为 0 可移除现有徽章。
  • categoryIdentifier :之前注册类别的标识符字符串,用于将本地通知与该类别设置关联。
  • userInfo :任意字典,用于携带后续要检索的额外信息。
  • threadIdentifier :字符串,具有相同线程标识符的通知提醒会在锁屏界面和通知中心进行物理分组。
  • launchImageName :若用户点击通知提醒启动应用,可指定应用启动时显示的替代启动图像。
  • trigger :告诉系统何时触发通知,是 UNNotificationTrigger 的子类,常见子类及初始化方法如下:
  • UNTimeIntervalNotificationTrigger :从现在起经过一定秒数后触发,可能会重复触发,初始化方法如下:
init(timeInterval:repeats:)
  • UNCalendarNotificationTrigger :在特定日期时间触发,使用 DateComponents 表示,可能会在相同 DateComponents 再次出现时重复触发,初始化方法如下:
init(dateMatching:repeats:)
  • UNLocationNotificationTrigger :当用户进入或离开特定地理区域时触发。

3.2 添加通知请求

创建 UNNotificationRequest 对象后,调用用户通知中心的 add(_:) 方法将通知添加到其内部的已安排通知列表中,示例代码如下:

let interval = // ... whatever ...
let trigger = UNTimeIntervalNotificationTrigger(
    timeInterval: interval, repeats: false)
let content = UNMutableNotificationContent()
content.title = "Caffeine!"
content.body = "Time for another cup of coffee!"
content.sound = UNNotificationSound.default
content.categoryIdentifier = self.categoryIdentifier
let url = Bundle.main.url(forResource: "cup2", withExtension: "jpg")!
if let att = try? UNNotificationAttachment(
    identifier: "cup", url: url, options:nil) {
        content.attachments = [att]
}
let req = UNNotificationRequest(
    identifier: "coffeeNotification", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(req)

4. 监听本地通知

要在安排的本地通知触发后收到通知,需将某个对象配置为用户通知中心的代理,采用 UNUserNotificationCenterDelegate 协议。建议在应用生命周期的早期进行此配置,例如在 application(_:didFinishLaunchingWithOptions:) 方法中,示例代码如下:

func application(_ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions:
    [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
        let center = UNUserNotificationCenter.current()
        center.delegate = self // or whatever
        return true
}

UNUserNotificationCenterDelegate 协议包含三个可选方法,这些方法都会提供一个 UNNotification 对象,其中包含通知的触发日期和原始请求( UNNotificationRequest ),因此可以识别本地通知并从中提取信息,如附件或 userInfo 字典。

4.1 userNotificationCenter(_:willPresent:withCompletionHandler:)

仅当应用处于前台且本地通知触发时调用此方法。默认情况下,此时通知的整个用户界面会被抑制,不播放声音、不显示横幅、不将通知添加到通知中心或锁屏界面。该方法可让你知道通知已触发,但用户无法得知。你可以选择让系统执行应用不在前台时的默认操作,通过传入的完成函数,使用 UNNotificationPresentationOptions 值( .alert .sound .badge )的组合或空选项集来指定操作,示例如下:

func userNotificationCenter(_ center: UNUserNotificationCenter,
    willPresent notification: UNNotification,
    withCompletionHandler completionHandler:
    @escaping (UNNotificationPresentationOptions) -> ()) {
        completionHandler([.sound, .alert])
}

4.2 userNotificationCenter(_:didReceive:withCompletionHandler:)

当用户与本地通知提醒进行交互时调用此方法,第二个参数是 UNNotificationResponse 对象,包含两个属性: notification UNNotification 对象)和 actionIdentifier (字符串,用于告知用户的操作)。 actionIdentifier 有三种可能取值:
- UNNotificationDefaultActionIdentifier :用户执行了默认操作,点击提醒或“打开”按钮启动应用。
- UNNotificationDismissActionIdentifier :用户关闭了本地通知提醒,仅当为该通知的类别指定了 .customDismissAction 选项时,才会收到此事件并调用该方法。
- 自定义操作标识符字符串:用户点击了自定义操作按钮,此为按钮的标识符。

若自定义操作是文本输入操作, UNNotificationResponse 会是 UNTextInputNotificationResponse 的子类,该子类有一个额外的 userText 属性,可通过 is as? 测试响应的类,然后检索 userText ,示例如下:

if let textresponse = response as? UNTextInputNotificationResponse {
    let text = textresponse.userText
    // ...
}

处理完成后,必须调用传入的完成函数,由于可能是在后台短暂唤醒应用,代码在主线程上运行,因此处理要迅速,示例如下:

func userNotificationCenter(_ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> ()) {
        let id = response.actionIdentifier
        if id == "snooze" {
            var id = UIBackgroundTaskIdentifier.invalid
            id = UIApplication.shared.beginBackgroundTask {
                UIApplication.shared.endBackgroundTask(id)
            }
            delay(0.1) {
                self.createNotification()
                UIApplication.shared.endBackgroundTask(id)
            }
        }
        completionHandler()
}

4.3 userNotificationCenter(_:openSettingsFor:)

(iOS 12 新增)若应用在请求授权时包含了 .provideAppNotificationSettings 选项,意味着应用承诺提供自己的内部界面让用户管理通知相关设置。运行时会在设置应用等合适的位置为应用提供一个特殊的应用通知设置按钮。当用户点击该按钮时,应立即显示该界面。例如,若应用有多个明显不同的通知类别,可允许用户选择为特定类别开启或关闭通知,这样可以减少用户界面的混乱,提高用户允许应用继续发送通知的可能性。

5. 分组通知

在 iOS 12 之前,可以通过设置通知请求有效负载( UNMutableNotificationContent )的 threadIdentifier 来对具有相同标识符的通知进行分组。iOS 12 之后,即使不设置 threadIdentifier ,应用的通知也会默认分组(用户可以关闭此功能)。若有多种通知类型,仍可使用不同的 threadIdentifier 值将应用的通知组进一步细分。

iOS 12 提供了改进的通知分组界面,分组不再只是通知列表中的有序部分,而是以单个折叠项的形式出现在列表中,用户可以展开分组。默认情况下,分组的摘要文本(如“2 more notifications”)会自动生成,你可以根据通知的具体内容自定义摘要文本。这可以通过 UNNotificationCategory 初始化时的 categorySummaryFormat 参数实现,该参数是一个格式字符串,至少包含一个 "%u" 格式说明符用于显示通知数量,例如 "%u more reminders"

创建通知的有效负载时,可以提供 summaryArgument 字符串,默认情况下,摘要文本会将其作为通知的发送者或来源,例如若三个通知的 summaryArgument 为 “Matt”,摘要文本会显示“2 more notifications from Matt”。若要自定义此显示, categorySummaryFormat 字符串需要包含一个 "%@" 格式说明符用于显示 summaryArgument ,例如 "%u more reminders from %@"

极少数情况下,应用可能会在有效负载中包含 summaryArgumentCount ,用于处理单个通知代表多个事项的特殊情况,此时摘要文本中的数量将是分组通知的 summaryArgumentCount 值之和,而不仅仅是分组通知的数量。

6. 管理通知

用户通知中心是可内省的,你可以检查已安排的通知列表, UNUserNotificationCenter 提供了以下方法来管理已安排的通知:

getPendingNotificationRequests(completionHandler:)

通过此方法可以获取待处理的通知请求列表,以便进行进一步的管理和操作。

综上所述,iOS 提供了丰富的本地通知功能,包括通知设置、类别管理、自定义操作、分组显示等,开发者可以根据应用的需求灵活运用这些功能,为用户提供更好的通知体验。同时,合理管理通知可以避免用户界面的混乱,提高用户对应用通知的接受度。

7. 通知使用总结与注意事项

7.1 通知设置总结

通知设置涵盖了声音、徽章、提醒样式、预览等多个方面,用户可以根据自身需求进行个性化配置。以下是对通知设置的总结表格:
| 设置项 | 取值 | 说明 |
| — | — | — |
| soundSetting | .enabled / .disabled / .notSupported | 控制通知声音的开启、关闭或不支持状态 |
| badgeSetting | .enabled / .disabled / .notSupported | 控制应用图标上徽章的显示状态 |
| alertSetting | .enabled / .disabled / .notSupported | 控制提醒的开启、关闭或不支持状态 |
| notificationCenterSetting | .enabled / .disabled / .notSupported | 控制通知中心的显示状态 |
| lockScreenSetting | .enabled / .disabled / .notSupported | 控制锁屏界面通知的显示状态 |
| alertStyle | .banner / .alert / .none | 控制提醒样式为横幅、弹窗或无 |
| showPreviewsSetting | .always / .whenAuthenticated / .never | 控制通知预览的显示时机 |
| providesAppNotificationSettings | 取决于应用请求授权时是否包含 .provideAppNotificationSettings | 决定是否提供应用内部的通知设置界面 |

7.2 通知类别注意事项

  • 标识符唯一性 :虽然运行时允许设置具有相同标识符但其他方面不同的通知类别,但这可能会导致问题,建议确保标识符的唯一性。
  • 多次注册 :类别以集合形式维护,多次注册相同的类别不会有问题,但为了代码的清晰性,建议避免不必要的重复注册。

7.3 自定义操作注意事项

  • 权限和性能 :使用 .foreground 选项时,要考虑应用在前台运行的性能和资源占用情况;使用 .authenticationRequired 选项时,要确保用户体验的流畅性,避免过度的身份验证要求。
  • 文本输入操作 :对于文本输入操作,要处理好用户输入的内容,确保应用能够正确响应和处理。

7.4 分组通知注意事项

  • 摘要文本自定义 :自定义摘要文本时,要确保格式字符串的正确性,包含必要的格式说明符( "%u" "%@" ),以正确显示通知数量和摘要参数。
  • summaryArgumentCount 使用 summaryArgumentCount 仅在特殊情况下使用,要确保其使用的合理性,避免造成摘要文本显示混乱。

7. 通知操作流程总结

7.1 安排本地通知流程

graph LR
    A[创建 UNNotificationRequest] --> B[创建 UNMutableNotificationContent]
    B --> C[设置 content 属性]
    C --> D[创建 UNNotificationTrigger]
    D --> E[初始化 UNNotificationRequest]
    E --> F[获取 UNUserNotificationCenter]
    F --> G[调用 add(_:) 方法添加通知]

具体步骤如下:
1. 创建 UNNotificationRequest 对象,需要先创建 UNMutableNotificationContent 对象并设置其属性,如标题、正文、声音、附件等。
2. 创建 UNNotificationTrigger 对象,根据需求选择不同的触发类型,如时间间隔触发、日历触发或位置触发。
3. 使用创建好的 UNMutableNotificationContent UNNotificationTrigger 初始化 UNNotificationRequest
4. 获取 UNUserNotificationCenter 实例。
5. 调用 add(_:) 方法将通知添加到用户通知中心的内部列表中。

7.2 监听本地通知流程

graph LR
    A[设置用户通知中心代理] --> B[实现 UNUserNotificationCenterDelegate 协议方法]
    B --> C{通知触发情况}
    C -->|应用前台| D[调用 userNotificationCenter(_:willPresent:withCompletionHandler:)]
    C -->|用户交互| E[调用 userNotificationCenter(_:didReceive:withCompletionHandler:)]
    C -->|点击设置按钮| F[调用 userNotificationCenter(_:openSettingsFor:)]

具体步骤如下:
1. 在应用启动时,将某个对象配置为用户通知中心的代理,采用 UNUserNotificationCenterDelegate 协议。
2. 实现 UNUserNotificationCenterDelegate 协议的三个可选方法:
- userNotificationCenter(_:willPresent:withCompletionHandler:) :当应用处于前台且通知触发时调用,可选择让系统执行默认操作。
- userNotificationCenter(_:didReceive:withCompletionHandler:) :当用户与通知进行交互时调用,根据 actionIdentifier 处理不同的操作。
- userNotificationCenter(_:openSettingsFor:) :当用户点击应用通知设置按钮时调用,应显示应用的通知管理界面。

7.3 管理通知流程

graph LR
    A[获取 UNUserNotificationCenter] --> B[调用 getPendingNotificationRequests(completionHandler:)]
    B --> C[处理待处理的通知请求列表]

具体步骤如下:
1. 获取 UNUserNotificationCenter 实例。
2. 调用 getPendingNotificationRequests(completionHandler:) 方法获取待处理的通知请求列表。
3. 根据需求对通知请求列表进行处理,如删除、修改或重新安排通知。

通过以上对 iOS 本地通知的详细介绍,开发者可以全面了解通知的各个方面,包括设置、类别、操作、分组和管理等。合理运用这些功能,能够为用户提供更加个性化、高效的通知体验,同时避免因通知管理不当而导致的用户界面混乱和用户体验下降。在实际开发中,要根据应用的具体需求和用户场景,灵活选择和配置通知功能,确保应用的通知系统既满足用户需求,又符合系统的性能和安全要求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值