系统推送的集成(二十一) —— 关于本地通知的详细解析(一)

2021-05-23  本文已影响0人  刀客传奇

版本记录

版本号 时间
V1.0 2021.05.23 星期日

前言

我们做APP很多时候都需要推送功能,以直播为例,如果你关注的主播开播了,那么就需要向关注这个主播的人发送开播通知,提醒用户去看播,这个只是一个小的方面,具体应用根据公司的业务逻辑而定。前面已经花了很多篇幅介绍了极光推送,其实极光推送无非就是将我们客户端和服务端做的很多东西封装了一下,节省了我们很多处理逻辑和流程,这一篇开始,我们就利用系统的原生推送类结合工程实践说一下系统推送的集成,希望我的讲解能让大家很清楚的理解它。感兴趣的可以看上面几篇。
1. 系统推送的集成(一) —— 基本集成流程(一)
2. 系统推送的集成(二) —— 推送遇到的几个坑之BadDeviceToken问题(一)
3. 系统推送的集成(三) —— 本地和远程通知编程指南之你的App的通知 - 本地和远程通知概览(一)
4. 系统推送的集成(四) —— 本地和远程通知编程指南之你的App的通知 - 管理您的应用程序的通知支持(二)
5. 系统推送的集成(五) —— 本地和远程通知编程指南之你的App的通知 - 调度和处理本地通知(三)
6. 系统推送的集成(六) —— 本地和远程通知编程指南之你的App的通知 - 配置远程通知支持(四)
7. 系统推送的集成(七) —— 本地和远程通知编程指南之你的App的通知 - 修改和显示通知(五)
8. 系统推送的集成(八) —— 本地和远程通知编程指南之苹果推送通知服务APNs - APNs概览(一)
9. 系统推送的集成(九) —— 本地和远程通知编程指南之苹果推送通知服务APNs - 创建远程通知Payload(二)
10. 系统推送的集成(十) —— 本地和远程通知编程指南之苹果推送通知服务APNs - 与APNs通信(三)
11. 系统推送的集成(十一) —— 本地和远程通知编程指南之苹果推送通知服务APNs - Payload Key参考(四)
12. 系统推送的集成(十二) —— 本地和远程通知编程指南之Legacy信息 - 二进制Provider API(一)
13. 系统推送的集成(十三) —— 本地和远程通知编程指南之Legacy信息 - Legacy通知格式(二)
14. 系统推送的集成(十四) —— 发送和处理推送通知流程详解(一)
15. 系统推送的集成(十五) —— 发送和处理推送通知流程详解(二)
16. 系统推送的集成(十六) —— 自定义远程通知(一)
17. 系统推送的集成(十七) —— APNs从工程配置到自定义通知UI全流程解析(一)
18. 系统推送的集成(十八) —— APNs从工程配置到自定义通知UI全流程解析(二)
19. 系统推送的集成(十九) —— APNs配置接收和处理的简单入门(一)
20. 系统推送的集成(二十) —— APNs配置接收和处理的简单入门(二)

开始

首先看下主要内容:

了解如何按时间间隔,一天中的时间和位置创建通知,以及如何支持类别分组和提示操作。内容来自翻译

接着看下写作环境:

Swift 5, iOS 14, Xcode 12

接着就是正文啦。

通知是在应用程序外部将信息传达给用户的一种必不可少的方式。 它们有助于吸引用户的注意力,并促进他们对应用程序的参与。 但是,大量的通知可能会使用户烦恼,从而导致他们将其关闭甚至删除该应用程序。 因此,您必须明智地使用通知。

有两种类型的通知:本地通知和远程通知。 本教程全部关于本地通知。 在本教程中,您将学习如何:

通常,用户会忘记任务并需要提醒。 您可以使用本地通知功能轻松提醒他们。

打开OrganizerPlus项目,构建并运行。

OrganizerPlus有助于跟踪您的任务。 点击+按钮开始创建任务。 接下来,为任务添加一个名称,然后点击Save。 您可以通过点击任务旁边的圆圈将任务标记为已完成。


Introducing Notifications

通知可以是本地或远程的。 设备上的应用可安排和配置本地通知。 相反,服务器使用Apple Push Notification Service(APNS)发送远程通知。 新闻alert是远程通知的示例,其中服务器将最新的突发新闻作为通知发送到设备。

远程通知可以是可见的也可以是静默的。 静默通知会在后台启动应用程序以执行操作,例如刷新应用程序。 您可以使用UserNotifications框架配置本地和远程通知。 要了解有关远程通知的更多信息,请查看 Push Notifications Tutorial: Getting Started

要创建和管理通知,您需要执行以下步骤:

您将在本教程中学习如何执行所有这些步骤。


Requesting Notification Permission

