JS和OC的交互这是个永恒话题,使用场景也是越来越多,如今一些reactnative、vue框架等,都是在重点结合原生与H5的混合使用。

那么,如何快捷方便的使用两者交互是一个很重要的关键点。

1、传统上的交互使用:

- OC调用JS:

webView对象通过调用stringByEvaluatingJavaScriptFromString这个方法执行一段JS代码实现交互。

如:

OC代码:

[self.webView stringByEvaluatingJavaScriptFromString:@"ocCallJS({'name':'xiaoxiao'})"];

JS代码:

</script>
   function ocCallJS(data) {
    var obj = eval(data);
    alert(obj.name);
   }
<script>

这种方式对一些简单场景比较适用,也很方便。

- JS调用OC:

webView拦截url链接,获取内容,再处理逻辑

如:

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;

实现以上webView的代理方法,当webView每次开始加载URL时会进入这个方法,我们便可以在这个方法实现JS调用OC。

举例大概如下:

JS代码:

OC代码:

(图片来源于网络)

这种JS调用OC的方法的缺点十分明显,需要繁琐地解释字符串得到相应的方法名和传值,且调用的方法也不能传递返回值;

但优点是:不需要等待页面加载完才触发,当相应的代码被运行就能调用OC的方法(相比 JavaScriptCore而言,下文会讲到)。

2、苹果推荐的框架--JavaScriptCore

JavaScriptCore是苹果在iOS7时新推出用以实现JS和iOS代码交互的框架,十分简单高效。

使用这种,需要导入JavaScriptCore.framework框架。

oc调用js时:

-(void)webViewDidFinishLoad:(UIWebView *)webView
{
//网页加载完成调用此方法 //首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)
JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
NSString *alertJS=@"alert('test js OC')"; //准备执行的js代码
[context evaluateScript:alertJS];//通过oc方法调用js的alert }

这句话的意思,是在webview加载结束,注入一段js代码,和传统方式有异曲同工之处。

js调用oc时:

这个是这个框架的优势重点。这里基本解决了两者的调用,并且能够实现,调用之后的回调处理。

举例:使用block方式比较简单,也是我比价推荐的一种,但是要注意防止循环引用问题的发生。

HTML文件按钮代码

 <button onclick="myAction(str);" style="">点击按钮返回上一个页面</button>

OC中代码

- (void)webViewDidFinishLoad:(UIWebView *)webView方法中对block块进行代码实现.

  __weak typeof(self)temp = self;
self.context[@"myAction"] = ^(NSString *str){
//如果有参数,就是str
[temp.navigationController popViewControllerAnimated:YES]; };

但!!!这里有个坑,就是oc调用js,必须是html加载完成之后(webViewDidFinishLoad)才可以。

3、WKScriptMessageHandler

注意:使用时必须iOS8+以及WKWebView(其实WKWebView并不支持方法二),如果用wk,我们可以用WKWebView的WKScriptMessageHandler 来实现交互。

第一步:初始化WKWebView,调用addScriptMessageHandler:name:方法,name为js中的方法名,如scan:

- (void)setupWKWebView{
  WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
  configuration.userContentController = [[WKUserContentController alloc] init];
  [configuration.userContentController addScriptMessageHandler:self name:@"funcname"];   WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];
  webView.UIDelegate = self;
}

oc调用js:

//OC调用JS
NSString *JSResult = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; [self.webView evaluateJavaScript:JSResult completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@", error);
}];

js调用oc:

h5:

func(){
window.webkit.messageHandlers.funcname.postMessage()
}

// 注意:这里funcname是方法名,必须和oc里定义的一致

oc:在WKScriptMessageHandler代理方法,当js调用scan方法时,会回调此代理方法:

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
  if ([message.name isEqualToString:@"funcname"]) {
    //调用原生扫码  
  }
}

4、优秀的第三方框架--WebViewJavascriptBridge

到了这里,就是本文的重点了,介绍一下WebViewJavascriptBridge

GitHub地址

WebViewJavascriptBridge同时支持UIWeView和WKWebView,无论是JS调用OC还是OC调用JS,都可以正常传值和返回值;而且在页面加载时只要JS代码被运行就可以进行交互,上面遇到的缺点和坑在这里都被掩埋的,所以是现在处理交互的主流做法。

网上我找的资料,很多也是从官方demo衍生出来的,本文也不例外,不同的是,我会在代码里,详细的添加各种注释,保证大家能快速的理解。

使用介绍:

1、准备文件

