这个Session介绍了Safari与WebKit的新特性,主要面向三类人群
- Web 网页开发者(是本篇主要面相对象)
- Use WKWebView 原生开发者
- Safari Extension 浏览器插件开发者
这个Session主要围绕着与浏览器技术相关的新特性与新功能,并且和大会的其他炙手可热的议题比如ARKit
,WatchOS
,都有相关和联动,极大地增强了Web技术的功能与性能。整个 Session 介绍的各种新功能相对来说比较琐碎,主要包括三大部分:
- 安全性与隐私保护
- 表现力与性能
- 丰富的交互体验
安全 Security
这一大块主要凸显苹果对安全以及用户隐私方面的重视,小到规范获取授权的提示,跨端的密码自动填充,大到网页上干扰广告商通过 cookie 定位跟踪用户,一种值得尊敬得企业态度。
UIWebView废弃,迁移WKWebView
在安全方面,Session上来就宣布了一件重量级的大事,UIWebView正式被官方宣布废弃,建议开发者迁移适配到WKWebView。在XCode9中UIWebView还是 NS_CLASS_AVAILABLE_IOS(2_0)
,而我们从最新的Xcode10再看UIWebView就已经是这个样子了
- UIKIT_EXTERN API_DEPRECATED("No longer supported; please adopt WKWebView.", ios(2.0, 12.0)) API_PROHIBITED(tvos, macos)
- @interface UIWebView : UIView <NSCoding, UIScrollViewDelegate>
- 复制代码
WKWebView从诞生之初相比UIWebView有太多的优势,无论是内存泄露还是网页性能,并且WKWebView可以同时支持macOS与iOS。由于WKWebView的独特设计,网页运行在独立的进程,如果网页遇到Crash,不会影响App的正常运行。
但是WKWebView不支持JSContext,不支持NSURLProtocol,Cookie管理蛋疼等问题确实给让不少开发者不想丢弃UIWebView,但最后通牒来了还是准备着手替换吧。
Safari扩展开发 Safari Extensions
safari扩展开发的历史
- 2010: 开放 macOS (Safari网页插件扩展) - Safari Extensions
- 2014: 开放 macOS 与 iOS 的 App Extensions 扩展开发 - App Extensibility for macOS and iOS
- 2015: 开放了 macOS 与 iOS 的 Safari 内容拦截能力(广告插件)- Content Blockers for macOS and iOS
- 2016: 开放了 macOS 的 Safari App Extensions 扩展开发 - Safari App Extensions for macOS
在macOS上,有一个Safari扩展的商店 Safari Extensions Gallery
,现在这个扩展商店也要退出历史舞台了,苹果希望开发者逐渐转移到 App Extensions 开发,最终提交到 AppStore
而不是开发Safari浏览器插件,提交到 Safari Extensions Gallery
,这个期限会持续到2018年底,之后 Gallery 就不再接受提交了。
子资源完整性校验 Subresource Integrity
早在很久之前,已经全面要求开发者适配HTTPS了,但如果开发者在个人网站上引用了存放在第三方平台的子资源,诸如 HTML/CSS/JS ,如果该资源在第三方平台出现了篡改等问题的发生,将导致我们的网站会遭受攻击
为了应对这种安全问题,Safari在新的版本里对HTML标签加入了一个新的属性 integrity
用来填写当前要引用的子资源的Hash值,如果该子资源下载完毕的时候发现Hash值和 integrity
属性不一致,则会直接放弃加载该资源,这个属性适用于一切子资源,JS/CSS等
- <script src="https://thirdparty.example/framework.js" integrity="sha384oqVuAfXRKa+R9GqQ8K/ux"></script>
- 复制代码
智能防追踪 Intelligent Tracking Prevention
在WWDC第一天的开场大会上,介绍到了在本届 WWDC,Apple 全面加强了用户隐私相关的保护,无论是用户设备指纹追踪,还是网络浏览行为追踪,表现出了,苹果非常在意保护用户的个人隐私。而在本场 Session 进一步介绍了如何智能的防止隐私追踪,Cookie 是这项技术的关键之一。
很多广告/搜索进行的用户行为追踪,导致用户刚搜过什么东西,在别处广告就能看到对应的商品推荐,主要靠的是创建一种唯一识别用户的 token,并将这 token 存入除了当前网站之外的第三方网站cookie,从而做到访问任意网站的时候能够追踪到用户在其他网站做过什么。
- 在去年的WWDC,苹果就宣布,Cookies 在24小时内之内可以被第三方上下文使用(用户可以被追踪),而过了24小时之后,Cookies 会被隔离存储,并且不提供给第三方上下文,30天候,Cookies 会被删除
- 今年这项举措进一步收紧,移除了24小时的宽限期,直接禁止第三方上下文使用 Cookies
那么问题来了?当用户确实需要跨网站之间同步登陆状态等用户信息怎么办?
Storage Access API
Apple 开放了专门用于存储读取这类用户敏感信息的 API,在使用这个 API 的时候会,苹果会向用户发起询问弹框,询问用户是否允许此类信息追踪,Storage Access API 的代码也很简单
- function makeRequestWithUserGesture() {
- let promise = document.requestStorageAccess();
- promise.then(function () {
- // Storage access was granted.
- // Check whether the user is logged in.
- // If not, do a popup to log the user
- // in.
- }, function () {
- // Storage access was denied.
- });
- }
- 复制代码
自动生成强密码 Automatic Strong Passwords
iOS12 会在用户需要创建一个用户名和密码的时候,自动生成一个强密码,包含了大小写,数字,特殊字符等等。并且这个强密码会被保存到用户的 KeyChain 之中,未来在访问当前网站的时候自动填充登陆,用户也可以在设置中查询已经生成的各个网站的密码,
对开发者来说,这个功能可以完全不做任何开发适配自动生效 Apple 默认的强密码规则,开发者也可以在自己的网站自定义强密码的规则
短信验证码自动填充 Security Code AutoFill
自动填充短信验证码,这个功能依然不需要开发者做任何适配自动填充,短信验证码会被填充到输入法里,快速录入到目标输入框
性能与展现 Performance
本届 WWDC 上来在介绍 iOS12 的时候就强调了软件性能,苹果做了巨大得努力,获得了巨大程度的提升。而在 Web 在浏览器上,一直被人诟病说表现力不如 Native ,性能流畅度不如 Native。而这一个大块内容就重点介绍了 Apple 是如何全面优化 web 的表现力与流畅度的。
字体集 Font Collections
Safari新增了一种可以将一些固定字符集的多种字体打包在一起,形成一个固定字符集的字体合集用来加载,此举可以大幅度减少多字体情况下的字体包下载大小,Session中提到的例子,使用了Font Collection,需要下载的所有字体体积下降了了84%
原理是多种字体在相同字符集下,可以共享同一个字符表,每一个字符的编码下对应存储多个字体的字形glyph,从而减少空间上的冗余。
CCS属性 font-display Descriptor
当一个网页使用了自定义字体,那么Safari会先用空白区域占位,然后去下载该字体,等下载完毕后在刷新出新的字体,如果这个过程 web 开发者想进一步的自己控制,就需要 font-display
这个 CSS 属性
font-display
是一个新的 CSS 属性,已经在 Chrome & Chrome for Android 率先得到了支持,这次 Safari 跟进了对这个属性的支持。
Session 中并没有讲太细致这个 CSS 到底该如何使用,目前有5种效果可以进行选择,样例中用的是 font-display: fallback;
此外还有 auto/swap/optional
- auto:默认值。使用自定义字体的文本会先被隐藏,直到字体加载结束后才会显示。
- swap:先用默认字体立即显示文字,直到自定义字体加载完成后再使用自定义字体渲染文本。
- fallback:这个可以说是auto和swap的一种折中方式。需要使用自定义字体渲染的文本会在较短的时间不可见,如果自定义字体还没有加载结束,那么就先加载无样式默认字体的文本。一旦自定义字体加载结束,那么文本就会被重新渲染。
- optional:效果和fallback几乎一样,都是先在极短的时间内文本不可见,然后再加载无样式的文本。不过optional选项可以让浏览器自由决定是否使用自定义字体,而这个决定很大程度上取决于浏览器的连接速度。如果速度很慢,那你的自定义字体可能就不会被使用。
Image标签中播放视频 Videos in image elements
网页中经常要播放动图,动画,我们一般都会使用 Gif 图,但 Gif 图加载时间太长了,因此开放了直接在 Image 标签中加载视频。并且 Safari 会使用内置的视频解码技术对视频进行最佳的渲染。
代码也非常简洁,无论是写一个HTML标签,还是写在CSS里,都支持
- //html 写法
- <img src="explosion.mp4" alt="Color Explosion">
- //CSS 写法
- body {
- background-image: url("explosion.mp4");
- }
- 复制代码
被动事件监听 Passive Event Listeners
这个 feture 大幅度优化了 Web 的滚动性能
在原本的 Safari 事件监听实现里,如果在滚动中触发了 addEventListener() 的事件监听,滚动会等待 JS 事件监听处理完毕,再继续滚动。
本次的被动事件监听优化,就是专门针对这种情况导致的可能的卡顿。被动监听作为一个标记位在 addEventListener() 的时候传入,当这个标记开启的时候,滚动不会等待 JS 事件监听执行完毕在继续,从而保证了流畅度。
异步图片解码 Async image decoding
新的 Web API 可以让JS自由的进一步控制DOM的异步图片解码,这里代码举个例子:页面中的一个图片,在点击的时候,加载下一张图片,然后淡淡地动画过度到新图片
- //读取要加载的新图片dom 和 新图片 src
- const img = this..currentItem.getElementsByTagName('img')[0];
- const unloadedSource = img.getAttribute('data-src');
-
- //新图片加载(会异步加载,不会卡主线程)
- if(unloadedSource){
- img.src = img.getAttribute('data-src');
- }
-
- //播放一个淡出动画,在老图片淡出,透出下面的新图片
- const transition = () =>{
- this.bringElementToFront(this.currentItem);
- this.currentItem.classList.add('fade-in');
- this.currentItem.onanimationend = () =>{
- this.currentItem.classList.remove('fade-in');
- };
- }
-
- transition()
- 复制代码
这段代码中最大的问题在于,当对 img.src 赋值的时候,web就开始异步加载图片了,但JS代码会立刻开始执行下面的动画效果,图片还没加载完,动画效果执行过程中出现了闪烁。
现在图片元素有了新API decode(),这个 decode() 会返回一个 promise ,当图片在异步下载解码完成后会触发。
- //读取要加载的新图片dom 和 新图片 src
- const img = this..currentItem.getElementsByTagName('img')[0];
- const unloadedSource = img.getAttribute('data-src');
-
- //新图片加载(会异步加载,不会卡主线程)
- if(unloadedSource){
- img.src = img.getAttribute('data-src');
- }
-
- //播放一个淡出动画,在老图片淡出,透出下面的新图片
- const transition = () =>{
- this.bringElementToFront(this.currentItem);
- this.currentItem.classList.add('fade-in');
- this.currentItem.onanimationend = () =>{
- this.currentItem.classList.remove('fade-in');
- };
- }
-
- //使用新 decode() Api 实现当解码完成的时候再执行动画效果
- img.decode().then(transition)
- 复制代码
支持 Beacon API
这个 Beacon API 可不是苹果他们家那个 iBeacon 设备与手机通信的东西哟!。
Beacon API 是 W3C 的一项新标准新 API,这个 API 主要用于发送不需要服务器回应的HTTP请求,Chrome && Firefox 似乎已经实现了,现在 Safari 跟进了这个功能。
这个API有什么用?
- 在空闲的时候发出异步请求,一般用于发送统计,并且因为不需要回应,完全不会影响页面诸如 JS/CSS Animation 的执行
- 即使在页面即将关闭
unload
状态下,也会异步发送出去统计,不影响过渡/跳转到下个页面
举个例子:当按钮点击,调往下一个页面的时候,我们希望发送一条数据请求给服务器,一般情况下浏览器发起请求都是发起异步的请求,但现在这个例子里,一旦发生跳转,当前页面即将销毁,这个网络请求会被浏览器忽略,为了保证数据发送成功,就得使用同步网络请求,就会导致页面先卡一会,请求完成后再跳转新页面。
- document.body.addEventListener('click',function(event){
- if(event.target.tagName == 'A'){
- const data = `from=${window.location.href}&to$(event.target.href)`;
-
- const xhr = new XMLHttpRequest();
- xhr.open('POST','/Event',false);//注意这里 false 表示这里强制同步网络请求,会卡
- xhr.send(data);
- }
- },true)
- 复制代码
有了不需要回应的 Beacon API,在这个例子里我们就可以不用让页面卡一下在跳转了,并且 sendBeacon() 这个 API 也比 XMLHttpRequest 简洁好多。
- document.body.addEventListener('click',function(event){
- if(event.target.tagName == 'A'){
- const data = `from=${window.location.href}&to$(event.target.href)`;
- //判断浏览器是否支持 Beacon API
- if (navigator.sendBeacon){
- navigator.sendBeacon('/event',data);
- }else{
- const xhr = new XMLHttpRequest();
- xhr.open('POST','/Event',false);
- xhr.send(data);
- }
- }
- },true)
- 复制代码
丰富的交互体验 Rich Experience
如果说安全与性能都是优化层面,那么这一大块内容就是彻彻底底的新功能了,更复杂的 Web 交互,Web 的移动支付,Web AR展现,甚至是 watch OS 上的 Web,让我们好好感受一下 Safari 的新能力
拖放交互 Drag and drop
新的 Safari 提供了拖拽 API,这个 API 也是 H5 的标准API,这次 Safari 跟进了支持。
- 通过 Dom 对象的 draggable 属性来开启拖拽效果
- 通过 dragstart/drop/dragover 事件监听来处理拖拽逻辑
- 通过 dataTransfer 来向事件对象 event 传递数据
下面看个简单的例子
- dragzone.forEach(function(element){
- element.addEventListener('dragstart',function(event){
- event.dataTransfer.setData('text/plain',element.textContent());
- });
- });
-
- dropzone.addEventListener('drop',function(event){
- event.preventDefault();
- const li = document.createElement('li');
- li.textContent = event.dataTransfer.getData('text/plain')
- goodList.appendChild(li);
- dropzone.classList.add('has-items');
- });
-
- 复制代码
苹果支付 Payment Request API + Apple Pay
恩,没错,苹果支付现在开放给 Web Safari 了,并且是遵循的 W3C 的标准 Payment Request API 从而对接到苹果支付上。
简单的例子:
- payButton.addEventListener('click',function(event){
- if (window.PaymentRequest){
- const method = {
- supportedMethods:"https://apple.com/apple-pay",
- data:{
- version:3,
- merchantIdentifier:"example,outdoorsy",
- merchantCapabilities: ['supports3DS','supportsCredit','supportsDebit'],
- countryCode:'US'
- }
- };
-
- const shoppingListItems = Array.from(shoppingList.children);
- const pricePerItem = 5.00;
-
- const details = {
- total:{
- label:"Outdoorsy",
- amount:{
- value:String(shoppingListItem.length * pricePerItem),
- currency:'USD'
- }
- },
- displayItems:shoppingListItems.map(function(item){
- return {
- label:item.textContent,
- pending:false,
- amount:{
- value:String(pricePerItem),
- currency:'USD'
- }
- }
- }),
- shippingOptions:[{
- id:'ground',
- label:'Ground Shipping',
- selected:true,
- amount:{
- value:'0.00',
- currency:'USD'
- }
- }]
- };
-
- const options = {
- requestPayerName:true,
- requestShipping:true
- }
-
- const paymentRequest = new PaymentRequest([method],details,options);
-
- paymentRequest.show().then((response) => {
- //do some thing
- //处理支付 response
- });
- }
- });
-
- 复制代码
离线网页 Service Worker
Service Worker 是当下炙手可热的渐进式网页技术 PWA ( Progressive Web App) 中的很重要的一环,赋予渐进式网页离线运行与更新的能力,本来由 Google 提出,苹果已经在 iOS 11.3 的版本进行了跟进和支持,关于 PWA 的内容可以搜到太多,这里就不详细讲了。
Service Worker 这种技术能带给网页离线访问的体验 Great offline experience,主要是通过向浏览器注册安装事件,从而引导内核在后台把网页所需要的 HTML/JS/CSS/IMG 等静态资源安装到本地,并且在网页生命周期之外,浏览器内核维持本地资源的更新频次,并且提供了请求拦截,凡是命中本地资源或数据的请求,都将优先返回本地缓存,不发起网络,从而做到离线使用
这里介绍一篇更详细介绍 Service Worker 的文章,(译)理解 Service Workers
iPad的全屏模式 Fullscreen API on iPad
之前 HTML 的全屏模式 API 在 iPad 是不支持的,现在可以正确的在 iPad 上生效了,并且提供了2个额外的 CSS 属性,来控制全屏模式下,关闭按钮的隐藏。
Safari下的AR AR Quick Look + Safari
本届 WWDC 重点介绍了 ARKit2.0 ,现在通过 Safari 也能够体验 AR了!
USDZ 是一种苹果ARKit的新模型格式,在 ARKit 的相关 Session 中有详细的介绍,现在 Safari 也能在浏览器中以 AR 的形式,展示这种模型了。现在已经升级 iOS12 的朋友可以直接用 Safari 打开下面的链接,你就可以立刻体验到浏览器中的 AR
代码非常简单,只需要写个 A 标签,加上一个属性 rel = 'ar' ,href指向 usdz 文件即可,感觉AR模型放置类的 APP 可以彻底被淘汰了,这么简短的3行 html 就能代替掉所有 AR 放置类 App。
- <a rel="ar" href="myfile.usdz">
- <img src="myimagefallback.jpg">
- </a>
- 复制代码
手表上的WebKit
现在 WebKit 已经被移植到 watchOS 上了,可以在手表上打开网页了
小结
总的来说这场 Session 主要还是为 web 开发者准备的,全面增强了 Safari 在各方面的能力。不过需要补充一点的是。好多新的功能都是 W3C 标准,JS API or CSS 属性之类的,我在文中都有提到,苹果在 Safari 中对这些标准进行了跟进与实现。其实,好多功能都是已经在 iOS 11.3 的版本中发布了的,只不过拿到了本次大会来一起进行说明。