1. 程式人生 > 實用技巧 >WKWebView 新變化:發掘 WKWebView 的神奇妙用

WKWebView 新變化:發掘 WKWebView 的神奇妙用

作者:RyRYanZhong,iOS 開發,位元組跳動研發工程師

Sessions: https://developer.apple.com/videos/play/wwdc2020/10188/

導覽

  1. 更靈活的 JS 控制

  2. 解決 native 與 web 名稱空間衝突

  3. 更靈活的 JS 引數傳遞

  4. web 與 native 雙向通訊

  5. 更好的渲染方式

  6. 多個新 api

更靈活的 JS 控制

WKWebView 中, 使用javaScriptEnabled可以 disable 所有 webview 試圖去載入的 js 檔案, 但是因為 native 很多時候其實都需要通過 EvaluateJavaScript 來進行資料互動. 直接禁用javaScriptEnabled

實際上是非常粗粒度的行為. 因此這個屬性將會被拋棄 取而代之的新屬性allowsContentJavaScript, 使用這個屬性可以禁用內聯的 JS, url 方式載入的遠端 js, 以及本地路徑的 js 檔案, 但是 native 直接執行的 js 仍然有效 在 decidePolicy 代理方法中使用 WKWebpagePreferences, 更可以對每個 web 頁面進行更細緻的配置, 來決定當前 web 頁面是否載入 js 以下圖程式碼為例, 針對特定的 url, 將 allowContentJavaScript 設為 false, 可以使 web 頁面更為靈活, 例如在某些特定的頁面, 你只希望獲得 html 的佈局能力, 然後點選互動網路請求等細節交由 native 接管, 這樣可以使頁面載入更為迅速

解決 native 與 web 名稱空間衝突

如上圖所示, 例如 native 執行了 js 後將window.commentDetails設為 null, 這樣會導致 js 內的同名函式直接被置空, 這種 native 與 web 的名稱空間衝突問題非常難以察覺, 甚至有惡意的 web 應用會故意覆蓋同名函式來達到改變應用行為或者獲取使用者資訊的能力. 要徹底解決, 就需要將 native 的 js 執行環境跟 web 的 js 執行環境進行隔離, 因此 native 需要一個自己的global object,WKContentWorld就是為此而生的

如上圖所示, 使用方式是在 native 執行 js 的 api 裡, 加上.defaultClient

的引數

更靈活的 JS 引數傳遞

例如我們希望在 native 側構建一個完整的 dom 節點並插入到 html 時, 我們需要 hardcode 很多 js 中資料結構的程式碼

例如下圖中的maring: "0", 這裡的0在 native 的其他地方其實是Int型別, 但因為讓這段 js 程式碼能轉 string 從而讓 webview 呼叫, 因此需要 hardcore 成 "0"

為了解決這個問題, 蘋果引入了callAsyncJavaScriptapi

如上圖, 在執行這段 js 時, 這段 js 的 scope 內使用到的變數, 可以直接通過arguments這個引數進行傳遞, 並且可以直接使用 swift 的字典資料型別

上圖是一個更神奇的妙用

在這段 js 中 return 了一個 promise 物件, 因此 native 的 completion 會等待這個 promise 被 resolve 了, 才會執行, 並且可以在 native 獲取到 fetch 成功後的資料

web 與 native 雙向通訊

以上圖為例, 這是現有 api 下很常見的 js 和 native 的通訊方式, web 直接呼叫 webkit 中的postMessage來呼叫 native, 在現有的 webkit 框架下只能實現 web to native 的單向呼叫, 如果要雙向通訊, 則需要開發者在postMessage的基礎上構建自己的雙向通訊機制.

但在新的 WKWebView 中, 蘋果加強了 WebView 與 native 的通訊能力,postMessage在 js 的返回值是從undefine變成了promise物件

如上圖, 在 userContentController 收到 message 後, 可以新增一個 replyHandler 引數, 當你執行這個 replyHandler 時, js 對應的 promise 就會被 resolve

如上圖, 在 js 側就可以通過 promise 的形式獲取到這個 replyHandler 的入參並執行後續的邏輯

因此, 這套雙向通訊的機制很好地利用了 js 的 promise 非同步機制與 swift 的程式碼塊相結合, 比起開發者自己去構建雙向通訊機制, 會更為友好和完善

更好的渲染方式

在 css 中, 媒體查詢樣式可以使得同一份 css 程式碼在不同的平臺執行有不同的展示效果

例如上圖的頁面, 被標記的 header 和 footer 實際上在 iPhone 上並不希望展示, 因為更多的時候 app 有著自己本身的 header 和 footer, 這個與 web 的 header 和 footer 在 ui 上造成衝突

因此在寫 css 的時候, 我們可以通過媒體查詢這一特性, 使得 css 在no-header-and-footer-device裡自動隱藏這些 ui 元素

如上圖, 通過mediaType這個新的物件屬性, 就可以實現 css 媒體查詢的自適應

多個新 api

WebView 內容查詢

使用上圖的findapi, 可以使 WebView 直接選中並滾動到對應的區域

生成 PDF

使用上圖的createPDFapi, 可以截圖整個 WebView 的全部內容, 包括螢幕外的, 並作為 pdf 輸出

Archive Web Content

使用上圖的createWebArchiveDataapi, 可以為當前頁面的所有資料建立一個 snapshot, 包括整個頁面的 html, js, css 以便重新執行這個 ArchiveData 時, 可以重現當時 Web 頁面的所有內容, 因此也非常適用於 Debug

APP-bound domains

例如上圖的 web content 中, 出現了一個外部的 url, 我們希望使用者能在瀏覽器中跳轉到這個 url, 但同時我們不希望使用者在這個新的 web 頁面中, 資訊被洩露或者遇到其他安全問題, 按蘋果的描述, 使用 APP-bound domains 可以使得瀏覽器在指定 domain 以外的 web 應用中, 禁止它們與使用者有deep interaction, 不過具體沒有說明會禁止什麼行為 要使用這一能力, 我們需要在 info.plist 中增加自己的 domain 白名單

總結

今年的 WebKit 更新, 個人感覺蘋果升級了更多 js 與 native 的互動能力, 充分運用的話能使得我們的 hybrid 應用的程式碼有很好的簡化.

來源:烏蘭察布SEO