-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
199 lines (138 loc) · 23.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hexo</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="Hexo">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Hexo">
<link rel="alternate" href="/atom.xml" title="Hexo" type="application/atom+xml">
<link rel="icon" href="/favicon.png">
<link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<div id="container">
<div id="wrap">
<header id="header">
<div id="banner"></div>
<div id="header-outer" class="outer">
<div id="header-title" class="inner">
<h1 id="logo-wrap">
<a href="/" id="logo">Hexo</a>
</h1>
</div>
<div id="header-inner" class="inner">
<nav id="main-nav">
<a id="main-nav-toggle" class="nav-icon"></a>
<a class="main-nav-link" href="/">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
</nav>
<nav id="sub-nav">
<a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
<a id="nav-search-btn" class="nav-icon" title="Search"></a>
</nav>
<div id="search-form-wrap">
<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
</div>
</div>
</div>
</header>
<div class="outer">
<section id="main">
<article id="post-iOS10 UserNotificaiton " class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2016/07/12/iOS10 UserNotificaiton /" class="article-date">
<time datetime="2016-07-12T07:44:29.000Z" itemprop="datePublished">2016-07-12</time>
</a>
</div>
<div class="article-inner">
<div class="article-entry" itemprop="articleBody">
<h1 id="iOS10-UserNotificaiton"><a href="#iOS10-UserNotificaiton" class="headerlink" title="iOS10 UserNotificaiton"></a>iOS10 UserNotificaiton</h1><p>Apple的推送通知在iOS10中有了更视觉化的更新。我们可以在通知中加入图片,视频,音频,甚至可以自定义内容的展示。还可以通过用户与通知的交互推测用户所感兴趣的推送内容。大部分功能来至于以下三个新的特性: <strong>Media Attachments</strong> ,<strong>Notificaiton Service Extensions</strong>,<strong>Notificaiotn Content Extensions</strong></p>
<h2 id="Media-Attachments"><a href="#Media-Attachments" class="headerlink" title="Media Attachments"></a>Media Attachments</h2><p>Media Attachment <a href="https://developer.apple.com/reference/usernotifications/unnotificationattachment" target="_blank" rel="external">UNNotificationAttachment</a> 是一个对象,包含附加媒体文件的 URL。支持的媒体文件类型包括常见的音频,视频和图片格式。Media attachment 在 iOS的10呈现的方式如下:<br><img src="http://7i7ht3.com1.z0.glb.clouddn.com/0.png" alt="MacDown"><br>就像一个消息警告,包含图像或视频附件的通知显示附件的缩略图。 看起来好不错,但真正神奇的是当你3D Touch 那通知时 :<br><img src="http://7i7ht3.com1.z0.glb.clouddn.com/1.png" alt="MacDown"></p>
<p>Medida Attachments 提升了用户在得到通知是的参与度。之前的通知只有寥寥几行文字信息,现在苹果推动的3D触控的预览风格下,可以为用户提过更丰富的内容而无需用户打开app,用户在与推送通知的交互中有了更多的选择。 </p>
<p>Media Attachment的工作方式在本地通知与很远程通知之间有些小小的不同。 当本地通时, media attachment 中必须包含磁盘中媒体附件的URL。远程通知时 ,消息都在APNS的推送载荷中,在只有4K的载荷中,只能在 payload的my-attachment 字段中指定我们需要处理的信息,可能是url 或者任何标识符<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line">{</div><div class="line">aps: {</div><div class="line">alert : {……}</div><div class="line">mutable-content : 1</div><div class="line">}</div><div class="line">my-attachment : https://example.com/phtos.jpg"</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>iOS 10 并不会自动的在通知中加入媒体附件。为解决这个问题,Notificaiton Service Extension 隆重出场了</p>
<h2 id="Notificaiton-Service-Extension"><a href="#Notificaiton-Service-Extension" class="headerlink" title="Notificaiton Service Extension"></a>Notificaiton Service Extension</h2><p><a href="https://developer.apple.com/reference/usernotifications/unnotificationserviceextension" target="_blank" rel="external">Notification Service Extension</a> 通过设置完上述的部分,推送就被推送到了每个设备的Service Extension那里了。在每个设备里面的Service Extension里面,就可以下载任意想要的attachment了。然后推送就会带着下载好的attachment推送到手机并显示出来了。 </p>
<p>如何来设置Service Extension呢?来看看如下WWDC中的示例代码:</p>
<figure class="highlight plain"><figcaption><span>Adding an attachment to a user notification</span></figcaption><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">public class NotificationService: UNNotificationServiceExtension {</div><div class="line">override public func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: (UNNotificationContent) -> Void)</div><div class="line">{</div><div class="line">let fileURL = // ...</div><div class="line">let attachment = UNNotificationAttachment(identifier: "image",</div><div class="line">url: fileURL,</div><div class="line">options: nil)</div><div class="line">let content = request.content.mutableCopy as! UNMutableNotificationContent</div><div class="line">content.attachments = [ attachment ]</div><div class="line">contentHandler(content)</div><div class="line">}</div><div class="line">}</div></pre></td></tr></table></figure>
<p>首先定义了一个didReceive的方法,用来接收request,后面跟着withContentHandler的回调函数。 </p>
<p>这个NotificationServiceExtension会在收到推送之后,被调用,然后在这个方法里面去下载自己的attachment。下载可以通过URL,或者任何你喜欢的方式。当下载完成之后,就可以创建attachment对象了。创建完UNMutableNotificationContent,我们就可以把这个加入到推送的content中了。最后,通过contentHandler回调,把它传递给iOS系统,iOS 系统就会展示给用户。<br><img src="http://7i7ht3.com1.z0.glb.clouddn.com/6.jpg" alt="MacDown"></p>
<p><strong>注意</strong> 在service extension里面去下载attachment,但是需要注意,service extension会限制下载的时间,并且下载的文件大小也会同样被限制<br>我们可以在func serviceExtensionTimeWillExpire()优雅的解time expire 的问题<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">override func serviceExtensionTimeWillExpire() {</div><div class="line">// Called just before the extension will be terminated by the system.</div><div class="line">// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.</div><div class="line">if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {</div><div class="line">contentHandler(bestAttemptContent)</div><div class="line">}</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h2 id="Notificaiton-Content-Extension"><a href="#Notificaiton-Content-Extension" class="headerlink" title="Notificaiton Content Extension"></a>Notificaiton Content Extension</h2><p><strong><a href="https://developer.apple.com/reference/usernotificationsui/unnotificationcontentextension" target="_blank" rel="external">Notification Content Extension</a></strong>类似于Notification Service Extension可以为通知提供新内容,与其不同的是content extionsion在本地和远程通知中都可以应用,content extsion 不仅仅是为了在提供通知中提供附加媒信息,更重要的是为了向用户展示自定义的通知内容展示界面。 </p>
<p>当添加一个扩展后,Xcode中生成一个新的storyboard文件,相应的源代码文件,以及为我们的内容扩展名“的info.plist”的文件。<br>Notification content extension允许开发者加入自定义的界面,在这个界面里面,你可以绘制任何你想要的东西。但是有一个最重要的限制就是,这个自定义的界面没有交互。它们不能接受点击事件,用户并不能点击它们。但是推送通知还是可以继续与用户进行交互,因为用户可以使用notificaiton的actions。extension可以处理这些actions。</p>
<p>接下来我们就来说说如何自定义界面 </p>
<p><strong>1. 推送的四部分</strong><br>先来看一个WWDC中介绍的日历推送例子:<br><img src="http://7i7ht3.com1.z0.glb.clouddn.com/7.jpg" alt="MacDown"></p>
<p>上图,整个推送分4段。用户可以通过点击Header里面的icon来打开app,点击取消来取消显示推送。Header的UI是系统提供的一套标准的UI。这套UI会提供给所有的推送通知。</p>
<p>Header下面是自定义内容,这里就是显示的Notification content extension。在这里,就可以显示任何你想绘制的内容了。你可以展示任何额外的有用的信息给用户。</p>
<p>content extension下面就是default content。这里是系统的界面。这里的系统界面就是上面推送里面payload里面附带的内容。这也就是iOS 9 之前的推送的样子。</p>
<p>最下面一段就是notification action了。在这一段,用户可以触发一些操作。并且这些操作还会相应的反映到上面的自定义的推送界面content extension中。</p>
<p><strong>2.创建Notification content extension</strong><br>接下来我们就来看看如何创建一个Notification content extension<br><img src="http://7i7ht3.com1.z0.glb.clouddn.com/10.jpg" alt="MacDown"><br>第一件事就是去创建一个新的target。创建好了之后,Xcode会自动帮我们生成一个template。template会在新的target里面生成3个文件,一个新的ViewController,main Interface storyboard,info.plist。info.plist中就是可以定义化一些target的配置。 </p>
<p>打开Notification content extension的ViewController</p>
<figure class="highlight plain"><figcaption><span>Minimal Content Extension</span></figcaption><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">class NotificationViewController: UIViewController, UNNotificationContentExtension {</div><div class="line">@IBOutlet var label: UILabel?</div><div class="line">override func viewDidLoad() {</div><div class="line">super.viewDidLoad()</div><div class="line">// Do any required interface initialization here.</div><div class="line">}</div><div class="line">func didReceive(_ notification: UNNotification) {</div><div class="line">label?.text = notification.request.content.body</div><div class="line">}</div><div class="line">}</div></pre></td></tr></table></figure>
<p>我们会发现,这个ViewController是UIViewController的子类,其实就是一个很普通的ViewController,和我们平时使用的没有啥两样。后面是UNNotificationContentExtension的protocol,这里是系统要求你必须实现的协议。</p>
<p>UNNotificationContentExtension只有一个required的方法,就是didReceive方法。当推送到达你的设备之后,这个didReceive方法会随着ViewController的生命周期的方法 ,一起被调用。当开发者给推送加上expands的时候,一旦推送送达以后,这时会接到所有的ViewController生命周期的方法,和didReceive方法。这样,我们就可以接收notification object ,接着更新UI</p>
<p><strong>3. 配置target</strong><br>接下来,我们需要做的是,告诉iOS系统,推送送达之后,iOS系统如何找到你自定义的Notification content extension。<img src="http://7i7ht3.com1.z0.glb.clouddn.com/11.png" alt="MacDown"><br>Notification content extension和我们注册notification actions一样,注册的相同的category。值得提到的一点是,这里的extension是可以为一个数组的,里面可以为多个category,这样做的目的是多个category共用同一套UI。<br>上图中,content0和 content1就共用了一套UI。这样我们就可以把他们打包到一个extension里面来。但是不同的category是独立的,他们可以相应不同的actions。通过以上设置,iOS系统就知道了我们的target了。<br>通过UNNotificationExtensionDefaultContentHidden设置默认的content是否隐藏。通过UNNotificationExtensionInitialContentSizeRatio定义CustomView的宽和高的比例 </p>
<p><strong>4. 自定义用户UI界面</strong></p>
<figure class="highlight plain"><figcaption><span>Notification Content Extension</span></figcaption><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">func didReceive(_ notification: UNNotification) {</div><div class="line">let content = notification.request.content</div><div class="line">titleLabel?.text = content.title</div><div class="line">subTitleLable.text = content.subtitle</div><div class="line">bobyLabel.text = content.body</div><div class="line">let info = content.userInfo["info"] // </div><div class="line">if let attachment = content.attachments.first {</div><div class="line">if attachment.url.startAccessingSecurityScopedResource() {</div><div class="line">imageView.image = UIImage(contentsOfFile: attachment.url.path!)</div><div class="line">attachment.url.stopAccessingSecurityScopedResource()</div><div class="line">}</div><div class="line">}</div><div class="line">}</div><div class="line">}</div></pre></td></tr></table></figure>
<p>上述代码中,我们在stroyboard 里面加入了一些labels 和 一个imageView 。当接收到推送的时候,我们提取出内容,得到我们想要的内容,然后把这些内容设置到label和imageView中。我们还可以在content的userinfo里面我们还能加入一些额外的信息,这些信息是标准的payload无法展示的。</p>
<figure class="highlight plain"><figcaption><span>Notification Content Extension Attachments</span></figcaption><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">class NotificationViewController: UIViewController, UNNotificationContentExtension {</div><div class="line">@IBOutlet var eventImage: UIImageView!</div><div class="line">func didReceive(_ notification: UNNotification) {</div><div class="line">let content = notification.request.content</div><div class="line">if let attachment = content.attachments.first {</div><div class="line">if attachment.url.startAccessingSecurityScopedResource() {</div><div class="line">eventImage.image = UIImage(contentsOfFile: attachment.url.path!)</div><div class="line">attachment.url.stopAccessingSecurityScopedResource()</div><div class="line">}</div><div class="line">}</div><div class="line">}</div><div class="line">}</div></pre></td></tr></table></figure>
<p>我们可以提取content的attachments。前文提到过,attachment是由系统管理的,系统会把它们单独的管理,这意味着它们存储在我们sandbox之外。所以这里我们要使用attachment之前,我们需要告诉iOS系统,我们需要使用它,并且在使用完毕之后告诉系统我们使用完毕了。对应上述代码就是startAccessingSecurityScopedResource()和stopAccessingSecurityScopedResource()的操作。当我们获取到了attachment的使用权之后,我们就可以使用那个文件获取我们想要的信息了。<br>上述例子中,我们从attachment中获取到图片,并展示到UIImageView中。于是notification就变成下面这个样子了。<br><img src="http://7i7ht3.com1.z0.glb.clouddn.com/12.png" alt="MacDown"><br><img src="http://7i7ht3.com1.z0.glb.clouddn.com/13.png" alt="MacDown"></p>
<h2 id="Customize-Actions"><a href="#Customize-Actions" class="headerlink" title="Customize Actions"></a>Customize Actions</h2><p>说道这里,我们不得不说一下iOS8开始引入的action的工作原理:</p>
<p>默认系统的Action的处理是,当用户点击的按钮,就把action传递给app,与此同时,推送通知会立即消失。这种做法很方便。</p>
<p>但是还有一种情况,当用户点击了按钮,希望接受一些日历上的邀请,我们需要把这个操作即时的展示在我们自定义的UI上,这是我们就只能用Notification content extension来处理这些用户点击事件了。这个时候,用户点击完按钮,我们把这个action直接传递给extension,而不是传递给app。当actions传递给extension时,它可以延迟推送通知的消失时间。在这段延迟的时间之内,我们就可以处理用户点击按钮的事件了,并且更新UI,一切都处理完成之后,我们再去让推送通知消失掉。</p>
<p>这里我们可以运用UNNotificationContentExtension协议的第二个方法,这方法是Optional。下面这是WWDC中的示例代码<br><figure class="highlight plain"><figcaption><span>Intercepting notification action response</span></figcaption><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">class NotificationViewController: UIViewController, UNNotificationContentExtension {</div><div class="line">func didReceive(_ response: UNNotificationResponse, completionHandler done: (UNNotificationContentExtensionResponseOption) -> Void) {</div><div class="line">server.postEventResponse(response.actionIdentifier) {</div><div class="line">if response.actionIdentifier == "accept" {</div><div class="line">eventResponse.text = "Going!"</div><div class="line">eventResponse.textColor = UIColor.green()</div><div class="line">} else if response.actionIdentifier == "decline" {</div><div class="line">eventResponse.text = "Not going :("</div><div class="line">eventResponse.textColor = UIColor.red()</div><div class="line">}</div><div class="line">done(.dismiss)</div><div class="line">}</div><div class="line">}</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>不用这个方法的时候就可以不声明出来。但是一旦声明了,那么你就需要在这个方法里面处理推送通知里面所有的actions。这就意味着你不能只处理一个action,而不管其他的action。 </p>
<p>这里值得一提的是,如果你还想把这个action传递给app,那么最后的参数应该是这样。<code>done(.dismissAndForwardAction)</code><br>参数设置成这样之后,用户的action就会再传递给app。</p>
<p><a href="https://github.com/oldMan80308006/UserNotification" target="_blank" rel="external">githubDemo</a></p>
<p><a href="https://developer.apple.com/videos/play/wwdc2016/708/" target="_blank" rel="external">Advanced Notifications</a><br><a href="https://developer.apple.com/videos/play/wwdc2016/707/" target="_blank" rel="external">Introduction to Notifications</a></p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2016/07/12/iOS10 UserNotificaiton /" data-id="ciqrgg4e0000076yddgtxnxom" class="article-share-link">Share</a>
</footer>
</div>
</article>
</section>
<aside id="sidebar">
<div class="widget-wrap">
<h3 class="widget-title">Archives</h3>
<div class="widget">
<ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/07/">July 2016</a></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Recent Posts</h3>
<div class="widget">
<ul>
<li>
<a href="/2016/07/12/iOS10 UserNotificaiton /">(no title)</a>
</li>
</ul>
</div>
</div>
</aside>
</div>
<footer id="footer">
<div class="outer">
<div id="footer-info" class="inner">
© 2016 John Doe<br>
Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
</div>
</div>
</footer>
</div>
<nav id="mobile-nav">
<a href="/" class="mobile-nav-link">Home</a>
<a href="/archives" class="mobile-nav-link">Archives</a>
</nav>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
<script src="/fancybox/jquery.fancybox.pack.js"></script>
<script src="/js/script.js"></script>
</div>
</body>
</html>