2、js代码截取片段

解释:这段代码是必须的,申明交互直接拷贝即可,处理交互部分,需要改动,关键就是和oc端协商的方法名,以及js内部需要的处理逻辑。

<!-- 申明交互 -->
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'https://__bridge_loaded__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, )
} <!-- 处理交互 方法名要和ios内定义的对应-->
setupWebViewJavascriptBridge(function(bridge) { <!--处理 oc 调用 js -->
bridge.registerHandler('registerAction', function(data, responseCallback) {
//处理oc给的传参
alert('oc请求js 传值参数是:'+data)
var responseData = { 'result':'handle success' }
//处理完,回调传值给oc
responseCallback(responseData)
}) var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button'))
callbackButton.innerHTML = '点击我,我会调用oc的方法'
callbackButton.onclick = function(e) {
e.preventDefault()
<!--处理 js 调用 oc -->
bridge.callHandler('loginAction', {'userId':'zhangsan','name': '章三'}, function(response) {
//处理oc过来的回调
alert('收到oc过来的回调:'+response)
})
}
})

3、OC代码

- pod导入框架

pod 'WebViewJavascriptBridge'

- import头部

#import "WebViewJavascriptBridge.h"

- viewDidload

    //初始化  WebViewJavascriptBridge
if (_bridge) { return; }
[WebViewJavascriptBridge enableLogging];
_bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
[_bridge setWebViewDelegate:self]; //请求加载html,注意:这里h5加载完,会自动执行一个调用oc的方法
[self loadExamplePage:webView]; //申明js调用oc方法的处理事件,这里写了后,h5那边只要请求了,oc内部就会响应
[self JS2OC]; //模拟操作:2秒后,oc会调用js的方法
//注意:这里厉害的是,我们不需要等待html加载完成,就能处理oc的请求事件;此外,webview的request 也可以在这个请求后面执行(可以把上面的[self loadExamplePage:webView]放到[self OC2JS]后面执行,结果是一样的)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self OC2JS];
});

- JS  调用  OC

-(void)JS2OC{
/*
含义:JS调用OC
@param registerHandler 要注册的事件名称(比如这里我们为loginAction)
@param handel 回调block函数 当后台触发这个事件的时候会执行block里面的代码
*/
[_bridge registerHandler:@"loginAction" handler:^(id data, WVJBResponseCallback responseCallback) {
// data js页面传过来的参数 假设这里是用户名和姓名,字典格式
NSLog(@"JS调用OC,并传值过来"); // 利用data参数处理自己的逻辑
NSDictionary *dict = (NSDictionary *)data;
NSString *str = [NSString stringWithFormat:@"用户名:%@ 姓名:%@",dict[@"userId"],dict[@"name"]];
[self renderButtons:str]; // responseCallback 给js的回复
responseCallback(@"报告,oc已收到js的请求");
}]; }

-  OC  调用  JS

-(void)OC2JS{
/*
含义:OC调用JS
@param callHandler 商定的事件名称,用来调用网页里面相应的事件实现
@param data id类型,相当于我们函数中的参数,向网页传递函数执行需要的参数
注意,这里callHandler分3种,根据需不需要传参数和需不需要后台返回执行结果来决定用哪个
*/ //[_bridge callHandler:@"registerAction" data:@"我是oc请求js的参数"];
[_bridge callHandler:@"registerAction" data:@"uid:123 pwd:123" responseCallback:^(id responseData) {
NSLog(@"oc请求js后接受的回调结果:%@",responseData);
}]; }

这里的关键点就是:OC和JS商定的方法名要统一,两端要合作一下。

这里的举例,我都用到了处理后的回调,大家运行demo的时候注意看日志文件。

源码下载:点击这里获取Demo

以上几种方法就到这里里,如果需求比较简单,不一定需要使用最后一种,灵活运用更方便~  

enjoy

