[iOS] 通知详解:iOS 10 UserNotifications API

通知相关系列文章
iOS10 之前通知使用介绍
[iOS] 通知详解: UIUserNotification
iOS10 相关API
[iOS] 通知详解:iOS 10 UserNotifications API
iOS10 本地/远程通知
[iOS] 通知详解: iOS 10 UserNotifications
iOS10 通知附加包
[iOS] 通知详解: iOS 10 UserNotifications -- 附加包Media Attachments
iOS10 自定义UI
[iOS] 通知详解: iOS 10 UserNotifications -- 自定义通知UI

iOS 10中引入 UserNotifications ,用来取代之前的通知处理方式,并增加了很多新的特性,来丰富通知的功能,使用时需要引入 UserNotifications 头文件,并遵循协议 UNUserNotificationCenterDelegate

import UserNotifications

由于UserNotifications的内容较多,开始写在一篇文章进行介绍,导致文章篇幅过长,所以进行了简单拆分,本文主要是介绍常用的一些API,如果想直接看使用方法,可以跳过,不清楚的再回来查看有无相关的介绍。

相关类库介绍

UserNotifications 模块主要涉及到以下一些类库

用户通知中心 UNUserNotificationCenter

主要管理通知相关的调度,添加,其相关的属性和方法如下

// The delegate can only be set from an application 代理
    weak open var delegate: UNUserNotificationCenterDelegate?
 // 当前设备是否支持的扩展
    // Returns YES if the current device supports content extensions
    open var supportsContentExtensions: Bool { get }

    // 获取当前的通知中心(单例)
    // The UNUserNotificationCenter for the current application
    open class func current() -> UNUserNotificationCenter

    // 请求通知的权限,参数为 UNAuthorizationOptions 的集合
    // User authorization is required for applications to notify the user using UNUserNotificationCenter via both local and remote notifications.
    open func requestAuthorization(options: UNAuthorizationOptions = [], completionHandler: @escaping (Bool, Error?) -> Void)

    // 通知快捷操作action集合,参数为 UNNotificationCategory的集合
    // Notification categories can be used to choose which actions will be displayed on which notifications.
    open func setNotificationCategories(_ categories: Set<UNNotificationCategory>)
// 获取当前添加的 Categories
    open func getNotificationCategories(completionHandler: @escaping (Set<UNNotificationCategory>) -> Void)

    // 获取通知当前的设置,详见 UNNotificationSettings
    // The application's user notification settings
    open func getNotificationSettings(completionHandler: @escaping (UNNotificationSettings) -> Void)

    // 添加通知的请求
    // Notification requests can be scheduled to notify the user via time and location. See UNNotificationTrigger for more information. Calling -addNotificationRequest: will replace an existing notification request with the same identifier. A notification request with the identifier as an existing delivered notifications will alert for the new notification request and replace the existing delivered notification when it is triggered. The number of pending notification requests that may be scheduled by an application at any one time is limited by the system.
    open func add(_ request: UNNotificationRequest, withCompletionHandler completionHandler: ((Error?) -> Void)? = nil)

    // 获取所有等待执行的通知请求
    // Notification requests that are waiting for their trigger to fire
    open func getPendingNotificationRequests(completionHandler: @escaping ([UNNotificationRequest]) -> Void)
// 取消未执行的通知请求
    open func removePendingNotificationRequests(withIdentifiers identifiers: [String])
// 取消所有未执行的通知请求
    open func removeAllPendingNotificationRequests()

    // 获取已添加到通知中心的通知
    // Notifications that have been delivered and remain in Notification Center. Notifications triggered by location cannot be retrieved, but can be removed.
    open func getDeliveredNotifications(completionHandler: @escaping ([UNNotification]) -> Void)
// 移除通知
    open func removeDeliveredNotifications(withIdentifiers identifiers: [String])

    open func removeAllDeliveredNotifications()

通知中心协议 UNUserNotificationCenterDelegate

其中主要有三个协议方法

// The method will be called on the delegate only if the application is in the foreground. If the method is not implemented or the handler is not called in a timely manner then the notification will not be presented. The application can choose to have the notification presented as a sound, badge, alert and/or in the notification list. This decision should be based on whether the information in the notification is otherwise visible to the user.
    @available(iOS 10.0, *)
    optional public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)

    
    // The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from application:didFinishLaunchingWithOptions:.
    @available(iOS 10.0, *)
    optional public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)

    
    // The method will be called on the delegate when the application is launched in response to the user's request to view in-app notification settings. Add UNAuthorizationOptionProvidesAppNotificationSettings as an option in requestAuthorizationWithOptions:completionHandler: to add a button to inline notification settings view and the notification settings view in Settings. The notification will be nil when opened from Settings.
    @available(iOS 12.0, *)
    optional public func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?)

  • 第一个协议方法,是当应用在前台运行时调用,其 completionHandler 回调用于告诉系统以何种方式告知用户,来了新通知,参数为UNNotificationPresentationOptions 类型,有三个值可供选择:badge、alert、sound,如果没有调用completionHandler回调,则不会有提醒;在iOS10之前,如果应用在前台运行,来了新通知,是无法使用系统提醒的。
  • 第二个协议方法,是当应用在后台或者被杀死,当用户点击通知内容或者通知action时,会调用该方法,通过 UNNotificationResponse 实例可获取详细的信息
  • 第三个协议方法,是在app内展示通知的设置情况,需要在请求权限的options中添加 providesAppNotificationSettings,iOS12才支持