通知会打断用户,因此应用程序需要用户允许它们。 在OrganizerPlus中,当用户点击右上角的响铃按钮时,您将请求通知权限。

首先,打开NotificationManager.swift。 然后,将以下内容添加到NotificationManager

func requestAuthorization(completion: @escaping  (Bool) -> Void) {
  UNUserNotificationCenter.current()
    .requestAuthorization(options: [.alert, .sound, .badge]) { granted, _  in
      // TODO: Fetch notification settings
      completion(granted)
    }
}

代码是这样的:

现在,在NotificationManager中添加以下内容:

func fetchNotificationSettings() {
  // 1
  UNUserNotificationCenter.current().getNotificationSettings { settings in
    // 2
    DispatchQueue.main.async {
      self.settings = settings
    }
  }
}

这是您添加的内容:

现在,在requestAuthorization(completion :)中,将// TODO: Fetch notification settings替换成如下:

self.fetchNotificationSettings()

在这里,您在用户授予授权后获取通知设置。

1. Prompting Notification Authorization

打开TaskListView.swift。 然后,在按钮的操作结束中找到// TODO: Add Notification authorization,并将其替换为以下内容:

// 1
NotificationManager.shared.requestAuthorization { granted in
  // 2
  if granted {
    showNotificationSettingsUI = true
  }
}

这是一个细分:

构建并运行。

点击右上角的响铃图标。这将提示通知授权。接下来,选择Allow。您会看到该应用授予的通知设置列表。

顺利完成通知管理的第一步!

2. Understanding Critical Notifications

在通知设置中,请注意,该应用没有获得严重alert的授权。但是什么是紧急alert

紧急alert是健康,医疗,安全或公共安全通知。他们绕过请勿打扰和振铃开关并播放声音。这些都是极具破坏性的,因此并非所有应用程序都可以发送严重警报。

如果您的应用程序需要发送它们,则可以在Apple developer portal上申请权利。

OrganizerPlus的提醒很重要,但并不紧急,因此您无需为此教程启用紧急alert

现在,该创建和安排通知了。


Creating Notifications

您可以使用以下任何触发器来创建和调度本地通知:

这些选项确定您的应用何时传递通知。下一步,您将学习如何使用这些触发器中的每个触发器来创建通知。


Triggering TimeInterval Notifications

打开NotificationManager.swift并将以下内容添加到NotificationManager

// 1
func scheduleNotification(task: Task) {
  // 2
  let content = UNMutableNotificationContent()
  content.title = task.name
  content.body = "Gentle reminder for your task!"

  // 3
  var trigger: UNNotificationTrigger?
  switch task.reminder.reminderType {
  case .time:
    if let timeInterval = task.reminder.timeInterval {
      trigger = UNTimeIntervalNotificationTrigger(
        timeInterval: timeInterval,
        repeats: task.reminder.repeats)
    }
  default:
    return
  }

  // 4
  if let trigger = trigger {
    let request = UNNotificationRequest(
      identifier: task.id,
      content: content,
      trigger: trigger)
    // 5
    UNUserNotificationCenter.current().add(request) { error in
      if let error = error {
        print(error)
      }
    }
  }
}

这是您添加的内容:

1. Scheduling the Notification

打开TaskManager.swift。在DispatchQueue.global().async块之后和方法结束之前,将以下内容添加到save(task :)

if task.reminderEnabled {
  NotificationManager.shared.scheduleNotification(task: task)
}

如果任务的reminderEnabled设置为true,则在此处调度通知。

构建并运行。

请按照以下步骤添加任务并测试您的通知:

最后,后台运行该应用程序并等待一分钟。 您会看到通知出现。

恭喜您收到第一个通知!

要查看此通知,您必须使应用程序后台运行并等待。 在应用仍处于前台状态时查看通知会不会很酷? 接下来,您将要执行此操作。


Viewing Notification When the App Is in the Foreground

打开AppDelegate.swift并将以下内容添加到文件末尾:

// MARK: - UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
  func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    willPresent notification: UNNotification,
    withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void
  ) {
    completionHandler(.banner)
  }
}

userNotificationCenter(_:willPresent:withCompletionHandler :)询问代理在应用程序处于前台时如何处理通知。 在这里,您可以将演示文稿选项设置为banner来调用completion handler。 您还可以添加其他选项,例如soundbadge

接下来,将以下内容添加到AppDelegate

private func configureUserNotifications() {
  UNUserNotificationCenter.current().delegate = self
}

在这里,您声明configureUserNotifications(),这使AppDelegate成为UNUserNotificationCenter的委托。

现在,在返回true之前,将以下内容添加到application(_:didFinishLaunchingWithOptions :)

configureUserNotifications()

在这里,您可以在应用启动后立即调用configureUserNotifications()来设置通知委托。

构建并运行。