iOS WebViewJavascriptBridge初步尝试与图文详细讲解的更多相关文章

  1. thinkphp6下载安装与配置图文详细讲解教程(composer下载安装)

    thinkphp6发布也有一段时间了,相对来说比较稳定,是时候学习一下thinkphp6框架,提前学习,到正式发布的时候,可以直接拿来做正式的项目,先人一步.thinkPHP6.0在5.1的基础上对底 ...

  2. iOS KVC详细讲解

    iOS KVC详细讲解 什么是KVC? KVC即NSKeyValueCoding,就是键-值编码的意思.一个非正式的 Protocol,是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取 ...

  3. [iOS]数据库第三方框架FMDB详细讲解

    [iOS]数据库第三方框架FMDB详细讲解 初识FMDB iOS中原生的SQLite API在进行数据存储的时候,需要使用C语言中的函数,操作比较麻烦.于是,就出现了一系列将SQLite API进行封 ...

  4. 【图文+视频新手也友好】Java一维数组详细讲解(内含练习题答案+详解彩蛋喔~)

    目录 视频讲解: 一.数组的概述 二.一维数组的使用 三.Arrays工具类中的sort方法(sort方法用的多,我们具体讲一下) 四.数组中的常见异常 五.一维数组练习题 六.彩蛋(本期视频使用的P ...

  5. 【iOS】使用CoreText实现图文混排

    iOS没有现成的支持图文混排的控件,而要用多个基础控件组合拼成图文混排这样复杂的排版,是件很苦逼的事情.对此的解决方案有使用CoreText进行绘制,或者使用TextKit.本文主要讲解对于CoreT ...

  6. (转)TDD的iOS开发初步以及Kiwi使用入门

    本文转自“瞄神”博客 TDD的iOS开发初步以及Kiwi使用入门 测试驱动开发(Test Driven Development,以下简称TDD)是保证代码质量的不二法则,也是先进程序开发的共识.App ...

  7. Python爬虫学习:二、爬虫的初步尝试

    我使用的编辑器是IDLE,版本为Python2.7.11,Windows平台. 本文是博主原创随笔,转载时请注明出处Maple2cat|Python爬虫学习:二.爬虫的初步尝试 1.尝试抓取指定网页 ...

  8. Siki_Unity_2-1_API常用方法和类详细讲解(上)

    Unity 2-1 API常用方法和类详细讲解(上) 任务1&2:课程前言.学习方法 && 开发环境.查API文档 API: Application Programming I ...

  9. 用R进行微博分析的初步尝试

    新浪微博如火如荼,基于微博的各种应用也层出不穷. 有一种共识似乎是:微博数据蕴含着丰富的信息,加以适当的挖掘.可以实现众多商业应用.恰好社会网络分析也是我之前有所了解并持续学习的一个领域,因此我做了微 ...

随机推荐

  1. seajs的常用api简易文档

    目前使用sea.js的公司越来越多, 比如朋友网,阿里巴巴,淘宝网,百姓网,支付宝,有道云笔记等.模块化的javascript开发带来了可维护,可扩展性,尤其在多人协作开发的时候不用再担心文件依赖和函 ...

  2. 不小心删掉root目录......

    1.先保存还剩下的的东西,比如说桌面的文件,保存在/下面其他目录 2.执行命令 cp -R /etc/skel/.[!.]* ./ 3.reboot

  3. /bin/sh 与 /bin/bash 的区别

    /bin/sh 与 /bin/bash 的区别,用 : 截取字符串不是POSIX 标准的. 区别 sh 一般设成 bash 的软链 (symlink) ls -l /bin/sh lrwxrwxrwx ...

  4. ARM-LINUX学习笔记-1

    安装完linux之后记得系统更新,更新使用apt命令,如下(记得使用之前使用sudo -i 指令切换到root用户模式) apt-get update  更新系统软件源,相当于查找更新 apt-get ...

  5. JS中Exception处理

    程序开发中,编程人员经常要面对的是如何编写代码来响应错误事件的发生,即例外处理(exception handlers).如果例外处理代码设计得周全,那么最终呈现给用户的就将是一个友好的界面.否则,就会 ...

  6. spring 自动化构建项目

    STS 3.7.0.RELEASE http://spring.io/tools/sts/legacy

  7. PHP文件夹操作2

    mkdir("路径文件名"); 创建文件夹 imdir("路径文件名"); 删除文件夹(只能删除空的文件夹) rename("路径",&qu ...

  8. MAC上更攺jenkins默认安装目录

    /Library/LaunchDaemons #编缉里面的jenkinshome和username sudo vim org.jenkins-ci.plist #然后 sudo launchctl u ...

  9. iOS搜索框UISearchBar 分类: ios技术 2015-04-03 08:55 82人阅读 评论(0) 收藏

    当你在seachBar中输入字母之前的时候,只是用鼠标选中searchBar的时候,如图 终端输出截图如下:(这个时候调用先shouldBeginEditing,之后调用didBeginEditing ...

  10. Asp.NET开启一个线程,不停的执行

    using System;using System.Threading;using System.Threading.Tasks; class StartNewDemo{    static void ...