WKWebView 那些坑 ---- 轉(zhuǎn)

導(dǎo)語

WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件旭旭,用以替代 UIKit 中笨重難用改艇、內(nèi)存泄漏的 UIWebView泵殴。WKWebView 擁有60fps滾動(dòng)刷新率棚赔、和 safari 相同的 JavaScript 引擎等優(yōu)勢(shì)。

簡單的適配方法本文不再贅述系吩,主要來說說適配 WKWebView 過程中填過的坑以及善待解決的技術(shù)難題来庭。

1、WKWebView 白屏問題

WKWebView 自詡擁有更快的加載速度穿挨,更低的內(nèi)存占用月弛,但實(shí)際上 WKWebView 是一個(gè)多進(jìn)程組件,Network Loading 以及 UI Rendering 在其它進(jìn)程中執(zhí)行科盛。初次適配 WKWebView 的時(shí)候帽衙,我們也驚訝于打開 WKWebView 后,App 進(jìn)程內(nèi)存消耗反而大幅下降贞绵,但是仔細(xì)觀察會(huì)發(fā)現(xiàn)佛寿,Other Process 的內(nèi)存占用會(huì)增加。在一些用 webGL 渲染的復(fù)雜頁面但壮,使用 WKWebView 總體的內(nèi)存占用(App Process Memory + Other Process Memory)不見得比 UIWebView 少很多。

在 UIWebView 上當(dāng)內(nèi)存占用太大的時(shí)候常侣,App Process 會(huì) crash蜡饵;而在 WKWebView 上當(dāng)總體的內(nèi)存占用比較大的時(shí)候,WebContent Process 會(huì) crash胳施,從而出現(xiàn)白屏現(xiàn)象溯祸。在 WKWebView 中加載下面的測(cè)試鏈接可以穩(wěn)定重現(xiàn)白屏現(xiàn)象:

http://people.mozilla.org/~rnewman/fennec/mem.html

這個(gè)時(shí)候 WKWebView.URL 會(huì)變?yōu)?nil, 簡單的 reload 刷新操作已經(jīng)失效,對(duì)于一些長駐的H5頁面影響比較大。

**我們最后的解決方案是: **

A焦辅、借助 WKNavigtionDelegate

iOS 9以后 WKNavigtionDelegate 新增了一個(gè)回調(diào)函數(shù):

- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));

當(dāng) WKWebView 總體內(nèi)存占用過大博杖,頁面即將白屏的時(shí)候,系統(tǒng)會(huì)調(diào)用上面的回調(diào)函數(shù)筷登,我們?cè)谠摵瘮?shù)里執(zhí)行[webView reload](這個(gè)時(shí)候 webView.URL 取值尚不為 nil)解決白屏問題剃根。在一些高內(nèi)存消耗的頁面可能會(huì)頻繁刷新當(dāng)前頁面,H5側(cè)也要做相應(yīng)的適配操作前方。

B狈醉、檢測(cè) webView.title 是否為空

并不是所有H5頁面白屏的時(shí)候都會(huì)調(diào)用上面的回調(diào)函數(shù),比如惠险,最近遇到在一個(gè)高內(nèi)存消耗的H5頁面上 present 系統(tǒng)相機(jī)苗傅,拍照完畢后返回原來頁面的時(shí)候出現(xiàn)白屏現(xiàn)象(拍照過程消耗了大量內(nèi)存,導(dǎo)致內(nèi)存緊張班巩,WebContent Process 被系統(tǒng)掛起)渣慕,但上面的回調(diào)函數(shù)并沒有被調(diào)用。在WKWebView白屏的時(shí)候抱慌,另一種現(xiàn)象是 webView.titile 會(huì)被置空, 因此逊桦,可以在 viewWillAppear 的時(shí)候檢測(cè) webView.title 是否為空來 reload 頁面。

綜合以上兩種方法可以解決絕大多數(shù)的白屏問題遥缕。