要进行尝试,请添加时间间隔设置为一分钟的任务,然后将应用程序置于前台。 当应用程序处于前台时,您会看到一条通知。 做得好!

将任务标记为完成会删除它,但是通知呢? 您不想看到不存在的任务的提醒。 接下来,您将进行处理。


Removing Scheduled Notifications

打开NotificationManager.swift并将以下内容添加到NotificationManager

func removeScheduledNotification(task: Task) {
  UNUserNotificationCenter.current()
    .removePendingNotificationRequests(withIdentifiers: [task.id])
}

您需要确保在任务完成时删除所有待处理的通知。 通过使用removePendingNotificationRequests(withIdentifers :)来执行此操作。 在这里,您将任务的标识符传递到数组中。 这对于将repeats设置为true的任务特别有用。

接下来,打开TaskManager.swift并在返回之前添加以下内容到remove(task:)

if task.reminderEnabled {
  NotificationManager.shared.removeScheduledNotification(task: task)
}

任务完成后,这将删除所有计划的通知。

构建并运行。

通过创建时间间隔为一分钟的任务来尝试一下。 这次,切换Repeat Notification开关以将其启用。 您会注意到该通知每分钟出现一次。 接下来,通过点击任务旁边的圆圈按钮,将创建的任务标记为完成。 这将删除任务,并且您将不再看到该任务的计划通知。

您可以在UNUserNotificationCenter上使用removeAllPendingNotificationRequests()取消计划所有待处理的通知。 removeAllDeliveredNotifications()将删除所有已传递的通知。

时间间隔只是触发通知的一种方式。 还有其他本地触发通知的方法:日历和位置。 接下来,您将实现这些。


Triggering Calendar Notifications

打开NotificationManager.swift。 然后,将以下内容添加到scheduleNotification(task :)中,作为switch task.reminder.reminderType中的附加情况:

case .calendar:
  if let date = task.reminder.date {
    trigger = UNCalendarNotificationTrigger(
      dateMatching: Calendar.current.dateComponents(
        [.day, .month, .year, .hour, .minute],
        from: date),
      repeats: task.reminder.repeats)
  }

使用添加的代码,您:

构建并运行。

请按照以下步骤创建任务:

您会看到通知出现。恭喜,您的第一个日历通知!

日历通知可让您安排定期提醒日常活动,例如每天早晨喝水。

现在,是时候提醒您通过GameStop商店时购买GME股票的提醒。输入基于位置的提醒!


Triggering Location Notifications

当用户进入或退出区域时,基于位置的触发器会导致应用传递通知。在后台,iOS使用地理围栏进行区域监视。这样,系统限制了用户可以同时调度的基于位置的触发器的数量。

添加基于位置的通知的第一步是请求位置权限。由于系统监视区域,因此该应用需要When-In-Use授权。LocationManager.swift中已经为您提供了位置授权和委托代码。

打开CreateTaskView.swift。然后,找到并替换//TODO: Request location authorization

locationManager.requestAuthorization()

在这里,当用户点击Request Location Authorization按钮时,您请求位置授权 —— 用户尚未获得授权。

1. Creating a Location Trigger

打开NotificationManager.swift。 接下来,通过替换switch task.reminder.reminderType中的default case,将以下内容添加到scheduleNotification(task :)中:

case .location:
  // 1
  guard CLLocationManager().authorizationStatus == .authorizedWhenInUse else {
    return
  }
  // 2
  if let location = task.reminder.location {
    // 3
    let center = CLLocationCoordinate2D(
      latitude: location.latitude,
      longitude: location.longitude)
    let region = CLCircularRegion(
      center: center,
      radius: location.radius,
      identifier: task.id)
    trigger = UNLocationNotificationTrigger(
      region: region,
      repeats: task.reminder.repeats)
  }

以下是分步细分:

构建并运行。

点击+按钮开始添加任务。接下来,点击细分栏中的Location。然后,如果您尚未授予位置授权,请点击Request Location Authorization。现在,在位置权限提示中选择Allow While Using App。您会看到Latitude, Longitude and Radius文本字段。

输入您打算不久后访问的地方的纬度或经度,或输入房屋的坐标。输入500作为半径。该值以米为单位。然后,点击Save以创建任务。

现在,当您输入或退出指定的位置时,您会收到一条通知。要对此进行模拟,请转到模拟器的Features菜单,选择Location ▸ Custom Location…,然后在提示符下输入相同的纬度和经度值。您会看到该通知从您的应用程序在后台显示。要走的路!

到目前为止,您已经根据不同的触发条件创建了通知。但是基于触发器将这些通知分组很酷,对吧?接下来,您将要执行此操作。


Grouping Notifications

默认情况下,您根据应用程序的bundle identifier将所有应用程序的通知分组。但是,您可以为您的应用程序创建自定义组。一个很好的例子是一个消息传递应用程序,该应用程序将不同消息组的通知进行分组。

