阅读 4002

WWDC 2018:Safari与WebKit的新特性

Session 234: What’s New in Safari and WebKit

这个Session介绍了Safari与WebKit的新特性,主要面向三类人群

  • Web 网页开发者(是本篇主要面相对象)
  • Use WKWebView 原生开发者
  • Safari Extension 浏览器插件开发者

这个Session主要围绕着与浏览器技术相关的新特性与新功能,并且和大会的其他炙手可热的议题比如ARKitWatchOS,都有相关和联动,极大地增强了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 ,如果该资源在第三方平台出现了篡改等问题的发生,将导致我们的网站会遭受攻击

subresuroucesha

为了应对这种安全问题,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
        });
    }
});

复制代码

webpay

离线网页 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

AR Quick Look Gallery

代码非常简单,只需要写个 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 上了,可以在手表上打开网页了

watchos

小结

总的来说这场 Session 主要还是为 web 开发者准备的,全面增强了 Safari 在各方面的能力。不过需要补充一点的是。好多新的功能都是 W3C 标准,JS API or CSS 属性之类的,我在文中都有提到,苹果在 Safari 中对这些标准进行了跟进与实现。其实,好多功能都是已经在 iOS 11.3 的版本中发布了的,只不过拿到了本次大会来一起进行说明。

关注下面的标签,发现更多相似文章
评论