美文网首页iOS开发收藏文档IOSiOS
简单- IOS WebView与JS交互方法详解

简单- IOS WebView与JS交互方法详解

作者: Www刘 | 来源:发表于2016-03-25 22:40 被阅读10188次

    最近在做的项目重点就是原生app与js的交互,以前也做过但是并没有深入的了解和研究过,因为这个项目我尝试了三种方式的交互方法,经过实践也更了解每种方法的利弊,再次分享一下希望大家可以批评指正:

    首先分析一下app目前的样式分类原生app和webapp的定义以及优缺点Web App

    Web App即是一种框架型APP开发模式(HTML5 APP 框架开发模式),该开发具有跨平台的优势,该模式通常由“HTML5云网站+APP应用客户端”两部份构成,APP应用客户端只需安装应用的框架部份,而应用的数据则是每次打开APP的时候,去云端取数据呈现给手机用户。

    原生App

    原生APP又称Native App,该开发针对IOS、Android、Windows等不同的手机操作系统要采用不同的语言和框架进行开发,该模式通常是由“云服务器数据+APP应用客户端”两部份构成,APP应用所有的UI元素、数据内容、逻辑框架均安装在手机终端上。

    Hybrid App(混合模式移动应用)

    是指介于web-app、native-app这两者之间的app,兼具“Native App良好用户交互体验的优势”和“Web App跨平台开发的优势”。

    这篇文章作者总结的不错

    WebAPP与原生APP的交互设计区别 - 简书

    http://www.oschina.net/question/585173_2141646

    这篇文章讲述了目前移动开发的趋势:

    为什么移动开发开始用混合app开发(Hybrid App)

    知道了各种形式app的定义却别,也更了解Hybrid App的优势那怎样更好的实现原生与web 的交互呢?

    首先我认为最好的方式

    1. 运用JavaScriptCore框架进行交互

    在iOS 7之后,apple添加了一个新的库JavaScriptCore,用来做JS交互,因此JS与原生OC交互也变得简单了许多。这是我做的一个例子

    1.首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)

    _mJSContext=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    2.异常处理

    _mJSContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {

    context.exception = exceptionValue;

    DLog(@"%@", exceptionValue);

    };

    3.在JS中添加了方法指针提供给JS调用

    @WeakObj(self);

    _mJSContext[@"jSInvokerGetMid"] = ^(void){

    DLog(@"JS获取UUID");

    @StrongObj(self);

    return  self.devie.mac;

    };

    _mJSContext[@"jSInvokerGetLocation"] = ^(void){

    DLog(@"JS获取坐标");

    @StrongObj(self);

    id devicePoint = @{

    @"latitude": [NSString stringWithFormat:@"%f", self.location.coordinate.latitude],

    @"longitude": [NSString stringWithFormat:@"%f", self.location.coordinate.longitude]

    };

    return devicePoint;

    };

    _mJSContext[@"jSInvokerGetUserSgid"] = ^(void){

    DLog(@"JS用户的ID");

    return @"UserId";

    };

    _mJSContext[@"jSInvokerSpeechSubView"] = ^(void){

    DLog(@"将要进行界面跳转由h5界面跳转到原生界面");

    @StrongObj(self);

    NSArray *args = [JSContext currentArguments];

    JSValue * value = args[0];

    NSString * str = value.toString;

    //必须放入主线程中更新UI否则会出错

    dispatch_async(dispatch_get_main_queue(), ^{

    SGHomeSeachDetailController * detailViewCon = [[SGHomeSeachDetailController alloc]init];

    detailViewCon.baseUrl = str;

    [self.navigationController pushViewController: detailViewCon animated:YES];

    });

    };

    4.iOS调用JS进行初始化

    NSString *textJS = @"window.ios_callback('这里是JS中alert弹出的message')";

    [_mJSContext evaluateScript:textJS];

    也可以参考:IOS中 使用JavaScriptCore 实现OC与JS的交互 - 简书

    以及我的博客:JS和Native交互之 - 运用JavaScriptCore框架进行交互 - lxm_780337的博客        - 博客频道 - CSDN.NET

    WebViewJavascriptBridge

    Obj-C和JavaScript原理:

    Obj-C调用JavaScript很简单,可以通过webview的stringByEvaluatingJavaScriptFromString:方法调用JavaScript代码;JavaScript调用Obj-C,则是通过web view的代理方法shouldStartLoadWithRequest:来接收JavaScript的网络请求从而实现调用。

    利弊:

    需要把响应的方法放到桥梁内,这样对安卓端可能会中影响

    不错的例子:

    1.按照本地的CSS文件展示一串网络获取的带HTML格式的只有body部分的文本,需要自己拼写完整的HTML。除此之外,还需要禁用获取的HTML文本中自带的 《 img 》 标签自动加载,并把下载图片的操作放在native端来处理,并通过JS将图片在Cache中的地址返回给UIWebview。http://www.cocoachina.com/ios/20150814/12985.html

    过程:

    一开始,我们在Native端和JS端都分别进行初始化:

    OC端:

    @property WebViewJavascriptBridge* bridge;

    对应的初始化代码如下,在初始化中直接包含了一个用于接收JS的回调:

    _bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {

    NSLog(@"ObjC received message from JS: %@", data);

    responseCallback(@"Response for message from ObjC");

    }];

    JS端:(以下是固定写法,你自己的JS文件中必须包含如下代码)

    function connectWebViewJavascriptBridge(callback) {

    if (window.WebViewJavascriptBridge) {

    callback(WebViewJavascriptBridge)

    } else {

    document.addEventListener('WebViewJavascriptBridgeReady', function() {

    callback(WebViewJavascriptBridge)

    }, false)

    }

    connectWebViewJavascriptBridge(function(bridge) {

    //注意,你的bridge函数都应写在这里面

    }

    //例如

    function doSomething(){

    connectWebViewJavascriptBridge(function(bridge) {

    bridge.init(function(message, yourCallback) {

    log('ObjC called testJavascriptHandler with', message)

    var responseData = { 'Javascript Says':'Right back atcha!' }

    log('JS responding with', responseData)

    responseCallback(responseData)

    })

    }

    }

    然后,我们要知道,在WebViewJavascriptBridge中,交互的方式只有两种:send 和 callHandle,JS和OC都有这两个方法,所以对应的四种关系是:

    blob.png

    OC调用JS方法

    1.调用JS中bridge.init的方法

    //OC

    [_bridge send:@"The message sent from ObjC to JS" responseCallback:^(id response) {

    NSLog(@"sendMessage got response: %@", response);//这里的response是js方法中的data

    }];

    //对应调用js中的方法

    bridge.init(function(message, yourCallback) {

    log('ObjC called testJavascriptHandler with', message)

    var responseData = { 'Javascript Says':'Right back atcha!' }

    log('JS responding with', responseData)

    responseCallback(responseData)

    })

    2.调用JS中bridge.registerHandler方法,该方法可以注册方法名,通过注册名确认调用方法

    //OC

    [_bridge callHandler:@"注册名" data:data responseCallback:^(id response) {

    NSLog(@"testJavascriptHandler responded: %@", response);

    }];

    //对应调用的js中的方法

    bridge.registerHandler('注册名', function(data, responseCallback) {

    log('ObjC called testJavascriptHandler with', data)

    var responseData = { 'Javascript Says':'Right back atcha!' }

    log('JS responding with', responseData)

    responseCallback(responseData)

    })

    JS端调用OC端方法

    1.调用OC中创建bridge对象时定义时的方法

    //JS中

    bridge.send(data,function(response){

    log('这里是回调方法',response) //回调方法

    })

    //对应调用的OC中bridge初始化中设置的block方法

    _bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {

    //do something...

    NSLog(@"ObjC received message from JS: %@", data);//从js获得的参数

    responseCallback(@"Response");//Response to js

    }];

    2.通过方法名调用OC中bridge的注册方法

    //JS中

    bridge.callHandler('注册名', {'foo': 'bar'}, function(response) {

    log('JS got response', response)

    })

    //对应调用的OC中的bridge注册的方法

    [_bridge registerHandler:@"注册名" handler:^(id data, WVJBResponseCallback responseCallback) {

    NSLog(@"testObjcCallback called: %@", data);//从js获取的参数

    responseCallback(@"Response");//

    }];

    这篇文章讲了交互原理非常不错:JS和Native交互之 -WebViewJavascriptBridge源码分析 - lxm_780337的博客        - 博客频道 - CSDN.NET

    UIWebView的代理方法

    原理:- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;在WebView中的wap页将要载入内容时得到通知触发,返回NO则阻止加载内容,优点:简单易用,在页面跳转请求时进行iOS端的页面跳转,并返回NO阻止wap内的页面跳转缺点:无法识别不加载新内容的JS动作(点击按钮弹出对话框和提交等)例子:HTML网页和一个btn点击事件用来与原生OC交互(用JS发起一个假的URL请求,然后利用UIWebView的代理方法拦截这次请求,然后再做相应的处理)JS调用IOSHTML代码如下:

    相关文章

      网友评论

      • UncleFool:你好,请教一个问题。js端在调用window.webkit.messageHandlers.AppModel.postMessage()时,需要iOS端向js端传递一个值。请问上面这个方法可以接收返回值吗,iOS端应该怎么处理呢?
        Www刘:@UncleFool 现在该做前端了~你在哪里上班?
        UncleFool:@Www刘 现在做什么呢
        Www刘:@UncleFool 不好意思很久没做ios了,很多都忘记了~
      • UncleFool:你好,请教一个问题。js端在调用window.webkit.messageHandlers.AppModel.postMessage()时,需要iOS端向js端传递一个值。请问上面这个方法可以接收返回值吗,iOS端应该怎么处理呢?
      • Bonew01:大神,求源码,谢谢~
      • 罗同学_:不错不错,比我写的详细多了
      • 火星的蝈蝈:谢谢博主,受益匪浅

      本文标题:简单- IOS WebView与JS交互方法详解

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