WWDC 2018:Safari與WebKit的新特性

折騰範兒_味精發表於2018-06-09

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

WWDC 2018:Safari與WebKit的新特性

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

WWDC 2018:Safari與WebKit的新特性

iOS12 會在使用者需要建立一個使用者名稱和密碼的時候,自動生成一個強密碼,包含了大小寫,數字,特殊字元等等。並且這個強密碼會被儲存到使用者的 KeyChain 之中,未來在訪問當前網站的時候自動填充登陸,使用者也可以在設定中查詢已經生成的各個網站的密碼,

對開發者來說,這個功能可以完全不做任何開發適配自動生效 Apple 預設的強密碼規則,開發者也可以在自己的網站自定義強密碼的規則

簡訊驗證碼自動填充 Security Code AutoFill

自動填充簡訊驗證碼,這個功能依然不需要開發者做任何適配自動填充,簡訊驗證碼會被填充到輸入法裡,快速錄入到目標輸入框

WWDC 2018:Safari與WebKit的新特性

效能與展現 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 的版本中釋出了的,只不過拿到了本次大會來一起進行說明。

相關文章