自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iOS 端容器之 WKWebView 那些事

網(wǎng)絡(luò)
熟悉 iOS\macOS Hybrid 混合開發(fā)的同學(xué)應(yīng)該都有體會(huì),WKWebView 雖然是蘋果作為替代 UIWebView\WebView 而推出的"新"組件,但大部分開發(fā)者對(duì)它實(shí)在“愛不起來”。畢竟對(duì)于國內(nèi)大部分應(yīng)用開發(fā)者來說,在實(shí)際使用中 WKWebView 所謂的“優(yōu)勢(shì)”未必能體現(xiàn)出來,但帶來的“坑”卻都著實(shí)都不淺。

 [[413463]]

一 背景

熟悉 iOS\macOS Hybrid 混合開發(fā)的同學(xué)應(yīng)該都有體會(huì),WKWebView 雖然是蘋果作為替代 UIWebView\WebView 而推出的"新"組件,但大部分開發(fā)者對(duì)它實(shí)在“愛不起來”。畢竟對(duì)于國內(nèi)大部分應(yīng)用開發(fā)者來說,在實(shí)際使用中 WKWebView 所謂的“優(yōu)勢(shì)”未必能體現(xiàn)出來,但帶來的“坑”卻都著實(shí)都不淺。

目前社區(qū)或線上可查找的 WKWebView 相關(guān)資料,大多比較陳舊且人云亦云、復(fù)制粘貼類的居多。少部分真實(shí)實(shí)踐和探索的開發(fā)者,或許也因時(shí)間或精力的原因,對(duì)問題和解決方案未能做詳細(xì)的闡述。導(dǎo)致目前線上 WKWebView 相關(guān)的資料數(shù)量不少、但質(zhì)量不高;且有不少文章存在對(duì)問題的背景解釋不清,解決方案缺乏有效驗(yàn)證等問題。

我從事端容器領(lǐng)域開發(fā)多年,曾在生產(chǎn)環(huán)境方案設(shè)計(jì)上與 WKWebView "對(duì)抗"多次。目前混合開發(fā)已經(jīng)是現(xiàn)代 App 標(biāo)配,一方面是對(duì)這么長時(shí)間用法經(jīng)驗(yàn)上的總結(jié),另外一方面也希望能夠?yàn)檫€在抗?fàn)幹械耐瑢W(xué)提供一些新視角或者解決思路,故準(zhǔn)備結(jié)合 WebKit 部分源碼,將自己對(duì)這個(gè)組件的理解以及部分問題解決方案整理分享一下。本文嘗試說明 3 件事情:

WKWebView 使用中的典型問題有哪些

為什么會(huì)出現(xiàn)這些問題

這些問題的解決辦法有哪些

二 基礎(chǔ)回顧

iOS 端網(wǎng)絡(luò)設(shè)計(jì)和 WKWebView 設(shè)計(jì)特點(diǎn)我們可以通過官方資料來查閱。但為了后面更好的說明問題,下面我們重點(diǎn)回顧下與文章后續(xù)內(nèi)容相關(guān)的兩個(gè)基本知識(shí)點(diǎn):

iOS 端網(wǎng)絡(luò)設(shè)計(jì)與 Cookie 管理

WKWebView 多進(jìn)程模型

1 iOS 網(wǎng)絡(luò)設(shè)計(jì)與 Cookie 管理

Cookie 管理是做混合開發(fā)過程中經(jīng)常會(huì)涉及到的部分,在應(yīng)用開發(fā)中我們知道可以通過 NSHTTPCookie 和NSHTTPCookieStorage 來管理應(yīng)用的 Cookie。但在系統(tǒng)層面 Cookie 是如何管理的、如何與網(wǎng)絡(luò)層各模塊進(jìn)行聯(lián)動(dòng),這對(duì)我們后面分析WKWebView 中的 Cookie 問題有著至關(guān)重要的聯(lián)系。

根據(jù)官方資料,我們可知 iOS 平臺(tái)下網(wǎng)絡(luò)相關(guān)模塊大概關(guān)系如下:

從上至下模塊依次為:

