使用WKWebView遇见的那些坑

PMNKay 7年前
   <p>iOS8之后出了WKWebView,据说加载速度和内存占用情况都甩UIWebView好几条街,鉴于我们公司的项目用到挺多的webView,于是简单的调研下决定用WKWebView替换UIWebView。WKWebView的使用方法不多少,相信网上所有的都比我讲得好,简单说下我在使用过程中遇到的坑,以及“复杂”的心路历程,相信不少人应该也遇到过这种情况</p>    <p>1.三个相关代理WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler。</p>    <p>我学习新东西的习惯是直接看头文件和露出来的接口,简单看下注释,然后直接用,为此多走了不少弯路</p>    <p>WKNavigationDelegate,只提一个方法,</p>    <pre>  <code class="language-objectivec">//相当于UIWebView的shouldStartLoadWithRequest,其中decisionHandler一定要实现,否则不执行  - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;</code></pre>    <p><strong>WKUIDelegate</strong></p>    <p>支持alert弹出框,confirm选择框,TextInput输入框,如果不实现此代理中相应的方法,直接点击是没有特别反应的,要特别注意。</p>    <pre>  <code class="language-objectivec">//alert弹出  - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;  //confirm选择框  - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;  //text Input输入框  - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;</code></pre>    <p>WKScriptMessageHandler</p>    <p>这是JS调用native的代理。native调用JS与UIWebView大同小异,在此不多说。</p>    <p>UIWebView中,JS调用native的方法还是比较好理解的,采用JSContext的形式</p>    <pre>  <code class="language-objectivec">JSContext *jsContext = (JSContext *)[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];  jsContext[@"jsCallApp"] = self.jsCallApp;</code></pre>    <p>注意WKScriptMessageHandler是WKUserContentController要遵循的协议,附上初始化方法</p>    <pre>  <code class="language-objectivec">NSString * name = @"jsCallApp";      WKUserContentController *userContentController = [[WKUserContentController alloc] init];      //遵循协议      [userContentController addScriptMessageHandler:self name:name];        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];      configuration.userContentController = userContentController;      _webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];      _webView.UIDelegate = self;      _webView.navigationDelegate = self;      //加载的本地html文件,便于修改      NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"];      NSURL *url = [NSURL fileURLWithPath:path];      [_webView loadFileURL:url allowingReadAccessToURL:url];      [self.view addSubview:_webView];</code></pre>    <p>实现协议方法:注意此方法是request的</p>    <pre>  <code class="language-objectivec">- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {      NSString *methods = [NSString stringWithFormat:@"%@:", message.body];      SEL selector = NSSelectorFromString(methods);      if ([self respondsToSelector:selector]) {        } else {          NSLog(@"未实行方法:%@", methods);      }  }</code></pre>    <p>JS端必须配合来写,前端必须用</p>    <p>window.webkit.messageHandlers.jsCallApp.postMessage(null);</p>    <p>来唤起app的方法,其中jsCallApp是对应的name,postMessage中传参数。</p>    <p>对于更新过很多版本的app来说,考虑实际情况,如果有这种复杂的js与app之间互相调用的话,前端必须考虑判断版本号,判断安卓还是iOS,或者安卓跟着做相应的修改,总之还是挺复杂的,如果速度还过得去,也不崩溃的话建议别修改了,如果你的前端和安卓好说话,修改也行。如果不涉及交互,那还是非常建议替换的</p>    <p>还有一个问题就是,对于html动画特别多的页面,WKWebView有时候比UIWebView还卡顿,至今未解决,也不知道是什么原因,欢迎知道的大神留言指导。</p>    <p> </p>    <p>来自:http://www.jianshu.com/p/39f3ef174835</p>    <p> </p>