UNNotificationRequest

主要是针对本地通知,发起一个通知请求,其主要有一个初始化方法,和三个只读属性来获取相应的值;
如果是远程通知,代理方法里会有回调的UNNotificationRequest实例,直接获取相应的值即可:

// identifier: 唯一标识符
// content:要展示的消息内容,详见UNNotificationContent
// trigger:触发的方式,详见 UNNotificationTrigger
public convenience init(identifier: String, content: UNNotificationContent, trigger: UNNotificationTrigger?)

open var identifier: String { get }

    // The content that will be shown on the notification.
    @NSCopying open var content: UNNotificationContent { get }

    // The trigger that will or did cause the notification to be delivered. No trigger means deliver now.
    @NSCopying open var trigger: UNNotificationTrigger? { get }

UNNotificationContent & UNMutableNotificationContent

通知内容的承载体,远程通知回调的主要是 UNNotificationContent,创建本地通知内容的时候使用 UNMutableNotificationContent

// 通知的附件,iOS10之后,允许通知携带一张图片,一段视频,一段音频
// Optional array of attachments.
    open var attachments: [UNNotificationAttachment]

    // 角标数值
    // The application badge number. nil means no change. 0 to hide.
    @NSCopying open var badge: NSNumber?

  // 标题,限制一行,多余的以...
// The title of the notification. Use -[NSString localizedUserNotificationStringForKey:arguments:] to provide a string that will be localized at the time that the notification is presented.
    open var title: String

    // 副标题,限制一行,多余的以...
    // The subtitle of the notification. Use -[NSString localizedUserNotificationStringForKey:arguments:] to provide a string that will be localized at the time that the notification is presented.
    open var subtitle: String

    // 消息内容
    // The body of the notification. Use -[NSString localizedUserNotificationStringForKey:arguments:] to provide a string that will be localized at the time that the notification is presented.
    open var body: String

    // 所属的 category 标识符
    // The identifier for a registered UNNotificationCategory that will be used to determine the appropriate actions to display for the notification.
    open var categoryIdentifier: String

    // 点击消息启动app时的启动图
    // The launch image that will be used when the app is opened from the notification.
    open var launchImageName: String

    // 消息提示音,默认是.default
    // The sound that will be played for the notification.
    @NSCopying open var sound: UNNotificationSound?

// 消息的payload内容
  // Apps can set the userInfo for locally scheduled notification requests. The contents of the push payload will be set as the userInfo for remote notifications.
    open var userInfo: [AnyHashable : Any]


    // The unique identifier for the thread or conversation related to this notification request. It will be used to visually group notifications together.
    open var threadIdentifier: String


    /// The argument to be inserted in the summary for this notification.
    @available(iOS 12.0, *)
    open var summaryArgument: String

    
    /// A number that indicates how many items in the summary are represented in the summary.
    /// For example if a podcast app sends one notification for 3 new episodes in a show,
    /// the argument should be the name of the show and the count should be 3.
    /// Default is 1 and cannot be 0.
    @available(iOS 12.0, *)
    open var summaryArgumentCount: Int

UNNotificationTrigger 推送的触发器

是一个抽象类,他有四个子类,代表四种不同的触发方式

UNPushNotificationTrigger

远程通知触发,一般是由苹果服务器触发

UNTimeIntervalNotificationTrigger 时间间隔触发器

一定时间间隔后触发通知:

// 初始化方法,时间间隔,是否重复触发
public convenience init(timeInterval: TimeInterval, repeats: Bool)
// 时间间隔,只读
open var timeInterval: TimeInterval { get }

// 下次触发的日期
    open func nextTriggerDate() -> Date?

例如:

// 10s后触发
let timer = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
UNCalendarNotificationTrigger 日期时间触发器

在某个日期的某个事件触发通知

// 获取当前的DateComponents
open var dateComponents: DateComponents { get }

    // 初始化方法,参数是DateComponents类型
    // The next date is calculated using matching date components.
    public convenience init(dateMatching dateComponents: DateComponents, repeats: Bool)

    // 下次触发的日期
    open func nextTriggerDate() -> Date?

