iOS中Objective-C与JavaScript之间相互调用的实现(实

来源:http://www.chinese-glasses.com 作者:Web前端 人气:139 发布时间:2020-04-15
摘要:时间: 2019-10-01阅读: 132标签: 原生一、前言 最近在iOS项目中需要使用到oc与js之间的相互调用,而且要求是实现方式必须与Android中的相同,方便js中统一处理。于是在对第三方库WebViewJa

时间: 2019-10-01阅读: 132标签: 原生一、前言

最近在iOS项目中需要使用到oc与js之间的相互调用,而且要求是实现方式必须与Android中的相同,方便js中统一处理。于是在对第三方库WebViewJavascriptBridge进行研究之后,仿照Android中的WebView与JS的交互机制,实现了一个,在这里分享给大家。

现在市面上有一些app是通过原生ios、Android加载一个网页实现的,如图所示,这样的app我们称之为 Hybrid App

首先要说明的是,在iOS中js调用Objective-C的代码只能通过重定向的形式进行,即js中通过修改iframe的src,或者直接跳转到一个url,在Objective-C中通过UIWebView的

那么为什么要用 hybrid app呢? 个人认为的原因有两点:

webView:shouldStartLoadWithRequest:navigationType:方法拦截这个跳转,然后通过解析跳转的url获取js需要调用的方法名和参数。而在Android中,只需要调用WebView的addJavascriptInterface方法,将一个js对象绑定到一个java类,在类中实现相应的函数,当js需要调用java的方法时,只需要直接在js中通过绑定的对象调用相应的函数即可。

1.提高开发效率,以钉钉为例在涉及到一些OA操作比如打卡,请假等功能的时候,显然一个嵌入一个网页就能够满足需求,如果在让IOS和Android再去各自开发一套那么效率就很低了。2.提高迭代效率。以商城为例,商城页面会根据市场情况实时发生变化,比如遇到各种节假日活动做促销。那么这个时候如果用原生,那么迭代等用户去升级可能这个活动都已经过了,但是用嵌套webview嵌套一个网页只需要网页做出修改hybrid app内的web页面就会马上修改,这样效率就非常高了。

显然Android中js交互的方式要比iOS上方便得多,因此,我们可以在iOS上实现一套与Android相类似的机制。下面先说明一下实现的原理,要在js中直接通过绑定的对象调用相应的函数,那么就需要在js中添加相应的代码,但是为了确保与Android的一致性,js代码应该在客户端以注入的形式加入。所以,我们先实现一下需要注入的代码:

hybrid app 实际上就是利用原生的组件webview加载一个url再让js和原生相互调用实现各种功能,那么接下来我就把js和原生相互调用的情况做一个总结。

;(function() {
    var messagingIframe,
        bridge = 'external',
        CUSTOM_PROTOCOL_SCHEME = 'jscall';

    if (window[bridge]) { return }

 function _createQueueReadyIframe(doc) {
        messagingIframe = doc.createElement('iframe');
  messagingIframe.style.display = 'none';
  doc.documentElement.appendChild(messagingIframe);
 }
 window[bridge] = {};
    var methods = ["test1", "test2"];
    for (var i=0;i

二、原生api实现:js和原生相互调用

在以上代码中,我们在网页中添加了一个iframe,使得改变iframe的src时webview可以捕捉到重定向请求,使用这种方式进行重定向,相比直接修改网页的url要安全得多。同时设置了一个external对象,并为该对象绑定了test1、test2方法,当这两个方法执行时,会修改iframe的src,并将要调用的方法和参数以url的形式来构造。然后,我们需要在webview完成网页加载的时候进行注入,实现以下委托:

要想让js和原生相互调用,对于webview最基本的一个设置就是要允许js脚本执行

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    //js是否注入成功
    if (![[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"typeof window.%@ == 'object'", kBridgeName]] isEqualToString:@"true"]) {
        NSBundle *bundle = _resourceBundle ? _resourceBundle : [NSBundle mainBundle];
        NSString *filePath = [bundle pathForResource:@"WebViewJsBridge" ofType:@"js"];
        NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
        [webView stringByEvaluatingJavaScriptFromString:js];
    }
}
 WebSettings settings = mWebView.getSettings(); settings.setJavaScriptEnabled(true);

注意,以上代码在注入前需要判断是否已经注入,避免重复注入。接下来,我们可以再实现一个webview的委托来拦截重定向事件:

(一)、js调用原生

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *url = [request URL];

    NSString *requestString = [[request URL] absoluteString];
    if ([requestString hasPrefix:kCustomProtocolScheme]) {
        NSArray *components = [[url absoluteString] componentsSeparatedByString:@":"];

        NSString *function = (NSString*)[components objectAtIndex:1];
        NSString *argsAsString = [(NSString*)[components objectAtIndex:2]
                                  stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSData *argsData = [argsAsString dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary *argsDic = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:argsData options:kNilOptions error:NULL];
        //将js的数组转换成objc的数组
        NSMutableArray *args = [NSMutableArray array];
        for (int i=0; i

以上代码中对重定向的url进行了判断,如果符合我们事先定义的协议,就进行解析,否则就进行跳转。解析的时候以冒号分隔,取出函数名和参数列表,并调用相应的方法。至此,我们就在iOS中实现了与Android相同的调用机制。
但以上方法的缺点是还没有达到Android中的方便程度,最理想的方法是当进行js注入时,动态设置待绑定的对象,同时动态获取当前类的实例方法,并生成相应的js代码。这就完全实现了Android中的绑定机制。这个实现起来并不难,有兴趣的朋友可以试试。为了方便大家使用,我将以上代码封装成了一个类,具体的使用方法见Demo。需要注意的是:1. 在实际应用中可能出现js执行顺序的问题,如果网页中的js在注入前先获取绑定的对象进行保存,是无法获取到的,因为这时候待绑定的对象为空。这就需要网页中js的初始化在注入之后,因此在上文代码中有一个initReady方法。2. 由于performSelector最多只能包含两个参数,因此例子中是通过数组来传递参数列表的。


如果大家觉得对自己有帮助的话,还希望能帮顶一下,谢谢:)

个人博客:http://blog.csdn.net/zhaoxy2850
本文地址:http://blog.csdn.net/zhaoxy_thu/article/details/22794201
转载请注明出处,谢谢!




http://www.bkjia.com/Javascript/749424.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javascript/749424.htmlTechArticle最近在iOS项目中需要使用到oc与js之间的相互调用,而且要求是实现方式必须与Android中的相同,方便js中统一处理。于是在对第三方库WebVi...

假设我现在有一个需求:点击web中的一个按钮,将web中的值传递给原生并在TextView组件中显示出来。那么这个需求怎么实现呢?

第一步:在java代码中定义js要调用的方法

 // 定义JS需要调用的方法 // 被JS调用的方法必须加入@JavascriptInterface注解 @JavascriptInterface public void sendMsg(String msg) {// Log.i(TAG, "JS调用了Android的hello方法" + msg);// Toast.makeText(mContext, "JS调用了Android的hello方法" + msg, Toast.LENGTH_SHORT).show(); //为了方便拿到上下文和ui组件,写一个回调接口。 mJSBridge.sendMsg(msg); }

这里需要说明的是,1.要在方法上面添加“@JavascriptInterface”注解,2.定义的方法必须是公共方法

第二步:给webview添加js脚本接口。

 mWebView.addJavascriptInterface(jsInterface, "Android_Interface");

void addJavascriptInterface (Object object, String name),这个方法有两个参数,第一个是一个注入webview中js上下文的java对象,第二个参数是在js脚本中来暴露的名称对象,也就是说,这里写什么,待会在js调用原生的时候就写什么。

第三步:用js调用原生方法

function sendMsg() { Android_Interface.sendMsg("你好,这是要传递的参数")}

(二)、原生调用js

原生调用js中的方法,例如,在这里我们实现点击原生中的按钮来改变web中div的样式。那么这个该如何实现呢?

这里直接使用webview的api就能够实现。Android中的代码如下:

// 第一种调用js中代码的方法// mWebView.loadUrl("javascript:beStronger()");//第二种调用js中代码的方法,同时传值过去 mWebView.evaluateJavascript("javascript:beStronger(‘" + str + "‘)", new ValueCallbackString() { @Override public void onReceiveValue(String value) { //此处为 js 返回的结果 Toast.makeText(H5Activity.this, value, Toast.LENGTH_SHORT).show(); } });

在web中的代码如下:

function beStronger(value) { let box = document.getElementById("box"); // box.innerText = value; box.className = "box2"; box.innerText=value; return "小明你好"}

本文由10bet发布于Web前端,转载请注明出处:iOS中Objective-C与JavaScript之间相互调用的实现(实

关键词:

上一篇:Mixin 和 CSS Guards

下一篇:没有了

频道精选

最火资讯