WebKit:應(yīng)用層,客戶端 App 以及 WKWebView 處于這一層。
NSURL:可以理解為對(duì)底層 CF 接口的封裝擴(kuò)展層,NSURLConnection、NSURLSession 等處于這一層。
CFNetwork:iOS 網(wǎng)絡(luò)模塊核心實(shí)現(xiàn)層,是網(wǎng)絡(luò)層設(shè)計(jì)中最重要的部分。負(fù)責(zé)網(wǎng)絡(luò)協(xié)議組裝發(fā)送接收等主要工作,與 CoreFoundation 框架關(guān)系緊密。
BSD socket:基于底層硬件接口的 socket 服務(wù)。
CFNetwork 是整個(gè)網(wǎng)絡(luò)系統(tǒng)的核心模塊,負(fù)責(zé)組裝請(qǐng)求、處理響應(yīng)等:

核心內(nèi)容包含:

CFURLRequest:包括 URL/header/body 這些請(qǐng)求的信息。CFURLRequest 會(huì)進(jìn)一步轉(zhuǎn)換成 CFHTTPMessage。
CFHTTPMessage:主要是 HTTP 協(xié)議的定義和轉(zhuǎn)換,把每一個(gè)請(qǐng)求 request 轉(zhuǎn)換成標(biāo)準(zhǔn)的 HTTP 格式的文本。
CFURLConnection:主要是處理請(qǐng)求任務(wù)。包括 pthread 線程、CFRunloop、請(qǐng)求隊(duì)列的管理等等。提供了start、cancel 等等操作的 API。
CFHost:負(fù)責(zé) DNS,有 CFHostStartInfoResolution 等函數(shù),基于 dns_async_start 和 getaddrinfo_async_start 等方法。
CFURLCache/CFURLCredential/CFHTTPCookie:處理 緩存/證書/cookie 相關(guān)的邏輯,都有對(duì)應(yīng)的NS類。
從上面分析可知關(guān)鍵信息:iOS Cookie 管理相關(guān)模塊處于 CFNetwork 這一層中。即對(duì)于請(qǐng)求 Response 中的 "set-cookie" 字段,在 CFNetwork 中被消費(fèi)和處理。

2 WKWebView 多進(jìn)程模型

通過官方資料,我們知道 WKWebView 相比 UIWebView 很大的一個(gè)變化是"多進(jìn)程模型":

WKWebView 在運(yùn)行時(shí),核心模塊運(yùn)行在獨(dú)立進(jìn)程中,與 App 進(jìn)程獨(dú)立。

WKWebView 使各種問題的原因,有不少和多進(jìn)程運(yùn)行模式有很大的關(guān)系。

多進(jìn)程模型詳解

但具體是什么樣形態(tài)的多進(jìn)程?我們通過一張簡圖來說明下:

WKWebView(WebKit) 包含 3 種進(jìn)程:UI Process, Networking Process, WebContent Process。
UI Process:即 App 進(jìn)程,WKWebView(WebKit) 中部分模塊運(yùn)行在此進(jìn)程,會(huì)負(fù)責(zé)啟動(dòng)其它進(jìn)程。
Networking Process:即網(wǎng)絡(luò)模塊進(jìn)程,主要負(fù)責(zé) WKWebView 中網(wǎng)絡(luò)請(qǐng)求相關(guān)功能;此進(jìn)程 App 中只會(huì)有啟動(dòng)一次,多個(gè) WKWebView 間共享。
WebContent Process:即 Web 模塊進(jìn)程,主要負(fù)責(zé) WebCore, JSCore 相關(guān)模塊的運(yùn)行,是 WKWebView 的核心進(jìn)程。此進(jìn)程在 App 中會(huì)啟動(dòng)多次,每個(gè) WKWebView 會(huì)有自己獨(dú)立的 WebContent 進(jìn)程。
各個(gè)進(jìn)程之間通過 CoreIPC 進(jìn)程通信。
總的來說:在一個(gè)客戶端 App 中,多個(gè) WKWebView 使用中會(huì)共享一個(gè) UI 進(jìn)程(與 App 進(jìn)程共享)、共享一個(gè) Networking 進(jìn)程、每個(gè) WKWebView 實(shí)例獨(dú)享一個(gè) WebContent 進(jìn)程。

示例:

此處關(guān)于 WebContent Process 和 Networking Process 的啟動(dòng)規(guī)則,官方文檔并未解釋特別清楚,且因?yàn)榘姹镜仍?,文檔與目前最新規(guī)則也略有出入。為避免混淆與歧義,下面結(jié)合 WebKit 源碼稍作分析。

WebContent 進(jìn)程啟動(dòng)規(guī)則

根據(jù)官方文檔描述:

A WKProcessPool object represents a single process that WebKit uses to manage web content. To provide a more secure and stable experience, WebKit renders the content of web views in separate processes, rather than in your app’s process space. By default, WebKit gives each web view its own process space until it reaches an implementation-defined process limit. After that, web views with the same WKProcessPool object share the same web content process.

規(guī)則是優(yōu)先使用創(chuàng)建新進(jìn)程,當(dāng)進(jìn)程上線超過某閾值之后則會(huì)共享,在 WebKit 內(nèi)部由 maximumProcessCount 控制。但是此規(guī)則只對(duì) iOS13 之前的系統(tǒng)生效,iOS13 之后的系統(tǒng),WKWebView 每次創(chuàng)建實(shí)例都會(huì)啟動(dòng)一個(gè)新的 WebContent Porcess。相關(guān)實(shí)現(xiàn)如下。

iOS13 前:

iOS 13 及以后:

Networking 進(jìn)程啟動(dòng)規(guī)則

Networking 規(guī)則相對(duì)簡單,確保在 App 生命周期內(nèi)啟動(dòng)一例(Crash 之后會(huì)重新創(chuàng)建)。相關(guān)代碼:

三 主要問題與解決方案

WKWebView 在生產(chǎn)環(huán)境使用中,除去相對(duì)簡單的使用和適配問題外,容易對(duì)開發(fā)者和前端同學(xué)造成困擾的問題有 4 個(gè):

請(qǐng)求代理問題
Cookie 管理問題
全面屏適配問題
WebContent 進(jìn)程崩潰問題
下面分別對(duì)這 4 例問題產(chǎn)生的原因、可嘗試的解決方案以及不同方案下引入的問題做一下說明。

1 請(qǐng)求代理問題

這一點(diǎn)應(yīng)該是阻礙 WKWebView 鋪開的首要問題。問題背景也相對(duì)簡單,并非有什么技術(shù)實(shí)現(xiàn)上的難度,而是蘋果官方不希望 WKWebView 請(qǐng)求被應(yīng)用攔截,美其名曰"為了安全"。但在實(shí)際使用場(chǎng)景中,我們又需要對(duì) WebView 的請(qǐng)求進(jìn)行代理以滿足業(yè)務(wù)和性能訴求,典型場(chǎng)景如:離線包、流量監(jiān)控等。

官方不支持、業(yè)務(wù)上又有使用場(chǎng)景,我們只能嘗試通過"黑魔法"來解決。目前適用面比較多的解決方案有兩個(gè):

通過 [WKBrowsingContextController registerSchemeForCustomProtocol:] 來注冊(cè)代理,為方便簡稱為代理方案1。
通過 [WKWebViewConfiguration setURLSchemeHandler:forURLScheme:] 來注冊(cè),為方便簡稱為代理方案 2。
目前兩種解決方案的實(shí)現(xiàn)方法都有較為豐富的資料和說明,在此不在贅述。

雖然這兩種方案某種程度上可以"部分解決問題",但帶來的副作用相對(duì)也不少,在生產(chǎn)環(huán)境中如何取舍還需具體開發(fā)同學(xué)來取舍。下面分別通過 "代理方案1" 和 "代理方案2" 代指來簡單說明下,可以供大家選型時(shí)做一個(gè)參考。

代理方案 1

此為最早出現(xiàn)的 WKWebView 請(qǐng)求代理方案,可滿足 iOS 9 及以后應(yīng)用使用(目前最新為 iOS 14)。根據(jù)之前調(diào)研分析,業(yè)界大部分有代理需求的 App 采用此方案或變種方案。

1)方案思路

通過 WKBrowsingContextController 將 http(s) 注冊(cè)到 Networking 的 m_registeredSchemes 數(shù)組中。對(duì)于數(shù)組中的 Scheme,WebKit 在發(fā)起請(qǐng)求時(shí)會(huì)通過 WKCustomProtocol 將請(qǐng)求發(fā)送到 App 所在的進(jìn)程,并由 App 進(jìn)程來執(zhí)行發(fā)送。

由于從 Networking 進(jìn)程將數(shù)據(jù)發(fā)送到 App 進(jìn)程時(shí),WebKit 內(nèi)有意剝離了 Body 部分(見 WebCoreArgumentCodersMac.mm):