2卫袒、WKWebView Cookie 問題

Cookie 問題是目前 WKWebView 的一大短板

2.1、WKWebView Cookie存儲(chǔ)

業(yè)界普遍認(rèn)為 WKWebView 擁有自己的私有存儲(chǔ)单匣,不會(huì)將 Cookie 存入到標(biāo)準(zhǔn)的 Cookie 容器 NSHTTPCookieStorage 中夕凝。

實(shí)踐發(fā)現(xiàn) WKWebView 實(shí)例其實(shí)也會(huì)將 Cookie 存儲(chǔ)于 NSHTTPCookieStorage 中,但存儲(chǔ)時(shí)機(jī)有延遲户秤,在iOS 8上码秉,當(dāng)頁面跳轉(zhuǎn)的時(shí)候,當(dāng)前頁面的 Cookie 會(huì)寫入 NSHTTPCookieStorage 中鸡号,而在 iOS 10 上转砖,JS 執(zhí)行 document.cookie 或服務(wù)器 set-cookie 注入的 Cookie 會(huì)很快同步到 NSHTTPCookieStorage 中,F(xiàn)ireFox 工程師曾建議通過 reset WKProcessPool 來觸發(fā) Cookie 同步到 NSHTTPCookieStorage 中鲸伴,實(shí)踐發(fā)現(xiàn)不起作用府蔗,并可能會(huì)引發(fā)當(dāng)前頁面 session cookie 丟失等問題。

WKWebView Cookie 問題在于 WKWebView 發(fā)起的請(qǐng)求不會(huì)自動(dòng)帶上存儲(chǔ)于 NSHTTPCookieStorage 容器中的 Cookie汞窗。

比如姓赤,NSHTTPCookieStorage 中存儲(chǔ)了一個(gè) Cookie:

name=Nicholas;value=test;domain=y.qq.com;expires=Sat, 02 May 2019 23:38:25 GMT;

通過 UIWebView 發(fā)起請(qǐng)求http://y.qq.com仲吏, 則請(qǐng)求頭會(huì)自動(dòng)帶上 cookie: Nicholas=test不铆;
而通過 WKWebView發(fā)起請(qǐng)求http://y.qq.com蝌焚, 請(qǐng)求頭不會(huì)自動(dòng)帶上 cookie: Nicholas=test。

2.2誓斥、WKProcessPool

蘋果開發(fā)者文檔對(duì) WKProcessPool 的定義是:A WKProcessPool object represents a pool of Web Content process. 通過讓所有 WKWebView 共享同一個(gè) WKProcessPool 實(shí)例只洒,可以實(shí)現(xiàn)多個(gè) WKWebView 之間共享 Cookie(session Cookie and persistent Cookie)數(shù)據(jù)。不過 WKWebView WKProcessPool 實(shí)例在 app 殺進(jìn)程重啟后會(huì)被重置劳坑,導(dǎo)致 WKProcessPool 中的 Cookie毕谴、session Cookie 數(shù)據(jù)丟失,目前也無法實(shí)現(xiàn) WKProcessPool 實(shí)例本地化保存泡垃。

2.3析珊、Workaround

由于許多 H5 業(yè)務(wù)都依賴于 Cookie 作登錄態(tài)校驗(yàn),而 WKWebView 上請(qǐng)求不會(huì)自動(dòng)攜帶 Cookie, 目前的主要解決方案是:

a蔑穴、WKWebView loadRequest 前忠寻,在 request header 中設(shè)置 Cookie, 解決首個(gè)請(qǐng)求 Cookie 帶不上的問題;
WKWebView * webView = [WKWebView new]; NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://h5.qzone.qq.com/mqzone/index"]]; 
[request addValue:@"skey=skeyValue" forHTTPHeaderField:@"Cookie"]; [webView loadRequest:request];
b存和、通過 document.cookie 設(shè)置 Cookie 解決后續(xù)頁面(同域)Ajax奕剃、iframe 請(qǐng)求的 Cookie 問題;

