文章目录
WKUserContentController
Api
1、向js注入方法
/*! @abstract Adds a user script.
@param userScript The user script to add.
*/
- (void)addUserScript:(WKUserScript *)userScript;
/*! @abstract Removes all associated user scripts.
*/
- (void)removeAllUserScripts;
这两个方法,提供向js方法注入和移除注入方法的功能。WKUserScript里有个source属性,就是被注入的js代码字符串。
2、添加/移除js端消息的监听回调
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
/*! @abstract Removes a script message handler.
@param name The name of the message handler to remove.
*/
- (void)removeScriptMessageHandlerForName:(NSString *)name;
WKScriptMessageHandler是一个协议类,这两个方法一个是添加代理,一个是移除代理。添加代理后实现代理方法来接收js端的消息
代理WKScriptMessageHandler的方法
/*! @abstract Invoked when a script message is received from a webpage.
@param userContentController The user content controller invoking the
delegate method.
@param message The script message received.
*/
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
添加协议后,通过此方法接收js端的消息回调。
OC与js交互
向js注入方法
向js端注入方法的目的是在移动端对js端的业务做处理,比如下面的代码是向js注入方法,给js的关闭按钮添加了一个监听,当web上点击关闭按钮时,js会将事件通过- userContentController: didReceiveScriptMessage:
方法回调过来。
也可以不注入方法,js端实现方法后向移动端直接通信,我们和js端约定还一个script message handler的name值,通过WKScriptMessageHandler这个协议来接收关闭消息。
还是通过- userContentController: didReceiveScriptMessage:
方法接收关闭按钮事件。
addUserScript
//创建webView的时候注入方法
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
NSString *script = @"document.querySelector('.close-btn').addEventListener('click',function() {window.webkit.messageHandlers.toServer.postMessage('close')},false)";
WKUserScript *userScript = [[WKUserScript alloc] initWithSource:script injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
[config.userContentController addUserScript:userScript];
self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 20, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)-20) configuration:config];
self.webView.navigationDelegate = self;
[self.view insertSubview:self.webView atIndex:0];
这种方式在- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
方法中执行是不会被注入成功的。
evaluateJavaScript
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
NSLog(@"load finished");
//向js注入关闭按钮事件监听
NSString *script = @"document.querySelector('.close-btn').addEventListener('click',function() {window.webkit.messageHandlers.toServer.postMessage('close')},false)";
[webView evaluateJavaScript:script completionHandler:^(id object, NSError * _Nullable error) {
NSLog(@"evaluateJavaScript error : %@",error);
}];
}
注入方法之后,还需要添加js消息回调的代理,实现协议方法,才能收到js端传来的消息。
添加代理
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//添加代理(WKScriptMessageHandler)
[self.webView.configuration.userContentController addScriptMessageHandler:self name:kScriptMessageHandlerWithname];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
//移除代理
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:kScriptMessageHandlerWithname];
}
这里的kScriptMessageHandlerWithname这个宏是一个与js端约定好的字符串。
实现协议方法
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
if (message.body)
{
if ([message.name isEqualToString:kScriptMessageHandlerWithname])
{
//Code...
}
}
}
OC与js互动传值
OC向js传值
1、如果不考虑安全性问题,直接拼接到链接里
比如网页需要一个用户id,直接拼URL里面也还可以,做法比较low,能实现业务。
这种传值好处就是不必等webView完全加载完就可以传。
2、js交互方法
使用OC与js交互的方法,调用js端的方法,将值作为参数传给js端。
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
NSString *string = [NSString stringWithFormat:@"getUserId('%@')",self.userId];
[webView evaluateJavaScript:string completionHandler:^(id _Nullable, NSError * _Nullable error) {
}];
}
这里的getUserId是js端已实现的一个方法,参数是传用户id。
js向OC传值
同理js交互。
注入js报错调试
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
NSLog(@"load finished");
NSString *script = @"document.querySelector('.close-btn').addEventListener('click',() => {window.webkit.messageHandlers.toServer.postMessage('{\"event\":\"close\"}')},false)";
[webView evaluateJavaScript:script completionHandler:^(id object, NSError * _Nullable error) {
NSLog(@"evaluateJavaScript error : %@",error);
}];
}
OC向js注入方法报错
evaluateJavaScript error : Error Domain=WKErrorDomain Code=4 “A JavaScript exception occurred” UserInfo={NSLocalizedDescription=A JavaScript exception occurred}
语法不支持 “=>”
改成
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
NSLog(@"load finished");
NSString *script = @"document.querySelector('.close-btn').addEventListener('click',function() {window.webkit.messageHandlers.toServer.postMessage('close')},false)";
[webView evaluateJavaScript:script completionHandler:^(id object, NSError * _Nullable error) {
NSLog(@"evaluateJavaScript error : %@",error);
}];
}
用浏览器调试,手机上run之后,打开浏览器,在开发–>iPhone–>选择对应的链接,可打开调试工具调试。
OC与js经验总结
- 尽量不使用注入js代码的方式
尽量避免向js端注入代码,一些事件需要传值或者通知到移动端,双方定义好script message handler的name值,移动端注册监听,接收js端消息。这种方法比移动端向js端注入js代码实现更加纯粹,而且简单。
- js传值使用json格式的数据
为了通信方便
洋洋洒洒一大篇文字,比较乱,凑合看。