CordVoa下WKWebView的UserAgent問(wèn)題

1.重構(gòu)項(xiàng)目 背景

cordVoa

WKWebView 替換UIWebView?

溝通的重要性

1.歷時(shí)8天的解決bug的坑逼日程

1.接到一個(gè)任務(wù),說(shuō)在WKWebView替換UIwebview過(guò)程中,decidePolicyForNavigationAction攔截url時(shí),URL有些內(nèi)容會(huì)丟失。比如abs:XX//a=1&b=2,正常情況是abs是可以攔截到的,但是WK加載相同的界面,a bs有時(shí)侯會(huì)加載出來(lái),有時(shí)候加載不出來(lái)。帶著問(wèn)題找答案,針對(duì)此類問(wèn)題百度一搜一大堆??戳藘扇?,基本上都是那個(gè)幾個(gè)問(wèn)題,畢竟大家都被坑的不欠你。比如說(shuō)一下這個(gè)問(wèn)題和我遇到的問(wèn)題相似:

(1)cookie問(wèn)題?

說(shuō)什么cookie 保存不下來(lái)之類的,我一想cookie是放在request.httpHeader里面的,是不是一起掉了,當(dāng)時(shí)有過(guò)一段懷疑,但是很快就排除掉了,怎么說(shuō)呢,cookie保存問(wèn)題,是個(gè)很普遍的問(wèn)題,如果我遇到的問(wèn)題和cookie一樣平常,那么我遇到的問(wèn)題簡(jiǎn)書(shū)里面應(yīng)該有體現(xiàn),但是我發(fā)現(xiàn)我遇到的問(wèn)題,簡(jiǎn)書(shū)里面我找不到,可能是我姿勢(shì)不正確把,沒(méi)找到問(wèn)題所在。

(2)WKWebView NSURLProtocol問(wèn)題

(1)正式從這個(gè)問(wèn)題,我走向了一條錯(cuò)誤的道路,簡(jiǎn)單來(lái)說(shuō)就是自定義Protocol,我們的協(xié)議不是在客戶端做的,而是H5根據(jù)UserAgent判斷加上的。

所以根本就沒(méi)有牽扯到NSURLProtocol 這個(gè)問(wèn)題。

WKWebView 在獨(dú)立于 app 進(jìn)程之外的進(jìn)程中執(zhí)行網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求數(shù)據(jù)不經(jīng)過(guò)主進(jìn)程,因此,在 WKWebView 上直接使用 NSURLProtocol 無(wú)法攔截請(qǐng)求。蘋果開(kāi)源的 webKit2 源碼暴露了私有API:

[WKBrowsingContextController registerSchemeForCustomProtocol:]

通過(guò)注冊(cè) http(s) scheme 后 WKWebView 將可以使用 NSURLProtocol 攔截 http(s) 請(qǐng)求:

Class cls = NSClassFromString(@"WKBrowsingContextController”);

SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");

if ([(id)cls respondsToSelector:sel]) {

// 注冊(cè)http(s) scheme, 把 http和https請(qǐng)求交給 NSURLProtocol處理

[(id)cls performSelector:sel withObject:@"http"];

[(id)cls performSelector:sel withObject:@"https"];

}

但是這種方案目前存在兩個(gè)嚴(yán)重缺陷:

a、post 請(qǐng)求 body 數(shù)據(jù)被清空

由于 WKWebView 在獨(dú)立進(jìn)程里執(zhí)行網(wǎng)絡(luò)請(qǐng)求。一旦注冊(cè) http(s) scheme 后,網(wǎng)絡(luò)請(qǐng)求將從 Network Process 發(fā)送到 App Process,這樣 NSURLProtocol 才能攔截網(wǎng)絡(luò)請(qǐng)求。在 webkit2 的設(shè)計(jì)里使用 MessageQueue 進(jìn)行進(jìn)程之間的通信,Network Process 會(huì)將請(qǐng)求 encode 成一個(gè) Message,然后通過(guò) IPC 發(fā)送給 App Process。出于性能的原因,encode 的時(shí)候 HTTPBody 和 HTTPBodyStream 這兩個(gè)字段被丟棄掉了

參考蘋果源碼:

https://github.com/WebKit/webkit/blob/fe39539b83d28751e86077b173abd5b7872ce3f9/Source/WebKit2/Shared/mac/WebCoreArgumentCodersMac.mm#L61-L88(復(fù)制鏈接到瀏覽器中打開(kāi))

及bug report:

https://bugs.webkit.org/show_bug.cgi?id=138169(復(fù)制鏈接到瀏覽器中打開(kāi))

因此,如果通過(guò) registerSchemeForCustomProtocol 注冊(cè)了 http(s) scheme, 那么由 WKWebView 發(fā)起的所有 http(s)請(qǐng)求都會(huì)通過(guò) IPC 傳給主進(jìn)程 NSURLProtocol 處理,導(dǎo)致 post 請(qǐng)求 body 被清空;

b、對(duì)ATS支持不足

測(cè)試發(fā)現(xiàn)一旦打開(kāi)ATS開(kāi)關(guān):Allow Arbitrary Loads 選項(xiàng)設(shè)置為NO,同時(shí)通過(guò) registerSchemeForCustomProtocol 注冊(cè)了 http(s) scheme,WKWebView 發(fā)起的所有 http 網(wǎng)絡(luò)請(qǐng)求將被阻塞(即便將Allow Arbitrary Loads in Web Content 選項(xiàng)設(shè)置為YES);

WKWebView 可以注冊(cè) customScheme, 比如 dynamic://, 因此希望使用離線功能又不使用 post 方式的請(qǐng)求可以通過(guò) customScheme 發(fā)起請(qǐng)求,比如dynamic://www.dynamicalbumlocalimage.com/,然后在 app 進(jìn)程 NSURLProtocol 攔截這個(gè)請(qǐng)求并加載離線數(shù)據(jù)。不足:使用 post 方式的請(qǐng)求該方案依然不適用,同時(shí)需要 H5 側(cè)修改請(qǐng)求 scheme 以及 CSP 規(guī)則;

(3)在 WKWebView 上通過(guò) loadRequest 發(fā)起的 post 請(qǐng)求 body 數(shù)據(jù)會(huì)丟失

因?yàn)槲覀冞@個(gè)是GET,請(qǐng)求也不會(huì)出現(xiàn)問(wèn)題