故需要對(duì)攜帶 body 的請(qǐng)求做一些特殊處理。處理方案是通過在 WKWebView 內(nèi)注入腳本,重寫掉 WebView 內(nèi)請(qǐng)求發(fā)送相關(guān)方法。在請(qǐng)求發(fā)送之前將 body 部分序列化之后通過 bridge 傳遞到 App 進(jìn)程暫存。

App 進(jìn)程代理 WKWebView 請(qǐng)求時(shí),根據(jù)規(guī)則按需拼接緩存的 body,完成之后再進(jìn)行發(fā)送動(dòng)作。

2)方案弊端

此方案雖然適用面較廣,但是弊端也很明顯。主要有兩方面:

(1)問題一:無法定向處理、只能一刀切即如果 App 采用此方案,對(duì)其所有 WKWebView 實(shí)例的發(fā)送的請(qǐng)求都需要代理。如果有 WKWebView 實(shí)例中并未注入腳本或者執(zhí)行代理,則可能導(dǎo)致請(qǐng)求無法發(fā)送、發(fā)送缺少 body 等問題,常見于一些集成的二方庫、三方庫中的 WKWebView 實(shí)例。

(2)問題二:重寫腳本完備性很難保障由于需要在 JS 層重寫請(qǐng)求發(fā)送邏輯,比如 form 表單提交、AJAX、Fetch 等接口,重寫接口的質(zhì)量直接決定方案的完備度。且 WKWebView 原設(shè)計(jì)有不少能力在 c++ 層面實(shí)現(xiàn),僅在 JS 重寫無法保證對(duì)齊。目前已知的問題有:

對(duì)于同步請(qǐng)求,此方案目前無法支持。
對(duì)于流式請(qǐng)求,比如上傳場(chǎng)景,目前支持度較差。只能在 JS 側(cè)全量讀取之后再進(jìn)行發(fā)送。
無法處理 Fetch API Stream 返回值。
當(dāng)使用 Form 表單提交內(nèi)容包含大塊數(shù)據(jù)時(shí),可能出現(xiàn)丟失、Crash 等情況。

代理方案 2

此方案是基于蘋果在 iOS 11 上開放的 [WKWebViewConfiguration setURLSchemeHandler:forURLScheme:] 接口做"擴(kuò)展"來實(shí)現(xiàn)。對(duì)于 iOS 11.3 以后的設(shè)備,此方案具備較好實(shí)用性(WebKit 處理了部分 Body 傳遞問題)。

1)方案思路

[WKWebViewConfiguration setURLSchemeHandler:forURLScheme:] 可以在 WKWebView 實(shí)例上注冊(cè)自定義請(qǐng)求 Scheme。如果 WKWebView 發(fā)送的請(qǐng)求匹配注冊(cè) Scheme,則會(huì)代理到 UI 進(jìn)程(App 進(jìn)程) 執(zhí)行發(fā)送動(dòng)作。
WKWebView 內(nèi)部默認(rèn)不支持注冊(cè) http(s) 等標(biāo)準(zhǔn) Scheme,但是有"黑魔法"可繞過限制。
對(duì)于 AJAX 發(fā)送 BLOB 數(shù)據(jù)時(shí),也會(huì)出現(xiàn) body 丟失的情況,可以參考 代理方案1 中類似的方案來解決。
2)方案優(yōu)勢(shì)

代理方案 2 相對(duì)方案 1 兩個(gè)巨大的優(yōu)勢(shì)在于:

不用一刀切,配置與 WKWebView 實(shí)例綁定:即可以定向處理我們需要處理的 WKWebView 實(shí)例,對(duì)于 三方庫 中的對(duì)象,完全可以做到無影響,安全性大大提高。
不用重寫所有發(fā)送請(qǐng)求:大部分情況下請(qǐng)求中的 body 是可以被攜帶到 App 進(jìn)程,即我們只需定向處理部分異常即可,健壯性大大提升。
3)方案弊端

此方案除去有 iOS 11.3 的系統(tǒng)版本限制外,在具體運(yùn)行中也有也有不少很難處理的問題,主要如下:

(1)問題一:多圖分片下載情況下,WKWebView 內(nèi)部存在處理時(shí)序存在 BUG

問題表現(xiàn):在 WKWebView 中加載大圖、且大圖數(shù)據(jù)存在存在分片返回時(shí),WKWebView 內(nèi)部時(shí)序處理異??赡軐?dǎo)致 圖片無法展示、圖片展示不完整等問題。具體可結(jié)合 WebKit 中對(duì)圖片加載的流程來簡單說明下:

