UIWebView之OC与JS相互调用

UIWebView简介

UIWebView是iOS8之前常用的用来加载H5的控件,iOS8之后出现了WKWebView,但是如果需要适配iOS7的同学,还是需要用到UIWebView

UIWebView加载

HTML代码,将HTML添加到工程中

<html>
    <header>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript">
            function btnClick() {
                ret = JSInvokeOC('args1','args 2','args3');
                alert(ret);
            }

            function btnClick1() {
                ret = OCObj.test();
                alert(ret);
            }


            function OCInvokeJS(message){
                alert(message);
                return 'OCInvokeJS return';
            }

        </script>
    </header>

    <body>
        <h2> OC&JS相互调用 </h2>
        <br/>
        <a href="aima://smsLogin?username=110&code=120">JS调用OC之URL拦截</a>
        <br/>
        <button type="button" onclick="btnClick()">JS调用OC之JSContext-block</button>
        <br/>
        <button type="button" onclick="btnClick1()">JS调用OC之JSExport</button>
        <br/>
    </body>
</html>

工程编译后,HTML会在根目录下,加载HTML到WebView

    //加载本地MyWebView.html
    NSString *basePath = [[NSBundle mainBundle]bundlePath];
    NSString *helpHtmlPath = [basePath stringByAppendingPathComponent:@"MyWebView.html"];
    NSURL *url = [NSURL fileURLWithPath:helpHtmlPath];
    //就是这么简单,load一下就可以了
    [self.webView loadRequest:[NSURLRequest requestWithURL:url]];

JS调用OC之URL拦截法

实现UIWebView下面的代理方法,WebView中发生的每次跳转都会先调用该代理方法,如果返回YES,则正常跳转,如果返回NO,则不跳转

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if ([request.URL.absoluteString containsString:@"aima://smsLogin"]) {   //aima://smsLogin?username=110&code=120
        NSLog(@"url parameters:%@", request.URL.query);     //username=110&code=120
        return NO;
    }    
    return YES;
}

JS调用OC之javaScriptCore

javaScriptCore.framework是从iOS7开始引入的框架,该框架让 Objective-CJavaScript 代码直接的交互变得更加的简单方便。

    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
    context[@"JSInvokeOC"] = ^(NSString *str1, NSString *str2, NSString *str3) {
        NSLog(@"Arguments:%@, %@, %@", str1, str2, str3);
        return @"JS调用了OC方法";
    };

JS调用OC之JSExport

JSExportjavaScriptCore.framework中提供的OC&JS交互方法,如果说上面JSContextblock方法,是对JS暴露一个方法,那么JSExport就是对JS暴露了一个对象,个人感觉JSExport的方式对于OC和JS开发者来说都更加规范,代码更加清晰。

首先声明一个自定义的协议并继承自JSExport协议。

@protocol TestJSExport <JSExport>
- (NSString *)test;
@end

然后实现这个自定义协议,然后JS就能像使用原生对象一样使用OC对象了。

@interface ViewController ()<UIWebViewDelegate, TestJSExport>
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@end

@implementation ViewController
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    context[@"OCObj"] = self;
//点击HTML上 JS调用OC之JSExport 按钮,就会调用下面的test方法了
}

- (NSString *)test {
    return @"JS 调用了OC的test方法";
}

@end

OC调用JS之UIWebView原生方法

//该方式调用方法简单
//但属于同步方法,会阻塞线程直到返回
//方法虽然未被废弃但帮助文档中已建议放弃该方式
//方法执行错误会直接返回nil
NSString *ret = [self.webView stringByEvaluatingJavaScriptFromString:@"OCInvokeJS('wocao')"];

OC调用JS之javaScriptCore

    //获取webView中的JavaScript上下文
    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    NSString *textJS = @"OCInvokeJS('WOCAO')";
    //直接调用即可,如果方法未实现会返回'undefined'
    //经测试,方法也是同步方法
    JSValue *ret = [context evaluateScript:textJS];

参考

深入浅出 JavaScriptCore
iOS中UIWebView与WKWebView、JavaScript与OC交互、Cookie管理看我就够

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容