对于OrganizerPlus,您将根据触发器类型对通知进行分组。

打开NotificationManager.swift并在NotificationManager之前添加以下内容:

enum NotificationManagerConstants {
  static let timeBasedNotificationThreadId =
    "TimeBasedNotificationThreadId"
  static let calendarBasedNotificationThreadId =
    "CalendarBasedNotificationThreadId"
  static let locationBasedNotificationThreadId =
    "LocationBasedNotificationThreadId"
}

在这里,您可以定义用于根据通知触发器类型对通知进行分组的常量。

scheduleNotification(task :)中找到switch task.reminder.reminderType。 通过为通知内容设置threadIdentifier为每种case添加标识符,如下所示:

switch task.reminder.reminderType {
case .time:
  content.threadIdentifier =
    NotificationManagerConstants.timeBasedNotificationThreadId
  // ...
case .calendar:
  content.threadIdentifier =
    NotificationManagerConstants.calendarBasedNotificationThreadId
  // ...
case .location:
  content.threadIdentifier =
    NotificationManagerConstants.locationBasedNotificationThreadId
  // ...
}

threadIdentifier帮助对相关通知进行分组。 在这里,您可以根据reminderType设置通知内容的标识符。

构建并运行。

用不同的触发器创建一些任务。出现通知时,您会看到它们根据触发器的类型进行了分组。

您可以选择关闭应用程序的通知分组。为此:

这将关闭分组。通知将按照收到的顺序显示。

轻按通知即可打开应用程序。有没有办法在不打开应用程序的情况下对通知采取行动?接下来,您将进行探讨。


Handling Notification Actions

可操作的通知允许用户在不打开应用程序的情况下对通知执行操作。可操作的通知除了内容之外,还可以显示一个或多个按钮。

为了支持可行的通知,您需要:

接下来,您将实现所有这些功能。

1. Declaring Category and Creating Actions

打开AppDelegate.swift。然后,将以下内容添加到UNUserNotificationCenter.current().delegate = self下的configureUserNotifications()

// 1
let dismissAction = UNNotificationAction(
  identifier: "dismiss",
  title: "Dismiss",
  options: [])
let markAsDone = UNNotificationAction(
  identifier: "markAsDone",
  title: "Mark As Done",
  options: [])
// 2
let category = UNNotificationCategory(
  identifier: "OrganizerPlusCategory",
  actions: [dismissAction, markAsDone],
  intentIdentifiers: [],
  options: [])
// 3
UNUserNotificationCenter.current().setNotificationCategories([category])

以下是分步细分:

现在,系统知道了您的通知类别及其执行的操作,但是一个应用程序可能具有多个通知类别,并且并非每个类别都会为其分配操作。要让系统知道它应该显示您的操作,您必须将通知分配给该类别。

2. Assigning Identifiers to Notification Payload

打开NotificationManager.swift。然后,将以下内容添加到scheduleNotification(task :)content.body = "Gentle reminder for your task!"下面:

content.categoryIdentifier = "OrganizerPlusCategory"
let taskData = try? JSONEncoder().encode(task)
if let taskData = taskData {
  content.userInfo = ["Task": taskData]
}

在这里,您将通知内容的categoryIdentifier设置为创建UNNotificationCategory实例时使用的标识符。 然后,您对任务数据进行编码,并将其分配给通知内容的userInfo。 当用户对通知执行操作时,该应用将能够访问此内容。

3. Handling Actions

打开AppDelegate.swift。 将以下内容添加到AppDelegate扩展中:

// 1
func userNotificationCenter(
  _ center: UNUserNotificationCenter,
  didReceive response: UNNotificationResponse,
  withCompletionHandler completionHandler: @escaping () -> Void
) {
  // 2
  if response.actionIdentifier == "markAsDone" {
    let userInfo = response.notification.request.content.userInfo
    if let taskData = userInfo["Task"] as? Data {
      if let task = try? JSONDecoder().decode(Task.self, from: taskData) {
        // 3
        TaskManager.shared.remove(task: task)
      }
    }
  }
  completionHandler()
}

以下是代码细分:

构建并运行。

通过选择时间触发器来创建任务。 当通知出现时,长按该通知。 您会看到两个带有通知的按钮。 点击Mark as Done按钮。 无需打开应用程序即可删除任务。

做得好! 您现在已成为本地通知的专家。

在本教程中,您学习了如何创建,安排,分组和处理本地通知。 您可以使用Notification Content Extension自定义通知的外观。 Push Notifications Tutorial for iOS: Rich Push Notifications对此进行了详细介绍。

后记

本篇主要讲述了关于本地通知的详细解析,感兴趣的给个赞或者关注~~~

上一篇下一篇

猜你喜欢

热点阅读