关闭

UIWebView中Objective-C与JavaScript交互

标签: UIWebView中Objective-
136人阅读 评论(0) 收藏 举报
分类:

UIWebView中Objective-C与JavaScript交互

image

现在越来越多的项目为了支持公司业务的发展而选择使用HTML5做一些功能,那么这样就会涉及到HTML5与原生Objective-C的交互,今天就聊聊HMTL与原生之间的相互调用问题。

概述

原生与Web页面的交互可以分为Objective-C执行JavaScript代码和Web页面(或JavaScript)执行Objective-C代码,前者相对非常简单,后面可以通过JavaScriptCore、拦截协议等方式实现,下面我将主要对这二种方式进行叙述。

Objective-C执行JavaScript代码

打开UIWebView的头文件我们可以发现有一个方法叫stringByEvaluatingJavaScriptFromString:,它就是Objective-C执行JavaScript代码的通路,并且要注意它的返回值是NSString,这个方法在平时非常实用,列举几个例子:

// 获取当前页面的title
NSString *title = [webview stringByEvaluatingJavaScriptFromString:@"document.title"];

// 获取当前页面的可高度
float offsetHeight = [[webview stringByEvaluatingJavaScriptFromString:@"document.body.offsetHeight"] floatValue];

// 获取需要分享的类内
NSString *sharedDictionary = [webview stringByEvaluatingJavaScriptFromString:@"getSharedContent"];

JavaScript执行Objective-C代码

JavaScript执行Objective-C代码之前我就说过有二种方式,现在我分别来说说这二种方式。

1. 利用JavaScriptCore来执行Objective-C代码

iOS7之后苹果推出了JavaScriptCore这个框架,从而让Web页面和本地原生应用交互起来非常方便,而且使用此框架可以做到Android那边和iOS相对统一,web前端写一套代码就可以适配客户端的两个平台,从而减少了Web前端的工作量。

Web前端

在三端交互中,web前端要强势一些,一切传值、方法命名都按web前端开发人员来定义,让另外两端去做适配。在这里以调用分享为例来详细讲解,测试网页代码取名为shared.html,其代码内容如下:

shared.html代码内容

<!doctype html>
<html>
<head>
    <meta charset="utf-8" />
    <title>js调用objective-c代码</title>
    <style type="text/css">
        #backButton { 
            display: inline-block;
            width:50px; height:30px;
        }
    </style>
</head>

<body>
    <button id="backButton">返回</button>
    <script type="text/javascript">

        var btn = document.getElementById('backButton');

        btn.addEventListener('click', function() {
           callBackObj.letsGoBack();
        });
    </script>
</body>
</html>
iOS

iOS这边根据前端定义的方法名来写代码,但是有些时候web前端会让我们定义,但是我们定义好之后他又要修改,这时候就会很烦啊。所以碰到三端交互的时候最好就是让web前端去定义方法名,iOS和Android根据web前端定义好的去写代码。JavaScriptCore中web页面调用原生应用的方法可以用Delegate或Block两种方法,此文以按Delegate讲解。

JavaScriptCore中类及协议:

JSContext:给JavaScript提供运行的上下文环境
JSValue:JavaScript和Objective-C数据和方法的桥梁
JSManagedValue:管理数据和方法的类
JSVirtualMachine:处理线程相关,使用较少
JSExport:这是一个协议,如果采用协议的方法交互,自己定义的协议必须遵守此协议

ViewController中的代码

- (void)webViewDidFinishLoad:(UIWebView *)webView {

    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    [context setExceptionHandler:^(JSContext *ctx, JSValue *value) {
    NSLog(@"error: %@", value);
}];

    context[@"callBackObj"] = self;
}

- (void) letsGoBack {
    [self.navigationController popViewControllerAnimated:YES];
}

ViewController中的代码解释

看到上面的代码我们可以看到设置了context中的callBackObj为self,通过这样的设置js在使用callBackObj.letsGoBack时其实等价于在viewController中使用[self letsGoBack]。

运行效果如图所示

image

拦截协议

首先我说解释一下什么是协议,协议是共同计议的规定,是大家一起遵循的准则。拦截协议这个非常适合各个平台,不需要引入什么框架,只需要大家相互之间遵守协议就可以了。那么在我们团队中协议是怎么定义的呢?scheme://model/aciton?{参数1}={数值1}&{参数2}={数值2}&…,比如在金蛋中分享的协议会是:jindanlicai://active/shared?callback=result(‘%s’,‘%s’)&function=getContent()。其中,function的值是可以获取分享内容的JavaScript函数名称,callback的值是分享结束之后调用的方法来告知HTML5是否分享成功与失败状态。

web前端

home.html中的代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <div>
            <input type="button" value="分享" onclick="share()">
        </div>

        <script>
        function share() {
            window.location.href = 'jindanlicai://active/shared?callback=result('%s','%s')&function=getContent()';
        }
        </script>
    </body>
</html>

home.html中的代码解释

通过点击分享按钮将会调用JavaStript中的share(),window.location.href这里是改变主窗口的指向从而马上发出一个链接为‘jindanlicai://active/shared?callback=result(‘%s’,‘%s’)&function=getContent()’请求,而在iOS方法中我们要拦截这个请求,根据URL请求内容去判断Web页面想要原生做的事情,从而实现web页面和本地应用之间的交互。

iOS

iOS对应的代码

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSString *url = request.URL.absoluteString;
    if ([[request.URL scheme] isEqualToString:@"jindanlicai"]) {
        [JDOpenURL handlerURL:request.URL context:self];
        return NO;
    }
    return YES;
}

iOS对应的代码的解释

在webView的代理方法中去拦截URL的scheme为自定义jindanlicai协议,调用原生提前约定好的方法,并且返回值为NO来阻止此链接的跳转。

总结

随着手机硬件的配置越来越强大和HTML5的兴起,一个App完全可以由web页面来写。现在在我们公司已经有很多的App已经完全是这么干了,iOS和Android只是给这个App套一个壳并通过一些协议去实现一些本地逻辑。协议是一个非常不错的方法,在这我推荐使用协议去做这样的事,当前提前是你要非常理解协议。如果有人喜欢协议,WebViewJavaScriptBridge是一个不错的第三库。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:170682次
    • 积分:2290
    • 等级:
    • 排名:第17046名
    • 原创:5篇
    • 转载:355篇
    • 译文:0篇
    • 评论:13条
    文章分类
    最新评论