NotificationServiceExtension和自定义action

示例

我们都收到过这种通知,它比普通通知内容更加丰富,可以附带图片、音频、视频等附件,下方也有各种选择项供用户选择。这其中附件功能由NotificationServiceExtension来提供和实现,选择项功能由UNNotificationActionUNNotificationCategory来提供和实现。
ps: 这些功能均自 iOS10 及以后才提供

一、NotificationServiceExtension

在targets中创建Notification Service Extension,然后生成的文件中有两个方法

didReceive(_:withContentHandler:)

我们用来将图片或音视频包装成attachment,然后再放入通知中。

  • 图片或音视频通过通知的附加字段来传输,此时mutable-content必须为1
  • 此方法的处理时间至多为30秒,如果30秒还未处理完毕,将调用serviceExtensionTimeWillExpire()方法
  • 因为UNNotificationAttachment的初始化方法中的URL只接收FileURL,所以需要将附件先写入本地,再拿到本地URL
  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]"
      // bestAttemptContent.subtitle = "this is subtitle"
                    
      // 处理附件 eg. 图片、视频、动图、音频
      // 附件最大尺寸 音频5M,图片10M,视频50M
      if let dict = bestAttemptContent.userInfo as? Dictionary, let urlString = dict["attachment"] as? String, let url = URL(string: urlString) {
        var path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
        path!.append(contentsOf: "/" + urlString.split(separator: "/").last!.split(separator: "?").first!)
        if ((try? Data(contentsOf: url).write(to: URL(fileURLWithPath: path!))) != nil), let attachment = try? UNNotificationAttachment(identifier: "attachment", url: URL(fileURLWithPath: path!), options: nil) {
          bestAttemptContent.attachments = [attachment]
        }
      }
      contentHandler(bestAttemptContent)
    }
  }

serviceExtensionTimeWillExpire()

此方法当附件处理时间过长时会调用,之后会将通知直接展示

调用时机

关于UNNotificationServiceExtension,系统文档有以下说明

Note
You cannot modify silent notifications or those that only play a sound or badge the app’s icon.

另外mutable-content必须为1,表示可以修改这条通知

二、自定义notification action

主要有UNNotificationCategoryUNNotificationAction两个类起作用。
其中UNNotificationAction对应用户的某个选项,如 查看跟贴 等,而UNNotificationCategory下可以添加多个action,一个通知对应一个category。
发送通知的时候需要将category参数填上想展示的对应categoryID。

UNTextInputNotificationActionUNNotificationAction的子类,点击后可以回复本条通知,就像微信的消息回复。

  // MARK: - 通知action的处理
    
  // 配置action
  fileprivate func setupNotificationAction() {
    guard #available(iOS 10.0, *) else { return }
    // options参数:
    // .foreground             白底黑字,触发后app打开(进入前台)
    // .authenticationRequired 白底黑字,触发后不进入app
    // .destructive            白底红字,触发后不进入app
    let action1 = UNNotificationAction(identifier: notificationActionIdentifierScan, title: "查看", options: .foreground)
    let action2 = UNNotificationAction(identifier: notificationActionIdentifierDismiss, title: "不感兴趣", options: .authenticationRequired)
    let action3 = UNTextInputNotificationAction(identifier: notificationActionIdentifierReply, title: "回复", options: .authenticationRequired, textInputButtonTitle: "发送", textInputPlaceholder: "请输入内容")
        
    let category1 = UNNotificationCategory(identifier: notificationCategoryNormal, actions: [action1, action2], intentIdentifiers: [notificationActionIdentifierScan, notificationActionIdentifierDismiss], options: .customDismissAction)
    let category2 = UNNotificationCategory(identifier: notificationCategorySession, actions: [action3, action1], intentIdentifiers: [notificationActionIdentifierScan, notificationActionIdentifierReply], options: .customDismissAction)
        
    UNUserNotificationCenter.current().setNotificationCategories([category1, category2])
  }

点击某个选项后进入app后依旧是调用userNotificationCenter(_:didReceive:withCompletionHandler:),所以响应处理依旧写在此方法里

  switch response.actionIdentifier {
    case notificationActionIdentifierScan:
      return
    case notificationActionIdentifierReply:
      // 获取回复内容并处理
      if let _ = (response as? UNTextInputNotificationResponse)?.userText {
                
      }
      return
    case notificationActionIdentifierDismiss:
      return
    default:
      return
   }

你可能感兴趣的:(NotificationServiceExtension和自定义action)