(4)到這里,基本上研究完了,但是根據(jù)log日志的分析,確定了問(wèn)題大概在 前端加 XX前綴上和WKWebview加載請(qǐng)求之前這個(gè)階段,然后就順著safras 瀏覽器的調(diào)試功能,確實(shí)發(fā)現(xiàn)前段判斷沒(méi)加上,是因?yàn)槲覀兛蛻舳艘粋€(gè)添加agent的方法沒(méi)加上,至此才發(fā)現(xiàn)了問(wèn)題所在。

坑:(1)自定義協(xié)議去了

? ? ? (2)4.1.1.2 攔截 URL SCHEME

先解釋一下 URL SCHEME:URL SCHEME是一種類似于url的鏈接,是為了方便app直接互相調(diào)用設(shè)計(jì)的,形式和普通的 url 近似,主要區(qū)別是 protocol 和 host 一般是自定義的,例如: qunarhy://hy/url?url=ymfe.tech,protocol 是 qunarhy,host 則是 hy。

攔截 URL SCHEME 的主要流程是:Web 端通過(guò)某種方式(例如 iframe.src)發(fā)送 URL Scheme 請(qǐng)求,之后 Native 攔截到請(qǐng)求并根據(jù) URL SCHEME(包括所帶的參數(shù))進(jìn)行相關(guān)操作。

在時(shí)間過(guò)程中,這種方式有一定的?缺陷

使用 iframe.src 發(fā)送 URL SCHEME 會(huì)有 url 長(zhǎng)度的隱患。

創(chuàng)建請(qǐng)求,需要一定的耗時(shí),比注入 API 的方式調(diào)用同樣的功能,耗時(shí)會(huì)較長(zhǎng)。

但是之前為什么很多方案使用這種方式呢?因?yàn)樗?支持 iOS6。而現(xiàn)在的大環(huán)境下,iOS6 占比很小,基本上可以忽略,所以并不推薦為了 iOS6 使用這種?并不優(yōu)雅?的方式。

【注】:有些方案為了規(guī)避 url 長(zhǎng)度隱患的缺陷,在 iOS 上采用了使用 Ajax 發(fā)送同域請(qǐng)求的方式,并將參數(shù)放到 head 或 body 里。這樣,雖然規(guī)避了 url 長(zhǎng)度的隱患,但是 WKWebView 并不支持這樣的方式。

【注2】:為什么選擇 iframe.src 不選擇 locaiton.href ?因?yàn)槿绻ㄟ^(guò) location.href 連續(xù)調(diào)用 Native,很容易丟失一些調(diào)用。

這部分內(nèi)容的誤導(dǎo),以為傳輸過(guò)程中丟失了,想用另外一個(gè)方式解決。(這種想法基本上不可能,要改的代碼太多了)

http://www.cocoachina.com/articles/28999?

這片文章給了啟示,也給了誤導(dǎo),里面給了好多技術(shù)方案。

https://juejin.im/entry/5975916e518825594d23d777

這片文章,給了好多技術(shù)原理方面的知識(shí)。

(3) 方法總結(jié) 1:階段性調(diào)試 (屏蔽原則) 2.log分析 3.問(wèn)題定位 前后端連調(diào)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件,用以替代 UIKit 中笨...
    Aiana閱讀 4,810評(píng)論 1 8
  • 轉(zhuǎn)載:http://www.cnblogs.com/NSong/p/6489802.html 導(dǎo)語(yǔ) WKWebVi...
    李小威閱讀 4,980評(píng)論 8 9
  • 1、WKWebView 白屏問(wèn)題WKWebView 自詡擁有更快的加載速度,更低的內(nèi)存占用,但實(shí)際上 WKWebV...
    無(wú)名感恩閱讀 2,282評(píng)論 0 3
  • 導(dǎo)語(yǔ) WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件,用以替代 UIKit...
    yahoouchen閱讀 4,203評(píng)論 8 17
  • 我離你那么近 心卻那么遠(yuǎn) 我看見(jiàn)你無(wú)所謂的眼神 你卻聽(tīng)不見(jiàn)我心痛的聲音 文|壹苝
    東夜十二閱讀 216評(píng)論 2 5

友情鏈接更多精彩內(nèi)容