WWDC2016-Session708(高级通知)

此篇我们接着Session 707接着讲,有兴趣的可以查看 : http://xiaolu520.com/2017/06/08/WWDC2016-Session707%EF%BC%88UNNotifications%EF%BC%89/

概览

本篇主要是对UNNotification框架的扩展,以及一些高级功能的实现

主要讲三个部分

  • 通知的用户界面多种多样。
  • 通知可以支持附件
  • 用户针对界面、交互的自定义

通知用户界面的多种多样

iOS 10新推出的通知框架可以实现十分丰富的推送效果,可以实现图片视频音频Gif动态图片的效果,同时可以实现快捷回复自定义用户交互等一系列酷炫的效果。此处就不上图了。

通知的媒体附件

上一篇我们了解了一个全新的十分重要的概念 Service Extension。此篇会使用Service Extension来完成一些重要的功能。

众所周知,iOS的通知在改版之后支持最大的推送容量仅仅才4KB,我们想依靠推送通知实现音视频的展示显然是不切实际的,这时候我们就要用到 Service Extension

媒体附件支持本地通知远程通知,可以支持图片视频音频Gif动态图片,而这些媒体资源会在系统内存中单独开辟出的一块儿空间存放,无需开发者进行管理,需要使用的时候,可以申请读取。

在通知推送到用户设备之前,我们需要标明这个推送的内容是可变的,同时将附件以链接的形式给my-attachment属性赋值,代码如下:

{
    aps: {
        alert: { … },
        mutable-content: 1
    }
    my-attachment: "https://example.com/photo.jpg"
}

