美文网首页
iOS10 - 推送通知

iOS10 - 推送通知

作者: lxl125z | 来源:发表于2017-07-13 21:34 被阅读0次

    iOS10里的通知与推送

    通知文章2

    远程推送工具

    一、各版本通知比较

    1. iOS 8以后,APNs推送的字节是2k,iOS8以前是256字节,iOS10现在是4k
    2. iOS 9以后APNs支持HTTP/2协议栈,优化长连接,具有标准的HTTP返回和管道复用技术
    3. iOS 10以后,APNs可根据推送消息的唯一标示符查询某条消息是否被用户阅读,可更新某一推送消息,而不用发重读的多条消息,可推送多媒体消息

    静默推送(iOS7之后):

    应用收到通知后在后台(background)状态下运行一段代码,可用于从服务器获取内容更新;

    静默推送:收到推送(没有文字没有声音),不用点开通知,不用打开APP,就能执行,用户完全感觉不到

    - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void(^)(UIBackgroundFetchResultresult))handler
    
    

    推送格式:

    1. 一定不能加alert,如果加入了alert就不是静默推送了
    2. 一定要加"content-available" : 1
    3. sound也不能加,加入的话也是静默推送,可以测试时添加.

    二、iOS10的通知

    1. iOS 10通知系统支持Images, GIFs, Audio and Video类型
    2. iOS 10推出Notification Service Extension与Notification Content Extension,可以实现推送数据在展示前进行下载更新、定制通知UI
    3. iOS 10统一了通知类型,具有时间间隔通知、地理位置通知和日历通知,App在前台获取通知。
    关系图

    1、UNUserNotificationCenter

    通知中心,用以管理通知的注册、权限获取和管理、通知的删除与更新,通过代理分发事件等

    获取未触发的通知

    func getPendingNotificationRequests(completionHandler: @escaping ([UNNotificationRequest]) -> Swift.Void)
    
    

    获取通知中心列表的通知

     func getDeliveredNotifications(completionHandler: @escaping ([UNNotification]) -> Swift.Void)
     
    

    清除某一个未触发/通知中心的通知

     open func removePendingNotificationRequests(withIdentifiers identifiers: [String])
    open func removeDeliveredNotifications(withIdentifiers identifiers: [String])
    
    

    删除所有通知

    func removeAllPendingNotificationRequests()
    func removeAllDeliveredNotifications()
    
    

    2、UNNotification

    通知实体,在UNUserNotificationCenter的代理回调事件中,告知App接收到一条通知,包含一个发起通知的请求UNNotificationRequest

    3、UNNotificationRequest

    包含通知内容UNNotificationContent和触发器UNNotificationTrigger

    4、UNNotificationContent

    通知内容,通知的title,sound,badge以及相关的图像、声音、视频附件UNNotificationAttachment,触发打开App时候指定的LacnchImage等

    5、UNNotificationTrigger

    iOS推送代码-地理位置

    iOS10之后,通过2个代理方法来处理通知的接收和点击事件,此外,本地通知跟远程通知合二为一,区分本地通知跟远程通知的类是UNNotificationTrigger.hiOS10推送

    1. UNPushNotificationTrigger是APNs通知
    2. UNTimeIntervalNotificationTrigger(本地通知) 一定时间之后发送,可以设置重复(必须大于60s)
    3. UNCalendarNotificationTrigger(本地通知) 一定日期之后,可以设置重复,也就是下一相同间隔内也推送
    4. UNLocationNotificationTrigger (本地通知)地理位置的一种通知,当用户进入或离开一个地理区域来通知。在CLRegion标识符必须是唯一的。

    6、UNNotificationResponse

    用户在触发了按钮或者文本提交的UNNotificationAction的时候,会形成一个response,通过通知中心的代理方法回调给App进行处理或者是交给扩展处理。

    7、UNNotificationAction

    是通知中添加的action,展示在通知栏的下方。默认以的button样式展示。有一个文本输入的子类UNTextInputNotificationAction。可以在点击button之后弹出一个键盘,输入信息。用户点击信息和输入的信息可以在UNNotificationResponse中获取

    UNNotificationActionOptions:foreground(打开APP),destructive(标识红色),authenticationRequired(是否需要解锁)

    ios10添加Action

    推送的时候必须添加category字段,当和本地设置的字段identifier 相同时才能展示

      //创建Action,放在注册的时候调用   
       @available(iOS 10.0, *)
        func ios10ActionRegister(){
            let enterAction = UNNotificationAction(identifier: "enterApp", title: "打开应用", options: .foreground)
            let inputAction = UNTextInputNotificationAction(identifier: "inputApp", title: "发送评论", options: .authenticationRequired, textInputButtonTitle: "回复", textInputPlaceholder: "请输入文字")
            let ingnoreAction = UNNotificationAction(identifier: "ingnoreApp", title: "忽略", options: .destructive)
            
            let category = UNNotificationCategory(identifier: "categoryIdentifier", actions: [enterAction,inputAction,ingnoreAction], intentIdentifiers: [], options: UNNotificationCategoryOptions(rawValue: 0))
            UNUserNotificationCenter.current().setNotificationCategories([category])
        }
    
    //代理方法中获取输入值
     func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
          
          ios10HandelActionButton(response)
    
        }
        
        
        func ios10HandelActionButton(response: UNNotificationResponse){
            
            print("👉👉response.actionIdentifier",response.actionIdentifier)
            
            switch response.actionIdentifier{
            case "inputApp":
                let  inputResponse = response as! UNTextInputNotificationResponse
                print("👉👉👉👉\(inputResponse.userText)")
            default:
                print("")
            }
        }
    
    

    iOS8 - ios9 添加Action

        //创建Action,放在注册的时候调用
        func ios8To9ActionRegister() -> UIMutableUserNotificationCategory{
            
            //添加操作按钮
            let action1 = UIMutableUserNotificationAction()
            action1.identifier = "enterApp"
            action1.activationMode = .foreground
            action1.title="打开应用"
            action1.isDestructive = false
            
            
            let  action2 = UIMutableUserNotificationAction()
            action2.identifier = "inputApp"
            action2.title="发送评论"
            action2.activationMode = .background
            action2.isAuthenticationRequired = false
            action2.isDestructive = true
            if #available(iOS 9.0, *) {
                action2.behavior = .textInput   //9.0支持
            } else {
                
                
            }//点击按钮文字输入,是否弹出键盘
            let category = UIMutableUserNotificationCategory()
            category.identifier = "categoryIdentifier"
            category.setActions([action1,action2], for: .default)
            
            return category
        }
    
    
     //在下面的代理方法中处理
        func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void) {
            
            //ios8to9 处理本地通知Action
            
        }
        
    
        func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [AnyHashable : Any], completionHandler: @escaping () -> Void) {
            //ios8to9 处理远程通知Action
        }
    
    

    8、UNNotificationCategory

    该分类包含了某一个通知包含的交互动作的组合,当request里面content属性categoryIdentity和UNNotificationCategory的Identity相同的话,那该通知就会以预定义好的交互按钮或者文本框添加到通知实体上。

    9、UNNotificationAttachment

    UNNotificationAttachment(附件通知)是指可以包含音频,图像或视频内容,并且可以将其内容显示出来的通知。使用本地通知时,可以在通知创建时,将附件加入即可。

    10、UNNotificationServiceExtension

    iOS10_UNNotificationServiceExtension 作者 徐不同

    ServiceExtension作用:

    1. 我们可以把即将给用户展示的通知内容,做各种自定义的处理,最终,给用户呈现一个更为丰富的通知。
    2. 安全性(收到通知后的最多30s内,你可以把你的通知内容,解密后,在重新展示在用户的通知拦上)
    附件大小

    11、UNNotificationContentExtension

    iOS10_UNNotificationContentExtension 作者 徐不同)

    收到远程或者本地通知的时候,弹出一个自定义界面

    UNNotificationContentExtension的Info.Plist

    info.plist

    UNNotificationExtensionCategory(必须要有)

    就是在收到通知的时候,我们可以让服务器把这个通知的categoryIdentifier带上,可以通过设置UNMutableNotificationContentcategoryIdentifier相同,关联当前UNNotificationContentExtension

    UNNotificationExtensionInitialContentSizeRatio(必须要有)

    这个值的类型是一个浮点类型,代表的是高度与宽度的比值。系统会使用这个比值,作为初始化view的大小。举个简单的例子来说,如果该值为1,则该视图为正方形。如果为0.5,则代表高度是宽度的一半。这个值只是初始化的一个值,在这个扩展添加后,可以重写frame,展示的时候,在我们还没打开这个视图预览时,背景是个类似图片占位的灰色,那个灰色的高度宽度之比,就是通过这个值来设定。

    UNNotificationExtensionDefaultContentHidden(可选)

    这个值是一个BOOL值,当为YES时,会隐藏上方原本推送的内容视图,只会显示我们自定义的视图。(默认为NO)

    二、通知代码

    1、通知注册

       func registerAPNS() -> Void{
            let sysVer = (UIDevice.current.systemVersion as NSString).floatValue
            if (sysVer >= 10) {
                // iOS 10
                if #available(iOS 10.0, *){
                    registerPush10()
                }
            } else if (sysVer >= 8) {
                // iOS 8-9
                registerPush8to9()
            } else {
                // before iOS 8
                registerPushBefore8()
            }
        }
        
        @available(iOS 10.0, *)
        func registerPush10() -> Void{
            let center = UNUserNotificationCenter.current()
            center.delegate = self
            center.requestAuthorization(options: [.alert, .badge, .sound]) { (result, error) in
                if result == true{
                    print("注册成功")
                }
            }
            //添加UNNotificationAction(代码见上面UNNotificationAction介绍)
            ios10ActionRegister()
            UIApplication.shared.registerForRemoteNotifications()
        }
        
        func registerPush8to9() -> Void{
            
            //添加UNNotificationAction(代码见上面UNNotificationAction介绍)
            let category = ios8To9ActionRegister() 
            let mySettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: [category])
            UIApplication.shared.registerUserNotificationSettings(mySettings)
            UIApplication.shared.registerForRemoteNotifications()
            
        }
        
        func registerPushBefore8() -> Void{
            //UIApplication.shared.registerForRemoteNotifications(matching: [.alert, .badge, .sound])
        }
    
    

    然后调用代理方法,运用第三方推送服务腾讯信鸽(如果自己服务端实现推送,可以将信鸽注册转化成本地服务器注册)

        func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
            //信鸽平台注册device token
            let deviceTokenStr = XGPush.registerDevice(deviceToken, account:"lxl125z" , successCallback: {
                print("😀😀信鸽平台注册成功!")
            }) {
                print("😞😞信鸽平台注册失败!")
            }
            print("device token is \(String(describing: deviceTokenStr))")
        }
        //注册APNs失败调用的方法
        func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
            print("😞😞注册APNs失败,reason : \(error)")
        }
    
    
    

    2、通知代理回调

    ios10回调方法

        @available(iOS 10, *)
        func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { 
            //点击通知的处理(即使应用在未打开的状态,点击通知栏进入,也会走此方法)
            //ios10以上,本地通知和远程通知合并,都会走上面的两个代理方法,可根据trigger去判断
            localOrAPNsPushHandel(notification: response.notification)
            completionHandler()
        }
        
        
        @available(iOS 10, *)
        func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
            //应用在前台的时候显示通知栏时会调用
            //设置应用在前台显示通知栏
            completionHandler([.alert, .badge, .sound])
        }
        
        @available(iOS 10.0, *)
        func localOrAPNsPushHandel(notification: UNNotification){
            if notification.request.trigger is UNPushNotificationTrigger{
                let content = notification.request.content
                //处理action((代码见上面UNNotificationAction介绍))
                ios10HandelActionButton(response: response)
                if UIApplication.shared.applicationState != .active{
                    print("【ios10设备】点击远程通知\n",content.subtitle,content.title,content.body)
                }else{
                    print("【ios10设备】前台接到通知")
                }
            }else{
                //处理action(代码见上面UNNotificationAction介绍)
                ios10HandelActionButton(response: response)
                print("处理本地推送")
            }
        } 
    
    

    ios10以下设备的回调

        func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
           //如果适配iOS6需要这个方法,【如果同时实现'didReceiveRemoteNotification completionHandler:'方法,会忽略当前方法,执行下面的方法】
            print("【ios6设备】接到【远程推送】通知")
            clickStatistic(userInfo: userInfo)  //统计通知点击量
        }
        
        func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
         //收到远程通知的回调(基于iOS 7 及以上的系统版本,如果是使用 iOS 7 的 Remote Notification 特性那么处理函数需要使用这个的方法,可以收到静默推送的回调)
            print("😜😜接到【通知推送】")
            clickStatistic(userInfo: userInfo)   //统计通知点击量
            completionHandler(.newData)
        }
         
        //收到本地推送的回调
        func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
          //本地通知
        }
        
        
        //处理action
            func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void) {
            
            //ios8to9 处理本地通知Action
            
        }
        
    
        func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [AnyHashable : Any], completionHandler: @escaping () -> Void) {
            //ios8to9 处理远程通知Action
        }
        
    

    3、本地通知

    ios10以上设备

    可以发送多媒体通知

    @available(iOS 10, *)
        func localNotification_iOS10_After(){
           let content = UNMutableNotificationContent()
            content.title = "【本地推送】标题"
            content.subtitle = "【本地推送】副标题"
            content.body = "【本地推送】主题内容"
            content.badge = 1
            //设置声音
            let sound = UNNotificationSound.default()
            content.sound = sound
            
            //设置通知附件内容(可以设置视频,图片,语音),创建附件的url,必须是一个文件路径,才能获取文件路径,开头是file://
             let filePath = Bundle.main.path(forResource: "notification_audio", ofType: "mp3")
            //let filePath = Bundle.main.path(forResource: "notification_image", ofType: "png")
            
            let fileUrl = URL(fileURLWithPath: filePath!)
            let att = try! UNNotificationAttachment(identifier: "show_audio", url: fileUrl)
            
            content.attachments = [att]
            content.categoryIdentifier = "categoryIdentifier"
            
            //修改展示的lanchImage
            content.launchImageName = "LaunchImage_1"
            
            //触发模式(大于60s才能设置repeats)
            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
            
            // 设置UNNotificationRequest
            let requestIdentifer = "TestRequest";
            let request = UNNotificationRequest(identifier: requestIdentifer, content: content, trigger: trigger)
            
            
            //添加UNNotificationAction
            let enterAction = UNNotificationAction(identifier: "enterApp", title: "打开应用", options: .foreground)
            let ingnoreAction = UNNotificationAction(identifier: "ingnoreApp", title: "忽略", options: .destructive)
            let category = UNNotificationCategory(identifier: "categoryIdentifier", actions: [enterAction,ingnoreAction], intentIdentifiers: [], options: UNNotificationCategoryOptions(rawValue: 0))
            UNUserNotificationCenter.current().setNotificationCategories([category])
            //把通知加到UNUserNotificationCenter, 到指定触发点会被触发
            UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
        }
    
    
    

    ios10以下设备

    
    func localNotification_iOS10_Before(){
           
            let localNoti = UILocalNotification()
            localNoti.fireDate = Date(timeInterval: 10, since: Date())
            localNoti.timeZone = NSTimeZone.default
            localNoti.alertBody = "【本地推送】主题内容"
            if #available(iOS 8.2, *) {
                localNoti.alertTitle = "本地推送】标题"
            }
            localNoti.alertLaunchImage = "LaunchImage_1"
            localNoti.soundName = UILocalNotificationDefaultSoundName
            localNoti.alertAction = "打开应用"
            localNoti.applicationIconBadgeNumber = 1
            UIApplication.shared.scheduleLocalNotification(localNoti)
            
        }
    
    

    4、远程通知

    ios10以上设备可以通过NotificationExtention接收多媒体消息通知,ios10之下无此功能

    Notification Extention Service中可以对收到的通知进行重新组装,以下是两个代理方法

     //这是处理通知内容重写的方法
        override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
            bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
            
            print(request.content.userInfo)
            if let bestAttemptContent = bestAttemptContent {
                // 重写一些东西
                bestAttemptContent.title = "【APNs推送】标题";
                bestAttemptContent.subtitle = "【APNs推送】子标题";
                bestAttemptContent.body = "【APNs推送】body";
                let dict =  bestAttemptContent.userInfo
                let apsDict = dict["aps"] as!  [AnyHashable : Any]
                if let category = apsDict["category"] as? String{
                   bestAttemptContent.categoryIdentifier = category
                }
                // 根据通知返回的字段,获取文件的URL
                guard let fileUrl = dict["fileUrl"] as? String,let fileType = dict["fileType"] as? String else{
                    contentHandler(bestAttemptContent)
                    return
                }
    
                //下载文件
                print("在此处做下载处理,成功后调用contentHandler(bestAttemptContent)",fileUrl)
      }
      
      
      override func serviceExtensionTimeWillExpire() {
            //附件发送通知失败,调用这个
         if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
                contentHandler(bestAttemptContent)
            }
        }
    
    
    

    Notification Extention content可以对界面进行重新定制

    
       // 这个方法是说,只要你收到通知,并且保证categoryIdentifier的设置,跟info.plist里面设置的一样,你就会调用这个方法。注意:一个会话的多个通知,每个通知收到时,都可以调用这个方法。
        func didReceive(_ notification: UNNotification) {
            self.label?.text = notification.request.content.body
        }
        
       //其他的一些代理方法。可以对播放按钮进行定制 
        
     
    

    相关文章

      网友评论

          本文标题:iOS10 - 推送通知

          本文链接:https://www.haomeiwen.com/subject/vxpghxtx.html