iOS之OC与JS的交互(iOS与H5混编)

1,178 阅读3分钟

现在iOS新提交的app必须使用WKWebView替换UIWebView,下面我们来了解下WKWebView的优势:

  1. 更多的支持HTML5的特性
  2. 官方宣称的高达60fps的滚动刷新率以及内置手势
  3. 将UIWebViewDelegate与UIWebView拆分成了14个类与3个协议,以前很多不方便实现的功能得以实现
  4. Safari相同的JavaScript引擎
  5. 占用更少的内存 类:

WKBackForwardList: 之前访问过的 web 页面的列表,可以通过后退和前进动作来访问到。
WKBackForwardListItemwebview 中后退列表里的某一个网页。
WKFrameInfo: 包含一个网页的布局信息。
WKNavigation: 包含一个网页的加载进度信息。
WKNavigationAction: 包含可能让网页导航变化的信息,用于判断是否做出导航变化。
WKNavigationResponse: 包含可能让网页导航变化的返回内容信息,用于判断是否做出导航变化。 WKPreferences: 概括一个 webview 的偏好设置。
WKProcessPool: 表示一个 web 内容加载池。
WKUserContentController: 提供使用 JavaScript post 信息和注射 script 的方法。
WKScriptMessage: 包含网页发出的信息。
WKUserScript: 表示可以被网页接受的用户脚本。
WKWebViewConfiguration: 初始化 webview 的设置。
WKWindowFeatures: 指定加载新网页时的窗口属性。

协议:

WKNavigationDelegate: 提供了追踪主窗口网页加载过程和判断主窗口和子窗口是否进行页面加载新页面的相关方法。

WKScriptMessageHandler: 提供从网页中收消息的回调方法。 
WKUIDelegate: 提供用原生控件显示网页的方法回调。

加载方式

方式一
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];

[self.view addSubview:webView];
方式二
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc] init];

webView = [[WKWebView alloc] configuration:configuration];

[webView loadRequest:[NSURLRequest URLWithString:@"http://www.baidu.com"]]];

[self.view addSubview:webView];

协议方法介绍:

WKNavigationDelegate
// 页面开始加载时调用

initWithFrame:self.view.bounds requestWithURL:[NSURL

-(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);

}
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:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler{

completionHandler(@"http");
}

确认框

-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{

completionHandler(YES);
}

警告框

-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString
 *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{

NSLog(@"%@",message); completionHandler();
}

OC与JS的交互

WKWebView的 UIDelegate 提供了三个协议方法, 可以让前端很方便的拦截JS的alert, confirm, prompt方法。除此之外,OC,JS互调可以按照如下方法。

1. OC 调用JS

可以使用webkit这个库

- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable idNSError * _Nullable error))completionHandler; 

例如OC调用JS的方法 setName

[webView evaluateJavaScript:@"setname('张三')" completionHandler:nil];

此处 setname为JS定义的方法名, 内部 ‘张三’为传给JS的参数。 如果setname方法需要 传入一个json或者array等非字符参数, 需要用format方法将其转为string类型,在调用 evaluate方法。例如

NSString * para = [NSString stringWithFormat:@"setname('%@')",json];

2. JS调用OC

此时就要用到WKScriptMessageHandler

//首先.m中加入属性

@property (nonatomic ,strong)WKUserContentController * userCC;

1. 遵循WKScriptMessageHandler协议 
2. 初始化

WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc]init];

self.wkWebViw=[[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];

[self.wkWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.webPageUrl]]];

[self.view addSubview:self.wkWebViw];
self.userCC = config.userContentController;
[self.userCC addScriptMessageHandler:self name:@"callOSX"]; //此处相当于监听了JS中callFunction这个方法

[self.userCC addScriptMessageHandler:self name:@"callFunction"];


当JS发出callFunction这个方法指令的时候, WKScriptMessageHandler的协议方法中我们就会收到这个消息

#pragma mark WKScriptMessageHandler delegate

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message

{

//这个回调里面, message.name代表方法名(‘本例为 callFunction’), message.body代 表JS给我们传过来的参数

}

最后, VC销毁的时候一定要把handler移除


- (void)dealloc {

    [_userContentController removeScriptMessageHandlerForName:@"callFunction"]; 
}

对应的JS代码

<button onclick="buttonClick('温馨提示')">点我</button>

<script>
function buttonClick(string){
//JS调用OC, 格式如下 //(window.webkit.messageHandlers.Method_Name.postMessage(parameterToOC))

window.webkit.messageHandlers.callFunction.postMessage(string) }

</script>