在转变之前,需要先来探究一番,到底适不适合替换.
看WKWebView是不是坑太多,根本不能使用.
这是找来的可能遇到的各路坑的情况:
这是找来的可能可参考的 使用资料:
WKWebView-Bridge 在react-native封装的实现 iOS开发
WKWebView 拦截URL ----这个解决了我的问题
我项目中实际替换遇到的问题:
项目中UIWebView和一起的使用的WebViewJavascriptBridge 都是很久之前封装的,WebViewJavascriptBridge中代码跟web端的代码有耦合.所以无法弃用.也无法使用网上现成的WebViewJavascriptBridge库. 只能去看WebViewJavascriptBridge中需要修改的地方.
主要是要替换WebViewJavascriptBridge中,使用到的UIWebView的代理方法.在替换过程中,有个问题卡了很久.
项目中嵌入了一段JS代码,其中有这么一段,作用是 "使用JS加载URL", 然后在webview中拦截URL,从而起到 "JS调用原生' 的功能.
var messagingIframe\n\
var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme'\n\
var QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__'\n\
function _createQueueReadyIframe(doc) {\n\
messagingIframe = doc.createElement('iframe')\n\
messagingIframe.style.display = 'none'\n\
doc.documentElement.appendChild(messagingIframe)\n\
}\n\
function _doSend(message, responseCallback) {\n\
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE\n\
}\n\
拦截URL
使用WKNavigationDelegate中的代理方法,拦截自定义的URL来实现JS调用OC方法。
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSURL *URL = navigationAction.request.URL; //在这里拦截要的URL
NSString *scheme = [URL scheme];
if ([scheme isEqualToString:@"haleyaction"]) {
[self handleCustomAction:URL];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
需要注意的是:
1.如果实现了这个代理方法,就必须得调用decisionHandler这个block,否则会导致app 崩溃。block参数是个枚举类型,WKNavigationActionPolicyCancel代表取消加载,相当于UIWebView的代理方法return NO的情况;WKNavigationActionPolicyAllow代表允许加载,相当于UIWebView的代理方法中 return YES的情况。
2.其他的关于为什么要统一设置scheme,在上一篇中讲过。
这个 上一篇 中,还有一段代码,是 JS 加载URL的. 跟上面 我们项目中 嵌入的JS相似.
functionloadURL(url){
var iFrame;
iFrame = document.createElement("iframe");
iFrame.setAttribute("src", url);
iFrame.setAttribute("style","display:none;");
iFrame.setAttribute("height","0px");
iFrame.setAttribute("width","0px");
iFrame.setAttribute("frameborder","0");
document.body.appendChild(iFrame);
// 发起请求后这个iFrame就没用了,所以把它从dom上移除掉
iFrame.parentNode.removeChild(iFrame);
iFrame = null;
}
跟JS打交道多了. 也留意了下JS相关的.
这是上面引用的某个博主的系列,有需要可以看一下
iOS下JS与OC互相调用(一)--UIWebView 拦截URL
iOS下JS与OC互相调用(二)--WKWebView 拦截URL
iOS下JS与OC互相调用(三)--MessageHandler
iOS下JS与OC互相调用(四)--JavaScriptCore
iOS下JS与OC互相调用(五)--UIWebView + WebViewJavascriptBridge
iOS下JS与OC互相调用(六)--WKWebView + WebViewJavascriptBridge
iOS下JS与OC互相调用(八)--Cordova详解+实战
(17.8.16)后记:
#WKWebView使用遇到的坑
使用WKWebView一段时间,发现它和UIWebView的一些区别之处,还有一些遇到的坑
WKWebView默认禁止了一些跳转
####1.cookie设置方式不同
- UIWebView:
```NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
```
```[storage setCookie:cookieKey value:cookieValue];
```
通过该方式设置的,为全局的cookie,项目中任意的```UIWebView```均携带一样的cookie.设置之后不需要做额外的操作.
- WKWebView
网页将不再能获取默认的cookie,如果需要携带cookie,需要做一些操作:
1 初始化cookie, ```NSString *cookie = @"document.cookie='cookieKey=cookieValue'";```
2 注入cookie
获取当前的```userContentController```:
``` WKUserContentController *userContentController = self.wkWebView.configuration.userContentController;
```
注入scrpit:
WKUserScript *script = [[WKUserScript alloc] initWithSource:cookieValue injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:script];
######注意
注入script时参数indectionTime有两个可选项```WKUserScriptInjectionTimeAtDocumentStart```和```WKUserScriptInjectionTimeAtDocumentEnd```,
我们看一下官方文档对于这两个选项的解释:
```WKUserScriptInjectionTimeAtDocumentStart``` : 注入时机为document的元素生成之后,其他内容load之前.
```WKUserScriptInjectionTimeAtDocumentEnd``` : 注入时机为document全部load完成,任意子资源load完成之前.
一般情况下,如果想尽早注入cookie,在```WKUserScriptInjectionTimeAtDocumentStart```时完成即可,但是有一种特殊情况,即目前的诊疗圈为后端渲染,数据请求依赖cookie中的```sessionKey```,而前端页面的元素依赖后端返回的数据,因此,有一个问题,即cookie是在页面元素生成之后注入的,而在这之前,后端需要获取cookie,那么应该怎么办呢??
######在requestHeader内注入cookie
```NSString *cookie = @"cookieKey1=cookieValue1;cookieKey2=cookieValue2";```
``` [mutableRequest addValue:cookie forHTTPHeaderField:@"Cookie"];
```
这样在网络请求开始时,requestHeader将携带cookie.
####2.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:^{}];
}
(使用资料:http://blog.csdn.net/j_av_a/article/details/52160413)