問題即出現(xiàn)在上述 step1, step2, step3 的執(zhí)行順序上。在異常情況下,會(huì)偶現(xiàn)執(zhí)行順序?yàn)椋簊tep1 -> step3 -> step2, 且 step3 不再被觸發(fā)(allDataReceived),進(jìn)而導(dǎo)致圖片最終的內(nèi)容未渲染上屏。

解決方案:目前暫無有效的解決辦法,通過配置 suppressesIncrementalRendering 配置為 YES 某種程度上可以緩解問題,但并無法根治且對(duì)體驗(yàn)略有影響。

(2)問題二:iOS 12及以下系統(tǒng)系統(tǒng)同步 AJAX 導(dǎo)致 Crash

問題表現(xiàn):在 WKWebView 中如果出現(xiàn) Web 頁面發(fā)送 sync request,則可導(dǎo)致 WebContent 進(jìn)程崩潰,WKWebView 回調(diào) webViewWebContentProcessDidTerminate,進(jìn)而導(dǎo)致頁面白屏等問題。此問題可明確是 WebKit 內(nèi)部的 BUG,且已有相關(guān) Fix:

Bug1: WebURLSchemeHandlerProxy::loadSynchronously crash with sync request(2018-08-06 14:14 ):https://bugs.webkit.org/show_bug.cgi?id=188358

 

Bug2: WKURLSchemeHandler crashes when sent errors with sync XHR(2019-06-20 01:20):https://bugs.webkit.org/show_bug.cgi?id=199063

處理方案:對(duì)于 Bug1,處理相對(duì)比較簡答,即在網(wǎng)絡(luò)請(qǐng)求回調(diào) error 之前優(yōu)先回調(diào)部分空數(shù)據(jù),規(guī)避掉問題;但是對(duì)于 Bug2,目前缺少有效的解決辦法。

(3)問題三:301 請(qǐng)求下 SWAP 導(dǎo)致頁面無法轉(zhuǎn)場(chǎng)問題

問題表現(xiàn):如果頁面中存在使用 301 做重定向的情況,可能會(huì)出現(xiàn)重定向頁面無法加載的情況,進(jìn)而導(dǎo)致頁面異常、白屏等問題。

處理方案:關(guān)閉 processSwapsOnNavigation,將置為 NO(內(nèi)部屬性)。

總的來說,雖然代理方案 2 相比代理方案 1 有很大的優(yōu)勢(shì),但此方案因?yàn)榘姹鞠拗频仍?,目前使用量相比代理方?1 略低。且與代理方案 1 相比,此方案的優(yōu)勢(shì)和劣勢(shì)都很明顯,如多圖分片場(chǎng)景下可能導(dǎo)致圖片無法展示的問題,目前未找到有效的解決辦法。方案 2 是否可替代方案 1 在生產(chǎn)環(huán)境使用,還需使用同學(xué)自己斟酌。

2 Cookie 問題

根據(jù)官方文檔及資料,我們可知 WKWebView 因?yàn)槠?quot;獨(dú)立存儲(chǔ)",導(dǎo)致 Cookie 和 Cache 與 App 不互通,進(jìn)而有問題。但是這種表述較為模糊,且實(shí)際使用中 WKWebView 與 App 的 Cookie 并非完全隔離,這種模棱兩可的表現(xiàn)很難讓人搞清楚"通"或"不通"的邊界在哪里。

下面首先根據(jù)自己對(duì)這塊的理解,嘗試說明下 WKWebView 使用 Cookie 問題到底是什么、以及背后的原因。由于蘋果并未對(duì)全部代碼開源,下有不少內(nèi)容是自己的理解和推斷,無法保證完全正確,僅介紹部分思路和判斷,供大家在需要時(shí)參考。

Cookie 管理策略

根據(jù)上節(jié)的背景介紹我們可知,iOS Cookie 相關(guān)內(nèi)容,是在 CFNetwork 這一層由 CFHTTPCookie、CFHTTPCookieStorage 等來管理,是 CFNetwork 模塊的一部分。且對(duì)于 Session Cookie 和 持久化 Cookie,系統(tǒng)有著不同的管理策略:

Session Cookie:內(nèi)存中保存,進(jìn)程周期內(nèi)生效。在 iOS 移動(dòng)端,一個(gè) App 進(jìn)程 即對(duì)應(yīng)于一個(gè) Session,即 Session Cookie 可在進(jìn)程內(nèi)共享。
持久化 Cookie:這部分 Cookie 除保存內(nèi)存以外,還會(huì)持久化到磁盤,可多次使用。本地文件存儲(chǔ)在 沙箱文件夾/Library/Cookies/Cookies.binarycookies;需要特別注意的是:持久化 Cookie 并非在產(chǎn)生之后立即同步到 Cookies.binarycookies,根據(jù)經(jīng)驗(yàn)會(huì)有一個(gè) 300ms ~ 3s 的延遲。

WKWebView Cookie 問題

基于上節(jié)的 iOS Cookie 管理、結(jié)合多進(jìn)程模型,我們大概可以推斷 App 與 WKWebView Cookie 管理模型,見如下簡圖:

注意:WKHTTPCookieStore 為示意,畫到了 Networking 進(jìn)程,實(shí)際情況中此模塊分散在 WebContent、Networking 以及 UI Process 中,且各進(jìn)程中的部分通過 IPC 橋接。

根據(jù)上圖可以引導(dǎo)出 WKWebView Cookie 相關(guān)的 2 個(gè)核心點(diǎn):

1)WKWebView Cookie 問題具體是什么

對(duì)于 "Session Cookie":App 進(jìn)程與 WKWebView 進(jìn)程(WebContent + Networking)之間 完全隔離。
對(duì)于 "持久化 Cookie":App 進(jìn)程與 WKWebView 進(jìn)程(WebContent + Networking)之間 同步存在時(shí)差。
2)造成 WKWebView Cookie 問題的根本原因

App 進(jìn)程 與 Networking 雙進(jìn)程的設(shè)計(jì)。

核心目標(biāo)

在了解 WKWebView 問題以及對(duì)應(yīng)的根本原因之后,如何來處理此問題相對(duì)也清晰了:根據(jù)是否采用代理了 WKWebView 的網(wǎng)絡(luò)請(qǐng)求,我們需要不同的處理策略。

場(chǎng)景 1 - 未代理 WKWebView 網(wǎng)絡(luò)請(qǐng)求:Cookie 完全由 Networking 進(jìn)程管理,WKWebView 內(nèi)可自閉環(huán)。大部分情況下 App 進(jìn)程也無需感知,如果確實(shí)需要感知,可以根據(jù)業(yè)務(wù)場(chǎng)景選擇 JS 橋接、強(qiáng)制持久化等方案。
場(chǎng)景 2 - 已代理 WKWebView 網(wǎng)絡(luò)請(qǐng)求:Cookie 大部分是由 App 進(jìn)程來管理,此時(shí)應(yīng)該采用何種同步策略。
由于場(chǎng)景 1 中我們并未在生產(chǎn)環(huán)境中采用,故本文不打算做冒然分析。下面主要聚焦于場(chǎng)景 2 來做進(jìn)一部分分析。在場(chǎng)景 2 下我們的核心目標(biāo):

對(duì)于 App 進(jìn)程中產(chǎn)生的 Cookie,能夠及時(shí)同步到 Networking 進(jìn)程:主要解決 Reponse 中存在 "Set-Cookie" 情況下,JS 端如何及時(shí)讀取相關(guān) Cookie 的問題。
對(duì)于 WebContent 中由 JS 產(chǎn)生的 Cookie,能及時(shí)同步到 App 進(jìn)程:主要解決在 JS 端產(chǎn)生 Cookie 之后,我們?nèi)绾伪WC在后續(xù)代理的網(wǎng)絡(luò)請(qǐng)求中可被正常攜帶的問題。

同步手段

在確認(rèn)方案之前,我們首先要搞清楚一個(gè)問題:客戶端側(cè) Cookie 來源有哪些?

對(duì)于 App 進(jìn)程,Cookie 來源有兩個(gè):

通過 NSHTTPCookieStorage 寫入的。
在網(wǎng)絡(luò)請(qǐng)求 Response Header 中通過 "Set-Cookie" 寫入的。
對(duì)于 WebContent 進(jìn)程,主要是 JS 通過 document.cookie 寫入的(網(wǎng)絡(luò)代理之后 Set-Cookie 不會(huì)在 WKWebView 進(jìn)程中生效)。

其次,我們要確認(rèn)可用做同步的手段有哪些:

對(duì)于 iOS 11 之后的系統(tǒng),蘋果已經(jīng)為我們提供了 WKHTTPCookieStore 對(duì)象用來讀寫、監(jiān)聽 WKWebView 對(duì)應(yīng)的 Cookie,可以直接使用。

對(duì)于 iOS 11 之前的系統(tǒng),需要區(qū)分處理一下。

從 App 進(jìn)程同步到 Networking 進(jìn)程,簡單流程如下:

第1步,需要把 Session Cookie 持久化,臨時(shí)保存(注意需要標(biāo)識(shí),以供恢復(fù))。
第2步,調(diào)用 NSHTTPCookieStorage 內(nèi)部接口 _saveCookies 觸發(fā)強(qiáng)制同步。
第3步,恢復(fù)臨時(shí)保存的 Session Cookie,避免污染。
由于 Networking 進(jìn)程不會(huì)產(chǎn)生 Cookie,所以我們下面要做的是從 WebContent 進(jìn)程同步 Cookie:處理策略即在 JS 側(cè)重寫 document.cookie 方法,在 JS 修改 cookies 時(shí),通過 bridge 將 cookie 傳遞到 App 進(jìn)程。

處理方案

在理清楚問題、目標(biāo)和可用手段之后,我們即可總結(jié)出 WKWebView Cookie 相關(guān)問題的處理方案:

對(duì)于 iOS 11 及之后的系統(tǒng),我們可以通過 HOOK NSHTTPCookieStorage 中讀寫 Cookie 的接口,并且監(jiān)聽網(wǎng)絡(luò)請(qǐng)求中 "Set-Cookie" 關(guān)鍵字,在 App 進(jìn)程 Cookie 發(fā)生變化時(shí)同步到 WKWebView;同時(shí)通過 WKHTTPCookieStore 提供 cookiesDidChangeInCookieStore 能力來監(jiān)聽 WKWebView 中 Cookie 的變化。
對(duì)于 iOS 11 之前的系統(tǒng),處理策略類似。但是我們需要過 NSHTTPCookieStorage 接口來做強(qiáng)制同步,并且需要注意恢復(fù) Cookie 的 SessionOnly 屬性;同時(shí)需要通過在 JS 側(cè)重寫 document.cookie 的方式,來感知 WKWebView 中 Cookie 的變化。
特別注意:

采用 iOS 11 之后方案處理時(shí)一定要注意,對(duì) WKHTTPCookieStore 的操作會(huì) 涉及到 IPC 通信,如果通信過于頻繁、通信數(shù)據(jù)量過大,會(huì)產(chǎn)生明顯的性能問題。極端情況可能造成 IPC 模塊異常,出現(xiàn)所有 WKWebView 都無法加載的情況。比如典型的場(chǎng)景,如果一個(gè)頁面請(qǐng)求較多、每個(gè)請(qǐng)求都帶"Set-Cookie"、且業(yè)務(wù)上為了簡單,每次把 App 進(jìn)程的 Cookie 全量同步到 WKWebView,則 Cookie 過多時(shí),有一定概率(暴力測(cè)試可復(fù)現(xiàn))觸發(fā) IPC 異常,導(dǎo)致后續(xù)所有 WKWebView 實(shí)例都無法正常加載,只有 App 殺進(jìn)程才可恢復(fù)。建議在同步 Cookie 時(shí),盡量按需同步變化的部分。

3 全面屏適配問題

全面屏適配問題相對(duì)不復(fù)雜,但因?yàn)?WKWebView 如 UIWebView 在表現(xiàn)上的不同,導(dǎo)致容易造成一些困擾。

問題是 UIWebView 與 WKWebView 在對(duì)前端 viewport-fit 支持表現(xiàn)上略有差別:UIWebView 對(duì) viewport-fit 支持度較好,表現(xiàn)基本與官方文檔表述一致。但是 WKWebView 中存在一個(gè)潛規(guī)則,如果 Web 頁面內(nèi) body 的高度,在沒有超出 WKWebView 組件實(shí)際高度時(shí),viewport-fit=cover 可能不生效。

處理辦法是在頁面中規(guī)避掉此類情況,如配置 body height 為 100vh (或其它類似方案)。

4 WebContent 進(jìn)程崩潰問題