注意:document.cookie()無法跨域設(shè)置 cookie

WKUserContentController* userContentController = [WKUserContentController new]; WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource: @"document.cookie = 'skey=skeyValue';" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; 
[userContentController addUserScript:cookieScript];

這種方案無法解決302請(qǐng)求的 Cookie 問題捐腿,比如纵朋,第一個(gè)請(qǐng)求是 www.a.com,我們通過在 request header 里帶上 Cookie 解決該請(qǐng)求的 Cookie 問題茄袖,接著頁面302跳轉(zhuǎn)到 www.b.com操软,這個(gè)時(shí)候 www.b.com 這個(gè)請(qǐng)求就可能因?yàn)闆]有攜帶 cookie 而無法訪問。當(dāng)然宪祥,由于每一次頁面跳轉(zhuǎn)前都會(huì)調(diào)用回調(diào)函數(shù):

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

可以在該回調(diào)函數(shù)里攔截302請(qǐng)求聂薪,copy request,在 request header 中帶上 cookie 并重新 loadRequest蝗羊。不過這種方法依然解決不了頁面 iframe 跨域請(qǐng)求的 Cookie 問題藏澳,畢竟-[WKWebView loadRequest:]只適合加載 mainFrame 請(qǐng)求。

3耀找、WKWebView NSURLProtocol問題

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

+ [WKBrowsingContextController registerSchemeForCustomProtocol:]

通過注冊(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,然后通過 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ù)制鏈接到瀏覽器中打開)

及bug report:

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

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

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

測(cè)試發(fā)現(xiàn)一旦打開ATS開關(guān):Allow Arbitrary Loads 選項(xiàng)設(shè)置為NO酥馍,同時(shí)通過 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)求可以通過 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ī)則襟企;

4顽悼、WKWebView loadRequest 問題

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

//同樣是由于進(jìn)程間通信性能問題,HTTPBody字段被丟棄[request setHTTPMethod:@"POST"];
[request setHTTPBody:[@"bodyData" dataUsingEncoding:NSUTF8StringEncoding]];
[wkwebview loadRequest: request];

workaround:

假如想通過-[WKWebView loadRequest:]加載 post 請(qǐng)求 request1: http://h5.qzone.qq.com/mqzone/index,可以通過以下步驟實(shí)現(xiàn):

  1. 替換請(qǐng)求 scheme冰评,生成新的 post 請(qǐng)求 request2: post://h5.qzone.qq.com/mqzone/index, 同時(shí)將 request1 的 body 字段復(fù)制到 request2 的 header 中(WebKit 不會(huì)丟棄 header 字段);

  2. 通過-[WKWebView loadRequest:]加載新的 post 請(qǐng)求 request2;

  3. 通過 +[WKBrowsingContextController registerSchemeForCustomProtocol:]注冊(cè) scheme: post://;

  4. 注冊(cè) NSURLProtocol 攔截請(qǐng)求post://h5.qzone.qq.com/mqzone/index ,替換請(qǐng)求 scheme, 生成新的請(qǐng)求 request3: http://h5.qzone.qq.com/mqzone/index甲雅,將 request2 header的body 字段復(fù)制到 request3 的 body 中坑填,并使用 NSURLConnection 加載 request3脐瑰,最后通過 NSURLProtocolClient 將加載結(jié)果返回 WKWebView;

5、WKWebView 頁面樣式問題

在 WKWebView 適配過程中盅惜,我們發(fā)現(xiàn)部分H5頁面元素位置向下偏移被拉伸變形抒寂,追蹤后發(fā)現(xiàn)主要是H5頁面高度值異常導(dǎo)致:

