WKWebview替代UIWebView之简单攻略

前言

Xcode8发布以后,编译器开始不支持IOS7,所以很多应用在适配IOS10之后都不在适配IOS7了,其中包括了很多大公司,网易新闻,滴滴出行等。因此,我们公司的应用也打算淘汰IOS7。

支持到IOS8,第一个要改的自然是用WKWebView替换原来的UIWebView。WKWebView有很多明显优势:

更多的支持HTML5的特性

官方宣称的高达60fps的滚动刷新率以及内置手势

将UIWebViewDelegate与UIWebView拆分成了14类与3个协议,以前很多不方便实现的功能得以实现。文档

Safari相同的JavaScript引擎

占用更少的内存

UIWebView

WKWebview替代UIWebView之简单攻略_第1张图片

functionsay(){//前端需要用 window.webkit.messageHandlers.注册的方法名.postMessage({body:传输的数据} 来给native发送消息window.webkit.messageHandlers.sayhello.postMessage({body:'hello world!'});}

UIWebView

WKWebView

WKWebview替代UIWebView之简单攻略_第2张图片

WKWebView

因此,使用WkWebview替换UIWebView还是很有必要的。

基本使用方法

WKWebView有两个delegate,WKUIDelegate和WKNavigationDelegate。WKNavigationDelegate主要处理一些跳转、加载处理操作,WKUIDelegate主要处理JS脚本,确认框,警告框等。因此WKNavigationDelegate更加常用。

比较常用的方法:

#pragma mark - lifeCircle

- (void)viewDidLoad {    [superviewDidLoad];    webView = [[WKWebView alloc]init];    [self.viewaddSubview:webView];    [webView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.equalTo(self.view);        make.right.equalTo(self.view);        make.top.equalTo(self.view);        make.bottom.equalTo(self.view);    }];    webView.UIDelegate=self;    webView.navigationDelegate=self;    [webView loadRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.baidu.com"]]];}

#pragma mark - WKNavigationDelegate

// 页面开始加载时调用

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{}

// 当内容开始返回时调用

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{}

// 页面加载完成之后调用

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{}

// 页面加载失败时调用

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{}

// 接收到服务器跳转请求之后调用

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{}

// 在收到响应后,决定是否跳转

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void(^)(WKNavigationResponsePolicy))decisionHandler{NSLog(@"%@",navigationResponse.response.URL.absoluteString);//允许跳转decisionHandler(WKNavigationResponsePolicyAllow);//不允许跳转//decisionHandler(WKNavigationResponsePolicyCancel);}

// 在发送请求之前,决定是否跳转

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void(^)(WKNavigationActionPolicy))decisionHandler{NSLog(@"%@",navigationAction.request.URL.absoluteString);//允许跳转decisionHandler(WKNavigationActionPolicyAllow);//不允许跳转//decisionHandler(WKNavigationActionPolicyCancel);}

#pragma mark - WKUIDelegate

// 创建一个新的WebView

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{return[[WKWebView alloc]init];}

// 输入框

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt defaultText:(nullableNSString*)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void(^)(NSString* __nullable result))completionHandler{    completionHandler(@"http");}

// 确认框

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString*)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void(^)(BOOLresult))completionHandler{    completionHandler(YES);}

// 警告框

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString*)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void(^)(void))completionHandler{NSLog(@"%@",message);    completionHandler();}

OC与JS交互

WKWebview提供了API实现js交互 不需要借助JavaScriptCore或者webJavaScriptBridge。使用WKUserContentController实现js native交互。简单的说就是先注册约定好的方法,然后再调用。

JS调用OC方法

oc代码(有误,内存不释放):

@interfaceViewController(){    WKWebView * webView;    WKUserContentController* userContentController;}@end

@implementationViewController

#pragma mark - lifeCircle

- (void)viewDidLoad {    [superviewDidLoad];//配置环境WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];    userContentController =[[WKUserContentController alloc]init];    configuration.userContentController= userContentController;    webView = [[WKWebView alloc]initWithFrame:CGRectMake(0,0,100,100) configuration:configuration];//注册方法[userContentController addScriptMessageHandler:selfname:@"sayhello"];//注册一个name为sayhello的js方法[self.viewaddSubview:webView];    [webView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.equalTo(self.view);        make.right.equalTo(self.view);        make.top.equalTo(self.view);        make.bottom.equalTo(self.view);    }];    webView.UIDelegate=self;    webView.navigationDelegate=self;    [webView loadRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.test.com"]]];}

- (void)dealloc{//这里需要注意,前面增加过的方法一定要remove掉。[userContentController removeScriptMessageHandlerForName:@"sayhello"];}

#pragma mark - WKScriptMessageHandler

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);}

@end

上面的OC代码如果认证测试一下就会发现dealloc并不会执行,这样肯定是不行的,会造成内存泄漏。原因是[userContentController addScriptMessageHandler:self name:@"sayhello"];这句代码造成无法释放内存。(ps:试了下用weak指针还是不能释放,不知道是什么原因。)因此还需要进一步改进,正确的写法是用一个新的controller来处理,新的controller再绕用delegate绕回来。

functionsay(){//前端需要用 window.webkit.messageHandlers.注册的方法名.postMessage({body:传输的数据} 来给native发送消息window.webkit.messageHandlers.sayhello.postMessage({body:'hello world!'});}

hello world

say hello

打印出的log:

name:sayhello body:{    body ="hello world!";} frameInfo: { URL: http://www.test.com/ }>

注意点

addScriptMessageHandler要和removeScriptMessageHandlerForName配套出现,否则会造成内存泄漏。

h5只能传一个参数,如果需要多个参数就需要用字典或者json组装。

oc调用JS方法

代码如下:

- (void)webView:(WKWebView *)tmpWebView didFinishNavigation:(WKNavigation *)navigation{//say()是JS方法名,completionHandler是异步回调block[webView evaluateJavaScript:@"say()"completionHandler:^(id_Nullable result,NSError* _Nullable error) {NSLog(@"%@",result);    }];}

h5代码同上。

WebViewJavascriptBridge

一般来说,一个好的UI总有一个大神会开发出一个好的第三方封装框架。WebViewJavascriptBridge的作者也做了一套支持WKWebView与JS交互的第三方框架:WKWebViewJavascriptBridge。

cocoaPods:pod 'WebViewJavascriptBridge', '~> 5.0.5'

github地址:https://github.com/marcuswestin/WebViewJavascriptBridge

主要方法如下:

//初始化方法

+ (instancetype)bridgeForWebView:(WKWebView*)webView;

+ (void)enableLogging;

//注册函数名

- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler;

//调用函数名

- (void)callHandler:(NSString*)handlerName;

- (void)callHandler:(NSString*)handlerName data:(id)data;

- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback;

//重置

- (void)reset;

//设置WKNavigationDelegate

- (void)setWebViewDelegate:(id)webViewDelegate;

你可能感兴趣的:(WKWebview替代UIWebView之简单攻略)