例如:

// 每周日的8点
        var dateCom = DateComponents()
        dateCom.weekday = 1
        dateCom.hour = 8
        
        let calendarTri = UNCalendarNotificationTrigger(dateMatching: dateCom, repeats: true)

附,从DateComponents 获取具体的时间


// 从 DateComponents 获取具体的时间信息
        let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
        
        if let date = calendar.date(from: dateCom) {
            let weekday = calendar.component(Calendar.Component.weekday, from: date)
        }
UNLocationNotificationTrigger 地理位置触发器

当进入/离开某个地理范围时,触发的本地通知,需要有定位权限

@NSCopying open var region: CLRegion { get }

    // 初始化方法,参数为CLRegion
    public convenience init(region: CLRegion, repeats: Bool)

例如:

let center = CLLocationCoordinate2D(latitude: 37.33, longitude: -122.009)
        let regin = CLCircularRegion(center: center, radius: 2000, identifier: "reginid")
        regin.notifyOnExit = true
        regin.notifyOnEntry = true
        
        let locaTrig = UNLocationNotificationTrigger(region: regin, repeats: true)

通知快捷操作Action

UNNotificationAction

通知点击事件的快捷操作,其创建主要是一个初始化方法

public convenience init(identifier: String, title: String, options: UNNotificationActionOptions = [])

open var identifier: String { get }
open var title: String { get }
open var options: UNNotificationActionOptions { get }

UNTextInputNotificationAction

通知快捷回复输入框的action:

public convenience init(identifier: String, title: String, options: UNNotificationActionOptions = [], textInputButtonTitle: String, textInputPlaceholder: String)

open var textInputButtonTitle: String { get }
open var textInputPlaceholder: String { get }
UNNotificationActionOptions

快捷操作的设置选项

@available(iOS 10.0, *)
public struct UNNotificationActionOptions : OptionSet {

    public init(rawValue: UInt)

    // 需要授权验证才能响应,点击不会打开app
    // Whether this action should require unlocking before being performed.
    public static var authenticationRequired: UNNotificationActionOptions { get }

    // 红色的按钮,点击不会打开app
    // Whether this action should be indicated as destructive.
    public static var destructive: UNNotificationActionOptions { get }

    // 点击后会打开app
    // Whether this action should cause the application to launch in the foreground.
    public static var foreground: UNNotificationActionOptions { get }
}

action的响应事件会调用代理UNUserNotificationCenterDelegate的方法进行反馈。

UNNotificationCategory

// identifier :当前Category的唯一标识符
// actions:需要展示的快捷按钮集合
// intentIdentifiers:意图标识符,告诉系统该通知可能与Sari进行的请求有关
// options:如何处理该消息
public convenience init(identifier: String, actions: [UNNotificationAction], intentIdentifiers: [String], options: UNNotificationCategoryOptions = [])

    // identifier :当前Category的唯一标识符
// actions:需要展示的快捷按钮集合
// intentIdentifiers:意图标识符,告诉系统该通知可能与Sari进行的请求有关
// hiddenPreviewsBodyPlaceholder:当预览被隐藏时,替换消息内容body;例如开启隐私保护的时候,锁屏时看不到消息具体内容
// options:如何处理该消息
    @available(iOS 11.0, *)
    public convenience init(identifier: String, actions: [UNNotificationAction], intentIdentifiers: [String], hiddenPreviewsBodyPlaceholder: String, options: UNNotificationCategoryOptions = [])

    // iOS 12中的消息分组
// identifier :当前Category的唯一标识符
// actions:需要展示的快捷按钮集合
// intentIdentifiers:意图标识符,告诉系统该通知可能与Sari进行的请求有关
// hiddenPreviewsBodyPlaceholder:当预览被隐藏时,替换消息内容body;例如开启隐私保护的时候,锁屏时看不到消息具体内容
// categorySummaryFormat:分组后的消息,显示的第一则消息下面的摘要文字,默认是“还有 %d 个通知”,可以自定义,以此参数传入
// options:如何处理该消息
    @available(iOS 12.0, *)
    public convenience init(identifier: String, actions: [UNNotificationAction], intentIdentifiers: [String], hiddenPreviewsBodyPlaceholder: String?, categorySummaryFormat: String?, options: UNNotificationCategoryOptions = [])

UNNotificationCategory 创建完成后,其identifier 要赋值给UNMutableNotificationContent实例的categoryIdentifier属性

UNNotificationAttachment 通知附加包