a. 空間H5頁面有透明導(dǎo)航掠剑、透明導(dǎo)航下拉刷新朴译、全屏等需求,因此之前 webView 整個(gè)是從(0, 0)開始布局躬翁,通過調(diào)整webView.scrollView.contentInset 來適配特殊導(dǎo)航欄需求盯拱。而在 WKWebView 上對(duì) contentInset 的調(diào)整會(huì)反饋到webView.scrollView.contentSize.height的變化上狡逢,比如設(shè)置 webView.scrollView.contentInset.top = a,那么contentSize.height的值會(huì)增加a,導(dǎo)致H5頁面長度增加蛮艰,頁面元素位置向下偏移壤蚜;

解決方案是:調(diào)整WKWebView布局方式,避免調(diào)整webView.scrollView.contentInset嘿悬。實(shí)際上水泉,即便在 UIWebView 上也不建議直接調(diào)整webView.scrollView.contentInset的值草则,這確實(shí)會(huì)帶來一些奇怪的問題蟹漓。如果某些特殊情況下非得調(diào)整 contentInset 不可的話葡粒,可以通過下面方式讓H5頁面恢復(fù)正常顯示:

/**設(shè)置contentInset值后通過調(diào)整webView.frame讓頁面恢復(fù)正常顯示 
 *參考:http://km.oa.com/articles/show/277372
 */ webView.scrollView.contentInset = UIEdgeInsetsMake(a, 0, 0, 0); 
webView.frame = CGRectMake(webView.frame.origin.x, webView.frame.origin.y, webView.frame.size.width, webView.frame.size.height - a);

b. 在接入 now 直播的時(shí)候嗽交,我們發(fā)現(xiàn)在 iOS 9 上 WKWebView 會(huì)出現(xiàn)頁面被拉伸變形的情況,最后發(fā)現(xiàn)是window.innerHeight值不準(zhǔn)確導(dǎo)致(在WKWebView上返回了一個(gè)非常大的值)拾枣,而H5同學(xué)通過獲取window.innerHeight來設(shè)置頁面高度盒让,導(dǎo)致頁面整體被拉伸邑茄。通過查閱相關(guān)資料發(fā)現(xiàn),這個(gè)bug只在 iOS 9 的幾個(gè)系統(tǒng)版本上出現(xiàn)左医,蘋果后來fix了這個(gè)bug炒辉。我們最后的解決方案是:延遲調(diào)用window.innerHeight

setTimeout(function(){height = window.innerHeight},0);

or

Use shrink-to-fit meta-tag 
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1, shrink-to-fit=no">

6泉手、WKWebView 截屏問題

空間玩吧H5小游戲有截屏分享的功能斩萌,WKWebView 下通過 -[CALayer renderInContext:]實(shí)現(xiàn)截屏的方式失效屏轰,需要通過以下方式實(shí)現(xiàn)截屏功能:

@implementation UIView (ImageSnapshot) 
- (UIImage*)imageSnapshot { 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size,YES,self.contentScaleFactor); 
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES]; 
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return newImage; 
} 
@end

然而這種方式依然解決不了 webGL 頁面的截屏問題霎苗,筆者已經(jīng)翻遍蘋果文檔唁盏,研究過 webKit2 源碼里的截屏私有API检眯,依然沒有找到合適的解決方案锰瘸,同時(shí)發(fā)現(xiàn) Safari 以及 Chrome 這兩個(gè)全量切換到 WKWebView 的瀏覽器也存在同樣的問題:對(duì)webGL 頁面的截屏結(jié)果不是空白就是純黑圖片。無奈之下舞萄,我們只能約定一個(gè)JS接口管削,讓游戲開發(fā)商實(shí)現(xiàn)該接口佩谣,具體是通過 canvas getImageData()方法取得圖片數(shù)據(jù)后返回 base64 格式的數(shù)據(jù)茸俭,客戶端在需要截圖的時(shí)候,調(diào)用這個(gè)JS接口獲取 base64 String 并轉(zhuǎn)換成 UIImage艇炎。

7腾窝、WKWebView crash問題

WKWebView 放量后虹脯,外網(wǎng)新增了一些 crash, 其中一類 crash 的主要堆棧如下:

