美文网首页iOS之功能细节iOS Tips架构师之路
UIWebView 与 JS 交互(1):Objective-C

UIWebView 与 JS 交互(1):Objective-C

作者: OneAPM | 来源:发表于2016-03-02 16:25 被阅读287次

    众所周知,随着硬件水平的发展,HTML5 与原生 APP 性能差距不断缩小,正在互联网科技领域扮演者越来越重要的角色。作为一种能很大程度上节约成本的技术方案,通过 HTML5 及 JS 实现的跨平台技术也越来越成熟。

    作为一名普通的 iOS 开发者,我们在项目中也会或多或少的用到一些 JS 代码,如何实现 JS 和 OC 之间的交互常常是我们会面临的一个问题。最近一段时间,笔者最近由于工作需要,研究了很多 iOS 下与 JS 交互的问题,接下来我会把这个过程中遇到的坑和积累的经验分享给大家。

    第一个要说的就是如何在 OC 下调用 JS,这个很简单,想必大家都会不约而同的回答出,使用 UIWebView 的stringByEvaluatingJavaScriptFromString 方法。

    接下来我从自己的实际经历聊一下如何使用stringByEvaluatingJavaScriptFromString调用javascript

    1、 stringByEvaluatingJavaScriptFromString只能在主线程执行。

    比如,假如你调用了下面这段代码:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        [webView stringByEvaluatingJavaScriptFromString:@"aaa"];
    });
    

    程序就会崩溃,并打出下面的log:

    崩溃产生的原因是你在主线程以外的线程调用了UIKit,系统在执行stringByEvaluatingJavaScriptFromString的时候调用了UIKit里的一些方法,所以不允许在主线程之外的线程去调用这个方法。

    解决方法也有很多可以用

    [webView performSelectorOnMainThread:]
    

    或者

    dispatch_sync(dispatch_get_main_queue(), ^{
        [webView stringByEvaluatingJavaScriptFromString:@"aaa"];
    });        
    

    2、简单调用系统提供的javascript方法

    对于一些简单的javascript系统方法,我们可以通过stringByEvaluatingJavaScriptFromString做一下简单的调用,并取得返回值。

    - (void)webViewDidFinishLoad:(UIWebView *)webView
    {
        NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
        NSLog(@"%@", title);
    }
    

    3、在加载的html里插入代码,并执行

    比如我用下面的代码插入了一个名叫alertTest的函数到javascript里实现在页面中显示alert的功能。

    - (void)webViewDidFinishLoad:(UIWebView *)webView
    {
            [webView stringByEvaluatingJavaScriptFromString:
             @"var script = document.createElement('script');"
             "script.type = 'text/javascript';"
             "script.text = \"function alertTest(str) { "
             "alert(str)"
             "}\";"
             "document.getElementsByTagName('head')[0].appendChild(script);"];
             [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"alertTest('%@');", @"test"]];
    }
    

    值得注意的一点是
    - (void)webViewDidFinishLoad:(UIWebView *)webView方法指的并不是webview完全加载完毕,而是指网页中一个iframe或frame加载完毕,也就是说假如网页里有多个frame,那么webViewDidFinishLoad会执行多次。这就会导致上面插入代码的方法会执行多次,stringByEvaluatingJavaScriptFromString执行JS是一笔不小的时间开销,所以我们应该尽量减少使用它去执行复杂的JS代码。

    我使用了下面的方式检查是否已经插入并执行了这个函数,typeof alertTest检查了alertTest这个函数是否存在,若存在则不执行if里面的代码插入和代码执行语句。

    - (void)webViewDidFinishLoad:(UIWebView *)webView
    {
        BOOL isExist = [[webView stringByEvaluatingJavaScriptFromString:@"typeof alertTest == \'function\';"] isEqualToString:@"true"];
        if (!isExist) {
            [webView stringByEvaluatingJavaScriptFromString:
             @"var script = document.createElement('script');"
             "script.type = 'text/javascript';"
             "script.text = \"function alertTest(str) { "
             "alert(str)"
             "}\";"
             "document.getElementsByTagName('head')[0].appendChild(script);"];
            [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"alertTest('%@');", @"test"]];
        }
    }
    

    OneAPM Mobile Insight ,监控网络请求及网络错误,提升用户留存。访问 OneAPM 官方网站感受更多应用性能优化体验,想阅读更多技术文章,请访问 OneAPM 官方技术博客

    本文转自 OneAPM 官方博客

    相关文章

      网友评论

        本文标题:UIWebView 与 JS 交互(1):Objective-C

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