美文网首页iOS学习笔记iOS开发技术
JavaScript与 OC 的交互使用

JavaScript与 OC 的交互使用

作者: ZYiDa | 来源:发表于2018-07-25 11:01 被阅读29次

    如果没有接触过 JavaScript 的可以在这里看看JavaScript菜鸟教程,我也是在上面学习的JavaScript
    在这里以WKWebView为主。

    第一步,创建WKWebView并配置:

    • 导入头文件
      #import <WebKit/WebKit.h>
      #import <JavaScriptCore/JavaScriptCore.h>
    • delegate

      <WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler>
    • WKWebView 对象
    - (WKWebView *)wkWebview
    {
        if (_wkWebview == nil)
        {
            
            WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
            //TODO:设置偏好设置
            config.preferences = [[WKPreferences alloc] init];
            //1-默认为0
            config.preferences.minimumFontSize = 80;
            //2-JavaScript 是否可用,默认认为YES
            config.preferences.javaScriptEnabled = YES;
            //3-在iOS上默认为NO,表示不能自动通过窗口打开
            config.preferences.javaScriptCanOpenWindowsAutomatically = YES;
            config.processPool = [[WKProcessPool alloc] init];
            config.userContentController = [[WKUserContentController alloc] init];
            
    
        
    
            _wkWebview = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT==812?(HEIGHT - 34):HEIGHT)
                                           configuration:config];
            _wkWebview.UIDelegate = self;
            _wkWebview.navigationDelegate = self;
            _wkWebview.backgroundColor = [UIColor clearColor];
            _wkWebview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
            _wkWebview.multipleTouchEnabled = YES;
            _wkWebview.autoresizesSubviews = YES;
            _wkWebview.scrollView.alwaysBounceVertical = YES;
            _wkWebview.allowsBackForwardNavigationGestures = YES;/**这一步是,开启侧滑返回上一历史界面**/
            [self.view addSubview:_wkWebview];
        }
        return _wkWebview;
    }
    

    第二步、监听网页上的弹窗事件并回传信息

    JavaScript弹窗分为三种,alert警告框confirm确认框prompt提示窗。在 Objective-C中分别有对应的方法来接收和响应他们的操作并且回传需要的信息。

    alert警告框
    #pragma mark 接收网页端过来的 alert 信息
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *confirm = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            
        }];
        [alert addAction:confirm];
        [self presentViewController:alert animated:YES completion:nil];
        completionHandler();
    }
    
    confirm确认框
    #pragma mark 接收确认框信息,并提交操作
    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{    
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *confirm = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(YES);
        }];
        UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(NO);
        }];
        
        [alert addAction:confirm];
        [alert addAction:cancel];
        [self presentViewController:alert animated:YES completion:nil];
    }
    
    prompt提示窗
    #pragma mark 接收网页端 prompt 信息,并提交输入内容
    - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler{    
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:prompt preferredStyle:UIAlertControllerStyleAlert];
        [alert  addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
            
        }];
        UIAlertAction *confirm = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(alert.textFields[0].text);
        }];
        UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(@"");
        }];
        
        [alert addAction:confirm];
        [alert addAction:cancel];
        [self presentViewController:alert animated:YES completion:nil];
    }
    

    第三步、响应其它网页端事件,接收JavaScript传递过来的值。

    如下,html 中有一个 button 元素,它响应的JavaScript函数为eoc()

    <button id="btn4" style="width:80%;height: 88px;padding: inherit" type="button" onClick="eoc()">
        Action01    
    </button>
    
    <script>
      function eoc(){
      }
    </script>
    

    如何在OC端响应这个消息呢?

    • 我们可以采取类似OC中观察者模式的方式,在eoc()中添加 window.webkit.messageHandlers.htmlAction01.postMessage('点击了第一个按钮');来向OC发送一条信息,具体的格式为:
      window.webkit.messageHandlers.ActionObjectName.postMessage('所需传递的值或信息');
    • OC中通过WKWebView添加消息监听,具体为
    //4-在这里设置监听代理,监听 JavaScript 对象的发出的信息
    [config.userContentController addScriptMessageHandler:self name:@"htmlAction01"];
    [config.userContentController addScriptMessageHandler:self name:@"htmlAction02"];
    [config.userContentController addScriptMessageHandler:self name:@"htmlAction03"];
    
    • 在代理方法中做出操作
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
        if ([message.name isEqualToString:@"htmlAction01"]) {
            NSLog(@"*01***%@***",message);
        }else if ([message.name isEqualToString:@"htmlAction02"]){
            NSLog(@"*02***%@***",message);
        }else if ([message.name isEqualToString:@"htmlAction03"]){
            NSLog(@"*03***%@***",message);
        }
            [self alertWithMessage:message.body];
    }
    

    第四步、JavaScript响应OC的消息,接收传递过来的值

    • 添加新元素节点
    - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
    

    具体的使用:

    NSString *jsValue = @"var ne = document.createElement('button');
                          var nc = document.createTextNode('后来添加的button');
                          ne.addEventListener('click',function(){alert('这是新添加 btn 的测试弹窗')});
                          ne.appendChild(nc);
                          document.getElementById('bby').appendChild(ne);"
    [webView evaluateJavaScript:jsValue completionHandler:^(id _Nullable response, NSError * _Nullable error) {
            NSLog(@"*001***** %@ *****error:%@",response,error);
        }];
    

    上面的操作会找到idbby的元素,并向这个元素节点之中添加一个button元素,同时这个button元素会响应function(){alert('这是新添加 btn 的测试弹窗')这个操作;

    • 传值给JavaScript

    方式一:
    在网页端有这样一个函数

    function userLogin(isLogin){
        alert(isLogin?"用户已登录":"用户未登录");
    }
    

    OC端的操作

     NSString *jsValue = [NSString stringWithFormat:@"userLogin(%d)",YES];
     [self.wkWebview evaluateJavaScript: jsValue completionHandler:^(id _Nullable response, NSError * _Nullable error) {
         NSLog(@"*002***** %@ *****error:%@",response,error);
    }];
    

    • 方式二
    NSString *jsValue = @"confirm('{name:Tom,age:18,height:188}');";
     [self.wkWebview evaluateJavaScript: jsValue completionHandler:^(id _Nullable response, NSError * _Nullable error) {
        NSLog(@"*003***** %@ *****error:%@",response,error);
    }];
    

    不足的地方,还请多多指教,谢谢了。



    更新:经过一位大神同学指导,
    关于JavaScript调用 原生方法
    因为window.webkit.messageHandlers.ActionObjectName.postMessage('所需传递的值或信息');只在第一次注册时有效,且可能会随着代码量的增加要注册很多个,这样就麻烦一些了。
    所以,当我们想通过JavaScript调用 原生方法且需要回传值时,可以在JavaScript端对prompt的参数进行封装(大神同学采取的是对prompt封装,我暂时没有看懂他写的,就对prompt的参数进行了封装),这样就能在不注册window.webkit.messageHandlers.ActionObjectName.postMessage('所需传递的值或信息');的时候随时调用 原生方法。
    思路:

    JavaScript

    function bridge(nativeMethod,otherParams,isNativeMethod,promptStr){
            var txt = {
                'nativeMethod':nativeMethod,
                'otherParams':otherParams,
                'isNativeMethod':isNativeMethod,
                'promptStr':promptStr
            };
            console.log(JSON.stringify(txt));
            return prompt(JSON.stringify(txt),'');
        }
    

    Objective-C
    在原生端,可以根据isNativeMethod参数来判断是调用原生方法,还是弹起弹窗。
    nativeMethod参数是所要调用原生方法的方法名字符串,通过NSSelectorFromString(<#NSString * _Nonnull aSelectorName#>)转为为原生方法。
    otherParams是其它需要传递的参数。
    promptStr是弹窗的提示信息。

    相关文章

      网友评论

        本文标题:JavaScript与 OC 的交互使用

        本文链接:https://www.haomeiwen.com/subject/zeaumftx.html