... 
28 UIKit 0x0000000190513360 UIApplicationMain + 208 29 Qzone 0x0000000101380570 main (main.m:181) 
30 libdyld.dylib 0x00000001895205b8 _dyld_process_info_notify_release + 36 Completion handler passed to -[QZWebController webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:] was not called

主要是JS調(diào)用window.alert()函數(shù)引起的循集,從 crash 堆棧可以看出是 WKWebView 回調(diào)函數(shù):

+ (void) presentAlertOnController:(nonnull UIViewController*)parentController title:(nullable NSString*)title message:(nullable NSString *)message handler:(nonnull void (^)())completionHandler;

completionHandler 沒有被調(diào)用導(dǎo)致的疆柔。在適配 WKWebView 的時(shí)候旷档,我們需要自己實(shí)現(xiàn)該回調(diào)函數(shù),window.alert()才能調(diào)起 alert 框范咨,我們最初的實(shí)現(xiàn)是這樣的:

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler 
{ 
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert]; 
    [alertController addAction:[UIAlertAction actionWithTitle:@"確認(rèn)" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { completionHandler(); }]]; 
    [self presentViewController:alertController animated:YES completion:^{}]; 
}

如果 WKWebView 退出的時(shí)候湖蜕,JS剛好執(zhí)行了window.alert(), alert 框可能彈不出來宋列,completionHandler 最后沒有被執(zhí)行炼杖,導(dǎo)致 crash坤邪;另一種情況是在 WKWebView 一打開罚缕,JS就執(zhí)行window.alert()邮弹,這個(gè)時(shí)候由于 WKWebView 所在的 UIViewController 出現(xiàn)(push或present)的動(dòng)畫尚未結(jié)束,alert 框可能彈不出來盟劫,completionHandler 最后沒有被執(zhí)行侣签,導(dǎo)致 crash急迂。我們最終的實(shí)現(xiàn)大致是這樣的:

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler 
{ 
    if (/*UIViewController of WKWebView has finish push or present animation*/) { 
        completionHandler(); 
        return; 
    } 
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert]; 
    [alertController addAction:[UIAlertAction actionWithTitle:@"確認(rèn)" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { completionHandler(); }]]; 
    if (/*UIViewController of WKWebView is visible*/) 
        [self presentViewController:alertController animated:YES completion:^{}]; 
    else 
        completionHandler(); 
}

確保上面兩種情況下 completionHandler 都能被執(zhí)行僚碎,消除了 WKWebView 下彈 alert 框的 crash,WKWebView 下彈 confirm 框的 crash 的原因與解決方式與 alert 類似裂七。

另一個(gè) crash 發(fā)生在 WKWebView 退出前調(diào)用:

 -[WKWebView evaluateJavaScript: completionHandler:]

