WKUserContentController

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格式的数据

为了通信方便

洋洋洒洒一大篇文字,比较乱,凑合看。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Morris_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值