zoukankan      html  css  js  c++  java
  • iOS10 推送通知详解(UserNotifications)

    iOS10新增加了一个UserNotificationKit(用户通知框架)来整合通知相关的API,UserNotificationKit框架增加了很多令人惊喜的特性:

    • 更加丰富的推送内容:现在可以设置推送的title、subtitle、body 以及符合大小的图片、音频、视频等附件内容。
    • 更好的通知管理:现在可以对通知进行查看、更新、删除了。
    • 更优雅的展示方式:可以设置应用在前台展示通知。

    对iOS10而言,UserNotificationKit(用户通知框架)是一种系统层面的UI展示,远程通知APNS只是通知的一种触发方式,UserNotificationKit的重要意义在于统一了Remote(远程通知)和Local(本地通知)。

    UserNotificationKit 基本流程

    UserNotificationKit使用大概分为以下几个过程:

    • 注册通知: 获取相关权限,注册APNS
    • 发送通知: 创建通知并发起通知请求
    • 处理通知: 处理通知回调,对通知进行额外的操作

    首先你需要向用户请求通知权限,在取得权限后注册通知;
    然后你可以创建一个通知并发起推送,当然对于远程推送APNS而言,你还需要注册DeviceToken;
    在接受到推送通知后可以根据app的运行情况决定是否展示通知,当然你也可以通过一系列的回调接口对通知进行处理加工。

    注册通知

    请求权限

    iOS 10 进一步消除了本地推送和远程推送的区别,因为两者在申请权限的时候都是在打断用户的行为。因此iOS 10统一了推送权限的申请:

    //iOS8以下 
    [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];
    //iOS8 - iOS10
    [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge categories:nil]];
    //iOS10
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    UNAuthorizationOptions options = UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert;
    [center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) {
    
    }
    //iOS10 swift 
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]{          granted, error in
    }

    推送设置

    iOS 10 还可以实时获取用户当前的推送的设置:

    //可以获取的设置参数
    @available(iOS 10.0, *) 
    open class UNNotificationSettings : NSObject, NSCopying, NSSecureCoding {
        open var authorizationStatus: UNAuthorizationStatus { get }
        open var soundSetting: UNNotificationSetting { get }
        open var badgeSetting: UNNotificationSetting { get }
        open var alertSetting: UNNotificationSetting { get }
        open var notificationCenterSetting: UNNotificationSetting { get }
        open var lockScreenSetting: UNNotificationSetting { get }
        open var carPlaySetting: UNNotificationSetting { get }
        open var alertStyle: UNAlertStyle { get }
    }
    //获取设置
    UNUserNotificationCenter.current().getNotificationSettings {
        settings in 
        print(settings.authorizationStatus) // .authorized | .denied | .notDetermined
        print(settings.badgeSetting) // .enabled | .disabled | .notSupported
    }

    在有些情况下,可以对推送权限设置进行检查。

    APNS:DeviceToken

    一旦获得用户权限后,你就可以在应用中发送本地通知了。不过对于APNS而言,你还需要申请DeviceToken,把DeviceToken传递给服务器,然后服务器根据DeviceToken发送到对应的用户。

    //向APNSS请求deviceToken:
    UIApplication.shared.registerForRemoteNotifications()
    //回调
    func application(_ application: UIApplication,             didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {  
            print("Get Push token: (deviceToken)")
        }

    发送通知

    本地通知发送的基本流程

    1.设置推送内容
    2.设置通知触发器
    3.添加通知

    1.设置推送内容

    let content = UNMutableNotificationContent()
    content.title = "Time Interval Notification" //推送内容标题
    content.subtitle = "My first notification" //推送内容子标题
    content.body = "My first notification"// 推送内容body
    content.categoryIdentifier = "categoryIdentifier"  //category标识,操作策略

    2.设置通知触发器

    有4种触发器
    UNPushNotificationTrigger 触发APNS服务,系统自动设置(这是区分本地通知和远程通知的标识)
    UNTimeIntervalNotificationTrigger 一段时间后触发
    UNCalendarNotificationTrigger 指定日期触发
    UNLocationNotificationTrigger 根据位置触发,支持进入某地或者离开某地或者都有。

    //设置5秒后触发
    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
    
    //每周三,13点触发
    var components:DateComponents = DateComponents()
    components.weekday = 4;//周三
    components.hour = 13;//13点
    let triggerDateComponents = UNCalendarNotificationTrigger(dateMatching: components, repeats: true);
    
    //这个点,100米范围内,进入触发。
    let Coordinate2:CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 39, longitude: 116);
    let region:CLCircularRegion = CLCircularRegion(center: Coordinate2, radius: 100, identifier: "center")
    region.notifyOnEntry = true;
    region.notifyOnExit = false;
    let triggerRegion = UNLocationNotificationTrigger(region: region, repeats: true);

    3.添加通知

    //先创建一个请求
    let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger)
    //将请求添加到发送中心
    UNUserNotificationCenter.current().add(request) { error in
        if error == nil {
            print("Time Interval Notification scheduled: (requestIdentifier)")
        }
    }

    APNS:Payload

    iOS 10之前的推送内容比较单一,仅仅支持一段文字的消息推送,最好带上badge和sound,以及一些自定义的字段内容,而在iOS 10中,Apple丰富了推送内容,并且增加了更多的显示方式。

    //iOS 10 之前的基础Payload: 
    {
      "aps":{
        "alert":{
            "body": "This is a message"
        },
        "sound":"default",
        "badge":1
      }
    }
    //iOS 10 基础Payload:
    {
      "aps":{
        "alert":{
          "title":"I am title",
          "subtitle":"I am subtitle",
          "body":"I am body"
        },
        "sound":"default",
        "badge":1
      }
    }

    title和subtitle并不是必须的。

    处理通知

    常规处理

    在创建通知请求时,我们已经指定了标识符。iOS10中我们可以通过标识符来管理处理通知。通UserNotificationKIt的一系列API 你可以做到: 查找更新删除通知。其中关键在于request的identifier,即在创建的时候的指定的通知的标识符。

    查找通知
    //获取所有等待递送的通知
    UNUserNotificationCenter.current().getPendingNotificationRequests { (request) in
             }
    //获取所有已经递送的通知
    UNUserNotificationCenter.current().getDeliveredNotifications { (noti) in
              }
    更新通知

    远程推送可以进行通知的更新,在使用 center 的 addNotificationRequest:withCompletionHandler: 向 APNS提交请求时,在 HTTP/2 的 header 中 apns-collapse-id key 的内容将被作为该推送的标识符进行使用。多次推送同一标识符的通知即可进行更新。

    //先创建一个请求
    let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger)
    //重新添加通知
    UNUserNotificationCenter.current().add(request) { error in
        if error == nil {
            print("Time Interval Notification scheduled: (requestIdentifier)")
        }
    }
    删除通知/取消通知
    //使用这个API来移除通知 还有一系列相似的API
    UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: dentifiers)
    //取消还未展示的本地通知
    UNUserNotificationCenter.current().add(request) { error in
        if error != nil {
            print("Notification request added: (identifier)")
        }
    }
    delay(2) {
        let newTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
        let newRequest = UNNotificationRequest(identifier: identifier, content:newContent, trigger: newTrigger)
        UNUserNotificationCenter.current().add(newRequest) { error in
            if error != nil {
                print("Notification request updated: (identifier)")
            }
        }
    }

    通知的回调:UNUserNotificationCenterDelegate

    UNUserNotificationCenterDelegate提供了两个方法处理通知。两个方法分别对应如何在应用内展示通知,和收到通知响应时要如何处理的工作。

    //在应用内展示通知
    func userNotificationCenter(_ center: UNUserNotificationCenter, 
                           willPresent notification: UNNotification, 
                           withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) 
        {
            completionHandler([.alert, .sound])
    
            // 如果不想显示某个通知,可以直接用空 options 调用 completionHandler:
            // completionHandler([])
        }
    //对通知进行响应,收到通知响应时的处理工作,用户与你推送的通知进行交互时被调用;
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        completionHandler()
    }

    Notification Extension

    iOS 10 中添加了很多 extension,作为应用与系统整合的入口。与通知相关的 extension 有两个:Service Extension 和 Content Extension。前者可以让我们有机会在「接收到推送之后、展示推送之前」对通知内容进行修改;后者可以用来自定义通知视图的样式。

    Service Extension

    Service Extension可以对推送进行处理,更改、替换原有的内容。他可以对通知内容进行加密,也可以给推送展示内容添加附件(比如照片、背景音乐),使得内容更加丰富。

    //NotificationService 的模板已经为我们进行了基本的实现:
    class NotificationService: UNNotificationServiceExtension {
    
        var contentHandler: ((UNNotificationContent) -> Void)?
        var bestAttemptContent: UNMutableNotificationContent?
    
        // 1 让你可以在后台处理接收到的推送,传递修改后的的内容给 contentHandler,然后展示
        override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
            self.contentHandler = contentHandler
            bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
            if let bestAttemptContent = bestAttemptContent {
                if request.identifier == "mutableContent" {
                    bestAttemptContent.body = "(bestAttemptContent.body), onevcat"
                }
                contentHandler(bestAttemptContent)
            }
        }
    
        // 2 在在你获得的一小段运行代码的时间内没有调用 contentHandler 的话,系统会调用这个方法。可以在这里传肯定不会出错的内容,或者他会默认传递原始的推送内容。
        override func serviceExtensionTimeWillExpire() {
            if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
                contentHandler(bestAttemptContent)
            }
        }
    }

    Service Extension 现在只对远程推送APNS的通知起效,你可以在推送 payload 中增加一个 mutable-content 值为 1 的项来启用内容修改

    {
      aps : {
        alert : "New Message",
        mutable-content : 1
      },
      encrypted-content : "#myencryptedcontent"
    }

    Media Attachments

    iOS 10 的另一个亮眼功能是多媒体的推送,开发者能够直接在推送的通知内容里面传递多媒体资源,在客户端进行直接的展示,极大丰富了推送内容的可读性和趣味性。

    为本地通知添加添加多媒体内容

    通过本地磁盘上的文件 URL 创建一个 UNNotificationAttachment 对象,然后将这个对象放到数组中赋值给 content 的 attachments 属性:

    let content = UNMutableNotificationContent()  
    content.title = "Hey guys"
    content.body = " body "
    if let imageURL = Bundle.main.url(forResource: "image", withExtension: "jpg"),  
    let attachment = try? UNNotificationAttachment(identifier: "imageAttachment", url: imageURL, options: nil)
    {
        content.attachments = [attachment]
    }
    为远程推送添加多媒体内容

    只需要在推送的 payload 中指定需要加载的资源地址,这个地址可以是应用 bundle 内已经存在的资源,也可以是网络的资源。不过因为在创建 UNNotificationAttachment 时我们只能使用本地资源,所以如果多媒体还不在本地的话,我们需要先将其下载到本地。在完成 UNNotificationAttachment 创建后,我们就可以和本地通知一样,将它设置给 attachments 属性,然后调用 contentHandler 了。

    {
      "aps":{
        "alert":{
          "title":"Image Notification",
          "body":"Show me an image from web!"
        },
        "mutable-content":1 //表示我们会在接收到通知时对内容进行更改
      },
      "image": "https://img1.baidu.com.jpg"//指明了目标图片的地址 
    }
    • 如果你想在远程推送来的通知中显示应用 bundle 内的资源的话,要注意 extension 的 bundle 和 app main bundle 并不是一回事儿。你可以选择将图片资源放到 extension bundle 中,也可以选择放在 main bundle 里。总之,你需要保证能够获取到正确的,并且你具有读取权限的 url。
    • UNNotificationContent 的 attachments 虽然是一个数组,但是系统只会展示第一个 attachment 对象的内容。不过你依然可以发送多个 attachments,然后在要展示的时候再重新安排它们的顺序,以显示最符合情景的图片或者视频。

    Notification Actions

    iOS 8 和 9 中 Apple 引入了可以交互的通知,这是通过将一簇 action 放到一个 category 中,将这个 category 进行注册,最后在发送通知时将通知的 category 设置为要使用的 category 来实现的。这些action的API在iOS10 中被统一。

    注册Actions
    private func registerNotificationCategory() {
        let saySomethingCategory: UNNotificationCategory = {
            // 1 创建 action 即一项交互操作 
            let inputAction = UNTextInputNotificationAction(
                identifier: "action.input",
                title: "Input", // 是交互按钮的内容
                options: [.foreground], // options 可以让该 action 成为一条可在前台执行的 action
                textInputButtonTitle: "Send",
                textInputPlaceholder: "What do you want to say...")
    
            let goodbyeAction = UNNotificationAction(
                identifier: "action.goodbye",//,推送消息的其中的identifier
                title: "Goodbye",
                options: [.foreground])
    
            let cancelAction = UNNotificationAction( 
                identifier: "action.cancel",
                title: "Cancel",
                options: [.destructive])
            //2. 创建 category
            return UNNotificationCategory(identifier:"saySomethingCategory", actions: [inputAction, goodbyeAction, cancelAction], intentIdentifiers: [], options: [.customDismissAction])
        }()
        // 3 把 category 添加到通知中心:
        UNUserNotificationCenter.current().setNotificationCategories([saySomethingCategory])
    }
    // 4 触发方式 
    //远程通知触发方式
    {
      aps : {
      alert : "Welcome to WWDC !",
      category : "saySomethingCategory" //和第二步identifier:"saySomethingCategory一致
             }
    }
    //本地通知触发方式 Local Notifications 只需要在创建 contnet 的时候指定 和第二步identifier 即可
    content.categoryIdentifier = "saySomethingCategory";

    通过上面的三个步骤我们已经创建了一个category



    作者:曲年
    链接:http://www.jianshu.com/p/567abab2098f
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    hdu 5723 Abandoned country 最小生成树 期望
    OpenJ_POJ C16G Challenge Your Template 迪杰斯特拉
    OpenJ_POJ C16D Extracurricular Sports 打表找规律
    OpenJ_POJ C16B Robot Game 打表找规律
    CCCC 成都信息工程大学游记
    UVALive 6893 The Big Painting hash
    UVALive 6889 City Park 并查集
    UVALive 6888 Ricochet Robots bfs
    UVALive 6886 Golf Bot FFT
    UVALive 6885 Flowery Trails 最短路
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/7239361.html
Copyright © 2011-2022 走看看