執(zhí)行JS代碼的情況下仓坞。WKWebView 退出并被釋放后導(dǎo)致completionHandler變成野指針无埃,而此時(shí) javaScript Core 還在執(zhí)行JS代碼嫉称,待 javaScript Core 執(zhí)行完畢后會(huì)調(diào)用completionHandler(),導(dǎo)致 crash壳繁。這個(gè) crash 只發(fā)生在 iOS 8 系統(tǒng)上荔棉,參考Apple Open Source润樱,在iOS9及以后系統(tǒng)蘋果已經(jīng)修復(fù)了這個(gè)bug壹若,主要是對(duì)completionHandler block做了copy(refer: https://trac.webkit.org/changeset/179160);對(duì)于iOS 8系統(tǒng)养篓,可以通過在 completionHandler 里 retain WKWebView 防止 completionHandler 被過早釋放觉至。我們最后用 methodSwizzle hook 了這個(gè)系統(tǒng)方法:

+ (void) load 
{ 
     [self jr_swizzleMethod:NSSelectorFromString(@"evaluateJavaScript:completionHandler:") withMethod:@selector(altEvaluateJavaScript:completionHandler:) error:nil]; 
} 
/* 
 * fix: WKWebView crashes on deallocation if it has pending JavaScript evaluation 
 */ - (void)altEvaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler 
{ 
    id strongSelf = self; 
    [self altEvaluateJavaScript:javaScriptString completionHandler:^(id r, NSError *e) { 
        [strongSelf title]; 
        if (completionHandler) { 
            completionHandler(r, e); 
        } 
    }]; 
}

8语御、其它問題

8.1席怪、視頻自動(dòng)播放

WKWebView 需要通過WKWebViewConfiguration.mediaPlaybackRequiresUserAction設(shè)置是否允許自動(dòng)播放挂捻,但一定要在 WKWebView 初始化之前設(shè)置,在 WKWebView 初始化之后設(shè)置無效骨田。

8.2态贤、goBack API問題

WKWebView 上調(diào)用 -[WKWebView goBack], 回退到上一個(gè)頁面后不會(huì)觸發(fā)window.onload()函數(shù)、不會(huì)執(zhí)行JS箱吕。

8.3茬高、頁面滾動(dòng)速率

WKWebView 需要通過scrollView delegate調(diào)整滾動(dòng)速率:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
     scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
}

9怎栽、結(jié)語

本文總結(jié)了在 WKWebView 上踩過的一些坑宿饱。雖然 WKWebView 坑比較多刑棵,但是相對(duì) UIWebView 在內(nèi)存消耗愚铡、穩(wěn)定性方面還是有很大的優(yōu)勢(shì)沥寥。盡管蘋果對(duì) WKWebView 的開發(fā)進(jìn)度過于緩慢,但相信 WKWebView 才是未來片橡。

原文地址: 騰訊Bugly
https://mp.weixin.qq.com/s/rhYKLIbXOsUJC_n6dt9UfA

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捧书,一起剝皮案震驚了整個(gè)濱河市经瓷,隨后出現(xiàn)的幾起案子舆吮,更是在濱河造成了極大的恐慌,老刑警劉巖潭袱,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屯换,死亡現(xiàn)場(chǎng)離奇詭異趟径,居然都是意外死亡癣防,警方通過查閱死者的電腦和手機(jī)蕾盯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門级遭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挫鸽,“玉大人,你說我怎么就攤上這事盔沫〖艿” “怎么了干茉?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵角虫,是天一觀的道長戳鹅。 經(jīng)常有香客問我,道長辣恋,這世上最難降的妖魔是什么伟骨? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任携狭,我火速辦了婚禮逛腿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碘举。我一直安慰自己引颈,他們只是感情好境蜕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布售滤。 她就那樣靜靜地躺著台诗,像睡著了一般拉庶。 火紅的嫁衣襯著肌膚如雪秃励。 梳的紋絲不亂的頭發(fā)上夺鲜,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天币励,我揣著相機(jī)與錄音食呻,去河邊找鬼。 笑死每辟,一個(gè)胖子當(dāng)著我的面吹牛渠欺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胳岂,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼乳丰,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼成艘!你這毒婦竟也來了淆两?” 一聲冷哼從身側(cè)響起拂酣,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤婶熬,失蹤者是張志新(化名)和其女友劉穎剑勾,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赵颅,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虽另,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饺谬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捂刺。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖募寨,靈堂內(nèi)的尸體忽然破棺而出族展,到底是詐尸還是另有隱情拔鹰,我是刑警寧澤仪缸,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站列肢,受9級(jí)特大地震影響恰画,放射性物質(zhì)發(fā)生泄漏宾茂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一锣尉、第九天 我趴在偏房一處隱蔽的房頂上張望刻炒。 院中可真熱鬧,春花似錦自沧、人聲如沸坟奥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爱谁。三九已至,卻和暖如春孝偎,著一層夾襖步出監(jiān)牢的瞬間访敌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工衣盾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寺旺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓势决,卻偏偏與公主長得像阻塑,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子果复,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容