這是一個(gè)出現(xiàn)概率不高,但是缺乏通用、有效解決辦法的問題。我們知道 WKWebView 多進(jìn)程模式下,如果 WebContent 進(jìn)程因?yàn)楦鞣N原因出現(xiàn) Crash,則 WKWebView 會(huì)通過 webViewWebContentProcessDidTerminate 回調(diào)告訴開發(fā)者,一般情況下我們會(huì)通過 reload 方法重新加載頁面。同時(shí)如果用戶設(shè)備內(nèi)存緊張,則可能出現(xiàn)系統(tǒng)主動(dòng) KILL WebContent 進(jìn)程的情況。即可能出現(xiàn) App 進(jìn)程(前臺(tái))正常,但是 WebContent 崩潰、頁面重新加載的情況。

絕大部分情況,進(jìn)入此流程并不一定會(huì)對(duì)用戶操作造成困擾。但是,如果此時(shí)造成內(nèi)存緊張是因?yàn)榍岸擞|發(fā)業(yè)務(wù)導(dǎo)致,典型如表單中喚起相機(jī)上傳圖片,此流程對(duì)用戶的影響可能是致命的。即使我們通過 WebView reload 使頁面恢復(fù),用戶在執(zhí)行的上傳動(dòng)作也會(huì)被打斷,導(dǎo)致提交流程出現(xiàn)異常、影響用戶的操作。且如果用戶設(shè)備進(jìn)入此狀態(tài),大部分情況下用戶再次操作還會(huì)觸發(fā)同樣的流程。

這種情況下,用戶無法及時(shí)感知到造成問題的根本原因,絕大多數(shù)直觀反應(yīng)即為:“App 出現(xiàn) bug 了!”故從用戶角度來看,缺少自動(dòng)恢復(fù)、處理問題的辦法。

目前此問題缺乏有效、統(tǒng)一解決辦法,一種解決思路是客戶端與前端配置,針對(duì)核心、可能出現(xiàn)異常的流程,定向設(shè)計(jì)解決方案。通過端側(cè)的能力來將數(shù)據(jù)持久化,在類似異常發(fā)生之后使用持久化數(shù)據(jù)恢復(fù)現(xiàn)場(chǎng),盡量在用戶無感的情況下保證用戶操作流程正常。

四 總結(jié)

以上便是我們?cè)诙巳萜髟O(shè)計(jì)開發(fā)過程中,WKWebView 使用上遇到的一些典型問題和對(duì)應(yīng)的解決辦法??偟膩碚f,目前造成這么不協(xié)調(diào)的狀態(tài),大部分是因?yàn)橄到y(tǒng)平臺(tái)未能充分考慮開發(fā)者訴求、組件設(shè)計(jì)對(duì)歷史業(yè)務(wù)兼容性不佳導(dǎo)致的。當(dāng)然,現(xiàn)在這種狀態(tài)必然也不是一種合理狀態(tài),未來無論是系統(tǒng)平臺(tái)方、還是業(yè)務(wù)方、或者是開發(fā)者,當(dāng)矛盾無法協(xié)調(diào)時(shí)總有一方要進(jìn)行妥協(xié)。在這個(gè)時(shí)間點(diǎn)來臨之前,希望上面總結(jié)內(nèi)容,能夠?yàn)槭艽祟悊栴}困擾的同學(xué)提供一些幫助。

 

責(zé)任編輯:梁菲 來源: 阿里云云棲號(hào)
相關(guān)推薦

2015-09-14 09:16:17

iOS統(tǒng)計(jì)打點(diǎn)

2019-12-10 08:00:46

Kata容器Linux

2022-10-26 09:57:52

VectorRustC++

2020-08-11 08:59:20

容器虛擬化技術(shù)

2017-01-10 13:33:51

iOS編程throttle

2011-05-19 16:47:50

軟件測(cè)試

2012-05-01 08:06:49

手機(jī)

2024-02-04 17:03:30

2017-05-15 21:50:54

Linux引號(hào)

2017-04-06 09:35:10

大數(shù)據(jù)SparkSQLSpark

2021-10-19 21:39:51

Unsafe構(gòu)造器內(nèi)存

2015-05-28 14:02:09

JavaJava日志性

2011-12-02 10:32:23

Java

2011-08-22 16:42:43

SqliteiPad

2014-06-06 16:08:17

初志科技

2020-09-23 09:07:16

特權(quán)賬號(hào)管理PAM網(wǎng)絡(luò)安全

2011-07-04 15:30:24

Qt 布局 GridLayout

2011-06-30 14:34:17

QT Tablewidge QTableWidg

2009-07-29 10:36:04

北電收購

2011-09-19 15:40:35

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)