iOS 10之后,通知允许添加一个与该通知关联的媒体文件,例如:一张图片,一段音乐或者视频,添加的文件必须保存在磁盘上。
对于本地通知,在添加通知的时候就需要创建UNNotificationAttachment实例,添加到相应的content中;如果是远程通知,需要通过扩展程序来下载附加的文件,然后创建UNNotificationAttachment实例,添加到通知中。

这里在创建 UNNotificationAttachment 实例的时候,会去校验文件的格式,如果是不支持的文件,或者超出规定大小的文件,会返回nil。

如果创建成功,文件数据将被移动到附件数据存储中;如果是本地的文件,会复制文件数据到附件数据存储中,以便于访问这些数据。

支持的文件类型及大小限制

  • Audio 声音文件 大小限制在 5Mb以内
    支持的格式有kUTTypeAudioInterchangeFileFormat、kUTTypeWaveformAudio、kUTTypeMP3、kUTTypeMPEG4Audio
  • Image图片 大小限制在 10Mb以内
    支持的格式:kUTTypeJPEG、kUTTypeGIF、kUTTypePNG
  • Movie 视频文件 最大 50Mb
    支持的格式:kUTTypeMPEG、kUTTypeMPEG2Video、kUTTypeMPEG4、kUTTypeAVIMovie

创建时,主要是有一个初始化方法:


 // Creates an attachment for the data at URL with an optional options dictionary. URL must be a file URL. Returns nil if the data at URL is not supported.
    public convenience init(identifier: String, url URL: URL, options: [AnyHashable : Any]? = nil) throws


// The identifier of this attachment
    open var identifier: String { get }

    // The URL to the attachment's data. If you have obtained this attachment from UNUserNotificationCenter then the URL will be security-scoped.
    open var url: URL { get }

    // The UTI of the attachment.
    open var type: String { get }

需要注意的是,这个初始化方法会抛出异常,需要使用try进行判断。

其参数 options是一个字典,支持以下几个key:

  • UNNotificationAttachmentOptionsTypeHintKey
    指定文件类型,其值为 String 类型,常用的有kUTTypeImage,kUTTypeJPEG2000,kUTTypeTIFF,kUTTypePICT,kUTTypeGIF ,kUTTypePNG,kUTTypeQuickTimeImage, 需要引入import MobileCoreServices
  • UNNotificationAttachmentOptionsThumbnailHiddenKey
    是否隐藏缩略图,其值为 Number 类型的Bool
  • UNNotificationAttachmentOptionsThumbnailClippingRectKey
    缩略图的裁剪区域,其值可以这样创建 ,坐标值为(0---1)
    let v = CGRect(x: 0, y: 0, width: 0.5, height: 0.5).dictionaryRepresentation
  • UNNotificationAttachmentOptionsThumbnailTimeKey
    动画图像帧数必须是NSNumber。视频时间是一个以秒为单位的NSNumber,或者是使用CMTimeCopyAsDictionary编码的CMTime

相关options介绍

UNNotificationCategoryOptions

告诉系统该如何处理该消息

@available(iOS 10.0, *)
public struct UNNotificationCategoryOptions : OptionSet {

    public init(rawValue: UInt)

    // 需要通过代理委托处理,调用UNUserNotificationCenterDelegate的相应方法
    // Whether dismiss action should be sent to the UNUserNotificationCenter delegate
    public static var customDismissAction: UNNotificationCategoryOptions { get }

    // 允许在驾驶模式下显示通知
    // Whether notifications of this category should be allowed in CarPlay
    public static var allowInCarPlay: UNNotificationCategoryOptions { get }

    // 在用户禁止显示预览的情况下,显示标题
    // Whether the title should be shown if the user has previews off
    @available(iOS 11.0, *)
    public static var hiddenPreviewsShowTitle: UNNotificationCategoryOptions { get }
// 在用户禁止显示预览的情况下,显示副标题
    // Whether the subtitle should be shown if the user has previews off
    @available(iOS 11.0, *)
    public static var hiddenPreviewsShowSubtitle: UNNotificationCategoryOptions { get }
}
UNAuthorizationOptions

请求权限的类型,请求权限的方法 requestAuthorization 参数

@available(iOS 10.0, *)
public struct UNAuthorizationOptions : OptionSet {

    public init(rawValue: UInt)

    // 角标提醒
    public static var badge: UNAuthorizationOptions { get }
// 声音提醒
    public static var sound: UNAuthorizationOptions { get }
// 弹框提醒
    public static var alert: UNAuthorizationOptions { get }
// 行车模式下,接收通知
    public static var carPlay: UNAuthorizationOptions { get }

    @available(iOS 12.0, *)
    public static var criticalAlert: UNAuthorizationOptions { get }

    @available(iOS 12.0, *)
    public static var providesAppNotificationSettings: UNAuthorizationOptions { get }

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

推荐阅读更多精彩内容