WKWebView使用遇到的坑
簡介
使用WKWebView一段時間,發(fā)現(xiàn)它和UIWebView的一些區(qū)別之處,有一寫遇到的坑,現(xiàn)在對處理方式做了個小總結,現(xiàn)分享給大家.
區(qū)別
1.EvaluateJavaScript方法為異步
- UIWebview:
在UIWebView
中是同步執(zhí)行的,直接調用
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;```
方法返回執(zhí)行結果
- WKWebView
在```WKWebView```中,改為了```block```的方式進行值返回,并且該方法的執(zhí)行是異步的
```- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ __nullable)(__nullable id, NSError * __nullable error))completionHandler;
延伸:執(zhí)行JS方法的使用場景之一,就是獲取當前webview的title,WKWebView
提供了新屬性title,如果是想獲取title,可以直接使用WKWebView
的title屬性.
2.cookie設置方式不同
- UIWebView:
通過該方式設置的,為全局的cookie,項目中任意的UIWebView
均攜帶一樣的cookie.設置之后不需要做額外的操作.
- WKWebView
網頁將不再能獲取默認的cookie,如果需要攜帶cookie,需要做一些操作:
1 初始化cookie, NSString *cookie = @"document.cookie='cookieKey=cookieValue'";
2 注入cookie
獲取當前的userContentController
:
注入scrpit:
WKUserScript *script = [[WKUserScript alloc] initWithSource:cookieValue injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:script];
注意
注入script時參數(shù)indectionTime有兩個可選項WKUserScriptInjectionTimeAtDocumentStart
和WKUserScriptInjectionTimeAtDocumentEnd
,
我們看一下官方文檔對于這兩個選項的解釋:
WKUserScriptInjectionTimeAtDocumentStart
: 注入時機為document的元素生成之后,其他內容load之前.
WKUserScriptInjectionTimeAtDocumentEnd
: 注入時機為document全部load完成,任意子資源load完成之前.
一般情況下,如果想盡早注入cookie,在WKUserScriptInjectionTimeAtDocumentStart
時完成即可,但是有一種特殊情況,即目前的診療圈為后端渲染,數(shù)據請求依賴cookie中的sessionKey
,而前端頁面的元素依賴后端返回的數(shù)據,因此,有一個問題,即cookie是在頁面元素生成之后注入的,而在這之前,后端需要獲取cookie,那么應該怎么辦呢??
在requestHeader內注入cookie
NSString *cookie = @"cookieKey1=cookieValue1;cookieKey2=cookieValue2";
[mutableRequest addValue:cookie forHTTPHeaderField:@"Cookie"];
這樣在網絡請求開始時,requestHeader將攜帶cookie.
3.WKWebView默認禁止了一些跳轉
- UIWebView
打開ituns.apple.com跳轉到appStore, 撥打電話, 喚起郵箱等一系列操作UIWebView默認支持的.
- WKWebView
默認禁止了以上行為,除此之外,js端通過window.open()
打開新的網頁的動作也被禁掉了.
如何支持呢?
可以跳轉appStore或者撥號
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
if(webView != self.wkWebView) {
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
UIApplication *app = [UIApplication sharedApplication];
if ([url.scheme isEqualToString:@"tel"])
{
if ([app canOpenURL:url])
{
[app openURL:url];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
if ([url.absoluteString containsString:@"ituns.apple.com"])
{
if ([app canOpenURL:url])
{
[app openURL:url];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
decisionHandler(WKNavigationActionPolicyAllow);
}
支持window.open()
需要打開新界面是,WKWebView的代理WKUIDelegate
方法
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
會攔截到window.open()事件.
只需要我們在在方法內進行處理
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}
支持alert()
WKWebView默認不響應js的alert()事件,如何可以開啟alert權限呢?
代理WKUIDelegate
方法
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
將會獲取到alert的信息,但是不會彈出alert.
在方法內部
[alertController addAction:[UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
completionHandler();
}]];
if ([self.delegate isKindOfClass:[UIViewController class]]) {
UIViewController *controller = (UIViewController *)self.delegate;
[controller presentViewController:alertController animated:YES completion:^{}];
}