JS与OC 互相调用

1、JS调用OC
如果是结合UIWebview来使用的话,至少有两种方式:
1)地址重定向,定义URL协议。就是将一些要调用的方法和参数拼成URL。然后再去截取解析。使用PerformSelector:方法进行回调。
在加载网页发送请求时会调用webView:shouldStartLoadWithRequest:navigationType: 代理方法。

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSURL *url = [request URL];
    NSString *urlStr = request.URL.absoluteString;
    NSString *scheme = @"test://";
    if ([urlStr hasPrefix:scheme]) {
        // 1.截取方法名称
        // methodName1_methodName2_?param1&param2
        NSString *temp = [urlStr substringFromIndex:scheme.length];
        NSArray *subPaths = [temp componentsSeparatedByString:@"?"];
        NSString *methodName = [subPaths firstObject];
        methodName = [methodName stringByReplacingOccurrencesOfString:@"_" withString:@":"];
        // 2.将截取出来的字符串转换为SEL
        SEL selector = NSSelectorFromString(methodName);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        // 3.切割所有的参数
        if (subPaths.count == 2) {
            NSArray *parms = [[subPaths lastObject] componentsSeparatedByString:@"&"];
            if (parms.count == 2) {
                [self performSelector:selector withObject:[parms firstObject] withObject:[parms lastObject]];
            }else
            {
                [self performSelector:selector withObject:[subPaths lastObject]];
            }
            return NO;
        }
#pragma clang diagnostic pop
        // 3.利用performSelector调用OC方法
        [self performSelector:selector withObject:nil];
        return NO;
    }
    NSLog(@"正在请求");
    return YES;
}

此段代码由于使用的performSelector系列的方法,所以对参数的个数是有限制的。如果需要传递多个参数,那么可以考虑使用NSInvocation这个类。不过在iOS7以后,我们一般就不用这种方式了,而是使用JavaScriptCore.framework框架提供的API来处理。

2)使用JavaScriptCore.framework库
使用JavaScriptCore.framework库进行JS调用OC时,使用jsContext[“js方法名”]就可以完成。因为这个jsContext[“js方法名”]后接一个block,该block中包含要执行的OC代码(block相当于一个匿名的函数,当从JS代码中触发该方法的时候,就相当于js调用了OC的方法)。
下面给出一个应用例子。我们加载一个html网页,当点击该网页中的一个按钮时,触发一段JS函数的调用,该JS函数调用在OC中注册的方法(jsContext[“js方法名”])。该网页的代码如下:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>百度一下,你就知道</title>
        <style type="text/css">

        body{
            width: 375;
            margin: 0;
            padding-bottom: 0;
            padding-left: 20px;
            padding-right: 20px;
            padding-top: 0;
        }
        #baiduimage{
            margin-left: 10%;
            margin-top: 10%;
        }
        form{
            margin-left: 10%;
            margin-top:10px;
        }
        #text{
            width: 200px;
            height: 45px;
            border-color:#39F;
            border-style:solid;
            border-width:1px;
            font-size:12px;
        }
        button{
            width:65px;
            height:50px;
            background-color:#39F;
            font-size: 10px;
        }
        div footer{
            margin-left: 9%;
            margin-bottom: 0%;
            margin-top: 200px;
            margin-bottom: auto;
            font-size: 12px;
        }
        </style>
        <script>
        function repost()
        {
            location.href = "test://sendMessageWithNumber_andContent_?10086&love";
        }
        function sum()
        {
            return 1 + 4;
        }
        function JSLoadOCMethod()
        {
            var str = logForTest("hello jsLoadOCMethod!");
            alert(str);
        }
        </script>
</head>

    <body>
        <div class="all">
            <div>
                <img src="baidu.png"  alt="" width="270" height="129" id="baiduimage"/>
            </div>
            <div>
                <form>
                    <input name="input" type="text" id="text" value="百度一下,你就知道" maxlength="100">
                    <button  onclick="JSLoadOCMethod();">百度一下</button>
                </form>
            </div>
            <div>
                <footer>
                    <span>&copy;2016&nbsp;baidu&nbsp;<a href="http://www.baidu.com/duty/">使用百度前必读</a>&nbsp;京ICP证030173号<img width="13" height="16" data-loadfunc="1" src="copy_rignt_24.png" data-loaded="1"></span>
                </footer>
            </div>
        </div>
    </body>
</html>

加载出来的网页效果如下:
这里写图片描述
当我们点击蓝色的“百度一下”这个按钮时,会触发绑定的函数,然后在该绑定的函数中我们调用了一个logForTest 的函数,而该函数并没有在js代码中实现,但是我们在OC代码中会通过jsContext["logForTest"]进行注册。之后就是触发了jsContext["logForTest"] 所赋值的block代码块。OC的实现代码如下:

- (void)JSLoadOCMethod {
    self.context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    self.context[@"logForTest"] = ^(){
        NSLog(@"Begin Log");
        NSArray *args = [JSContext currentArguments];

        for (JSValue *jsVal in args) {
            NSLog(@"%@", jsVal);
        }

        JSValue *this = [JSContext currentThis];
        NSLog(@"-------End Log----%@---",this);
        return @"Are you OK?";
    };
}

测试的结果如下:
这里写图片描述
在这里同时将OC中block的返回值返回到了所调用的js函数里,并且显示出来。这样也就做到了JS和OC值之间的互相传递。
这里可能有一个注意点,就是JSLoadOCMethod 方法所放的位置,如果你放在控制器的viewDidLoad 方法中,那么不管你点多少次按钮,上面的block只会执行一次。这是因为当我们点击按钮时页面重新加载,所注册的JSContext已经失效。所以如果我们把JSContext的注册放在viewDidLoad 方法中就无法实现JSContext的重新注册。每次重新注册都会执行,webViewDidFinishLoad: 方法,所以我们可以将JSLoadOCMethod 方法放在该方法中。对于我们这种情况,由用户发起触发了一个JS调用OC的方法是没有问题的,但如果你的网页在一开始加载的时候,就要触发这个JS调用OC的方法可能是不合适的,因为webViewDidFinishLoad: 方法还没有执行。其中一个解决方法是:在该方法中触发OC调用JS函数,然后,再由JS函数调用JSContext中注册的方法。

2、OC调用JS
如果是使用UIWebView,那么可以使用它所提供的一个方法stringByEvaluatingJavaScriptFromString: 该方法的参数是一个字符串类型的JS代码。
当然我们也可以使用JavaScriptCore.framework库提供的OC调用JS的API方法。如:evaluateScript:evaluateScript: withSourceURL: 方法。
示例代码:

    JSValue *funcValue = [self.jsContext evaluateScript:@"function OCLoadJS(){ return 'hello OCLoadJS' }; OCLoadJS()"];
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值