Service Extension中,可以对附件的链接进行下载操作。这样就可以实现通过Extension实现下载操作。

    Public class notificationService:UNNotificationServiceExtension {
        
        override public func didreceive(request:UNNotificationRequest,withContentHandler contentHandler: (UNNotificationContent) -> Void){
        
        let fileURL = "www.baidu.com"
        let attachment = UNNotificationAttachment(identifier: "image" ,url: fileURL,options: nil)
        let content = request.content.mutableCopy as! UNMutableNotificationContent
        content.attachments = [ attachment ]
        contentHandler(content)
    }

通过以上的步骤即可实现,通过Service Extension下载附件并显示出来的功能。

自定义通知样式


那么针对通知的样式,我们可能会有这样或者那样的需求,我们希望通知的风格和我们的App风格一致,那么这个时候,我们就要自定义通知的UI样式

想实现通知的自定义样式,我们会需要

  • 通知内容的扩展(Notification content extension)
  • 自定义的View
  • 无需用户交互
  • 针对通知可以触发相应的动作

首先创建一个Notification Content

通过代码,我们就知道这个Notification Extension继承自UIViewController,其实就是VC那一层。我们一共会得到三个文件。一个VC文件,一个StoryBoard的图形化界面文件还有一个info.plist的配置文件。

VC文件中只有一个遵守UINotificationContentExtension协议的didReceive方法是必须实现的,这个方法随着通知被发送到Extension,当用户展开通知时需要更新UI,随视图控制器的生命周期方法被一起调用,通过这个方法我们获取到具体的通知,得到通知的内容以及其他信息,从而也就可以进行接下来的操作.

为了让Notification Extension知道具体是哪个通知该被扩展,你需要在info.plist文件中,对Notification Extension Category进行注册,此时注册所用的Identifier,应该和你发送通知时所用的identifier一致,这样就将这个Extension和你的Notification绑定了,当然扩展也可以关联多个类型。

如下图:

在自定义通知的过程中,会碰到一些问题:

例如,显示范围过大,或者通知会显示重复的信息。

要解决通知会显示重复的信息,这个只需要在info.plist中将默认的属性值修改了就可以。

而为了解决显示区域过大,我们要修改显示区域的范围,通过PreferedContentSize可以做到,我们可以按照自己的需要设定一个范围。但是这样还会有另外一个问题,就是通知默认是按照大尺寸出现的,出现后的一瞬间再按照PreferedContentSize所给的尺寸去更新UI,为了避免出现这种动画,只需修改另一个属性UNNotificationExtensionDefaultContentHidden

UNNotificationExtensionDefaultContentHidden这个属性,可以保证通知界面一开始不出现,知道改为合适的尺寸直接出现,这样做就避免了通知出现一瞬间,还要更新UI。

PreferedContentSize我们需要在代理方法中自己用代码设定,也可以在info.plist利用UNNotificationExtensionInitialContentSizeRatio设置区域。

    Public class notificationService:UNNotificationServiceExtension {
    
        override func viewDidLoad() { super.viewDidLoad() {
        
            let size = view.bounds.size preferredContentSize = CGSize(width: size.width, height: size.width / 2)
        
        }
        
        override public func didreceive(request:UNNotificationRequest,withContentHandler contentHandler: (UNNotificationContent) -> Void){
        }

展示通知的媒体附件

我们知道通知的媒体附件被系统单独的开辟出一块儿内存空间所管理,所以当我们想要使用的时候,我们要申请读取,访问结束后要将空间关闭


class NotificationViewController: UIViewController, UNNotificationContentExtension {

    @IBOutlet var eventImage: UIImageView!

    func didReceive(_ notification: UNNotification) { 
    
        let content = notification.request.content

        if let attachment = content.attachments.first { 
            // 使用时申请访问
            if attachment.url.startAccessingSecurityScopedResource()
            {
                eventImage.image = UIImage(contentsOfFile: attachment.url.path!)
                // 用完了需要关闭
                attachment.url.stopAccessingSecurityScopedResource()
            }
        }
    }
}

通过通知我们可以与用户互动,用户点击了不同的选项,我们可以有不同的行为,例如接受或者拒绝

class NotificationViewController: UIViewController, UNNotificationContentExtension
{
    func didReceive(_ response: UNNotificationResponse, completionHandler done: (UNNotificationContentExtensionResponseOption) -> Void) {

        server.postEventResponse(response.actionIdentifier) 
        { 
            if response.actionIdentifier == "accept"
            {
                eventResponse.text = "Going!" 
                eventResponse.textColor = UIColor.green() 
            }
            else if  response.actionIdentifier == "decline" 
            {
                eventResponse.text = "Not going :(" 
                eventResponse.textColor = UIColor.red()
            }
            done(.dismiss)
        }
    }
}

同时也允许用户进行输入操作,同时还增加了PlaceHolder

    private func makeEventExtensionCategory() -> UNNotificationCategory {

        let commentAction = UNTextInputNotificationAction( identifier: "comment",
                                                                title: "Comment",
                                                              options: [],
                                                 textInputButtonTitle: "Send", 
                                                 textInputPlaceholder: "Type here…")

        return UNNotificationCategory(identifier: "event-invite",
                                         actions: [ acceptAction, declineAction, commentAction ], 
                                  minimalActions: [ acceptAction, declineAction ], 
                               intentIdentifiers: [], 
                                         options: [])
}

    //  点击后
    class NotificationViewController: UIViewController, UNNotificationContentExtension {
    
    func didReceive(_ response: UNNotificationResponse, completionHandler done: (UNNotificationContentExtensionResponseOption) -> Void) {

        if let textResponse = response as? UNTextInputNotificationResponse
        {
            server.send(textResponse.userText) 
            {
                done(.dismiss)
            }
        }
    }
}

还可以自定义inputView

    class NotificationViewController: UIViewController, UNNotificationContentExtension 
    
    // 判断能否成为第一响应者
    override func canBecomeFirstResponder() -> Bool { 
        
        return true 
    }
    
    // 重写inputView
    override var inputAccessoryView: UIView {
         get { 
            return inputView 
         } 
    }

    func didReceive(_ response: UNNotificationResponse, completionHandler done: (UNNotificationContentExtensionResponseOption) -> Void) {

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

推荐阅读更多精彩内容