现在的iOS项目中嵌入了越来越多的Web界面,当然是为了方便,那么为了迎合这一趋势,作为iOS开发程序员,我们必须要了解怎么样用OC去和这些Web界面进行交互。这里介绍的是JavaScriptCore这个框架,他就是苹果为了解决这一问题而推出的框架。

JavaScriptCore的类说明

在做OC与H5的交互之前,我们需要先导入JavaScriptCore框架

#import <JavaScriptCore/JavaScriptCore.h>

然后我们进入到JavaScriptCore框架的JavaScriptCore.h,我们发现总共有如下几个类。

  1. #if defined(__OBJC__) && JSC_OBJC_API_ENABLED
  2.  
  3. #import "JSContext.h"
  4. #import "JSValue.h"
  5. #import "JSManagedValue.h"
  6. #import "JSVirtualMachine.h"
  7. #import "JSExport.h"
  8.  
  9. #endif

1. JSContext

JSContext 代表一个JavaScript的执行环境的一个实例。所有的JavaScript执行都是在上下文内。作为上下文,我们在很多情况下遇到过,比如CoreData,CoreGraphics等等,那么上下文对象到底是什么呢?你可以理解为是一个两者的连接桥梁,如图所示.

2.JSValue

JSValue的主要作用就是用来接收JSContext执行后的返回结果,当然了,JSValue可以是Js的任意类型。例如,JS中的变量,对象,以及函数。下面,我们举个例子来说明一下,例如我们现在需要从JSContext对象中接收到一个变量,我们可以如下所示。

首先在<script>标签中我们定义了一个字符串变量

  1. <script type="text/javascript">
  2. var myObject = "myObject";
  3. </script>

然后,我们在OC的代码中如下表示,其中self.context代表着已经初始化完成的JSContext对象。

JSContext 对象的创建有两种方法

  1. /*使用这个方法进行初始化 系统会自动创建一个JSVirtualMachine对象 然后 调用下面的方法 */
    - (instancetype)init;
  2.  
  3. /*!
  4. JSVirtualMachine对象其实代表着一个JavaScript对象空间或者一组执行资源。初始化只需要init 就行了
  5. */
  6. - (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;

当然 如果你使用了WebView 你可以这样初始化一个JSContext对象

  1. JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

有了JSContext,我们只需要在OC中写出下面的代码,就可以拿到我们在JS中定义的变量了

JSValue *value = self.context[@"myObject"];
//转换为OC的字符串
NSLog(@"%@",[value toString]);

3.JSManagedValue

JSManagedValue这个类其实到现在我还没有具体用到过.当时这里我也要根据API文档说明一下.JSManagedValue是JSValue的封装,用它可以解决JS和OC代码之间循环引用的问题,JSManagedValue最常用的用法就是安全的从内存堆区里面引用JSValue对象.如果JSValue存储在内存的堆区的方式是不正确的,很容易造成循环引用,然后导致JSContext对象不能正确的释放掉.

4.JSValueMachine

一个JSVirtualMachine对象其实代表着一个JavaScript对象空间或者一组执行资源。JSVirtualMachine支持线程安全锁,虚拟机,并发分配支持的JavaScript执行.也就说JSVirtualMachine用来管理整个JavaScript,当然了,这个类我也没有用到过.

5.JSExport

JSExport是一个协议,通过实现它可以完成把一个native对象暴漏给JS,当然了我们要指定native对象.比如我们指定native对象就是自身.如下所示.

self.context[@"native"] = self;

JavaScript 调取 OC的代码

那么我们怎么使用JavaScriptCore 进行JS与OC的交互呢,我们先来介绍JS调取OC的代码的方法。主要有两种方法:一种是很简单的直接使用Block,另一种是使用JSExport协议。

Block方式

block的方式比较简单,也是我比较推荐的一种,但是要注意防止循环引用问题。首先 我们说一下不带参数的函数调用,也就是我们不需要从网页那边有参数的传值。比如,页面跳转等等,代码如下:

HTML文件中的<body>标签中的按钮代码

  1. <button type="button" onclick="buttonClick()">点击按钮返回上一个页面</button>

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

  1. __weak typeof(self)weakSelf = self;
  2. self.context[@"buttonClick"] = ^() {
  3. [weakSelf.navigationController popViewControllerAnimated:YES];
  4. };

这样当你点击Web页面上的按钮的时候,就会执行block中的代码。进行页面跳转。

接下来 我们看一下,通过页面的传值,我们把H5标签的之作为参数进行传值操作。并且调用OC的block进行打印。

HTML文件中的<body>标签中的代码

  1. <body bgcolor="antiquewhite">
  2.  
  3. <!--&lt;!&ndash;打开本地 或者网页&ndash;&gt;-->
  4. <!--<a href="news.html" target="_top">打开本地</a>-->
  5. <!--<h1 align="center">标题一</h1>-->
  6. <!--<h2 class="h2ID">标题2</h2>-->
  7. <button type="button" onclick="buttonClick('你好','世界')">点击按钮返回上一个页面</button>
  8. <script type="text/javascript">
  9. function buttonClick(str1,str2) {
  10. alert(str1 + "---" + str2);
  11. }
  12. </script>
  13. </body>

OC调用这个block中的代码 有两种方法

  1. - (void)webViewDidFinishLoad:(UIWebView *)webView {
  2. self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
  3. //第一种方法
  4. // self.context[@"buttonClick"] = ^() {
  5. // //获取该方法的所有参数
  6. // NSArray *args = [JSContext currentArguments];
  7. // for (JSValue *arg in args) {
  8. // NSLog(@"%@",arg);
  9. // }
  10. //
  11. // };
  12. //第二种方法
  13. self.context[@"buttonClick"] = ^(NSString *str1,NSString *str2) {
  14. NSLog(@"%@ and %@",str1,str2);
  15. };
  16. }

点击按钮 可以看到 打印结果 你好 世界

JSExport 协议方式

通过实现JSExport协议方式进行OC与JS的交互,这里我只是简单的实现以下没有参数的函数调用.首先,我们在HTML文件中创建一个按钮用来调用OC中JSExport协议方法.

声明一个person类

  1. .h
  2. #import <Foundation/Foundation.h>
  3. #import <JavaScriptCore/JavaScriptCore.h>
  4.  
  5. @protocol webJsExport <JSExport>
  6.  
  7. - (void) myButtonClick;
  8.  
  9. @end
  10.  
  11. @interface Person : NSObject<webJsExport>
  12.  
  13. @end
  14. .m
  15.  
  16. #import "Person.h"
  17.  
  18. @implementation Person
  19.  
  20. - (void)myButtonClick {
  21. NSLog(@"再来一次");
  22. }
  23.  
  24. @end

HTML

  1. <button type="button" onclick="stu.myButtonClick()">JSExport没有参数</button>

调用

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. self.p = [[Person alloc] init];
  4. self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(, , self.view.frame.size.width, self.view.frame.size.height)];
  5. self.webView.delegate = self;
  6. NSURL *baseURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
  7. NSString *path = [[NSBundle mainBundle] pathForResource:@"Index" ofType:@"html"];
  8. NSString *html = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
  9. [self.webView loadHTMLString:html baseURL:baseURL];
  10. [self.view addSubview:self.webView];
  11. // self.context = [[JSContext alloc] init];
  12. // JSValue *value = self.context[@"myObject"];
  13. // //转换为OC的字符串
  14. // NSLog(@"%@",[value toString]);
  15. // __weak typeof(self)weakSelf = self;
  16. // self.context[@"buttonClick"] = ^() {
  17. // [weakSelf.navigationController popViewControllerAnimated:YES];
  18. // };
  19. }
  20.  
  21. - (void)webViewDidFinishLoad:(UIWebView *)webView {
  22. self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
  23. //第一种方法
  24. // self.context[@"buttonClick"] = ^() {
  25. // //获取该方法的所有参数
  26. // NSArray *args = [JSContext currentArguments];
  27. // for (JSValue *arg in args) {
  28. // NSLog(@"%@",arg);
  29. // }
  30. //
  31. // };
  32. //第二种方法
  33. self.context[@"buttonClick"] = ^(NSString *str1,NSString *str2) {
  34. NSLog(@"%@ and %@",str1,str2);
  35. };
  36. self.context[@"stu"] = self.p;
  37.  
  38. }

点击JSExport没有参数 会打印:在来一次

OC调用JavaScript函数

今天我们说一下如何使用JavaScriptCore让OC调用JavaScript函数,使用JavaScriptCore进行OC调用JavaScript函数是很容易进行传值操作的.首先我们需要在HTML文件创建爱你一个带有id的标签以及一个JavaScript函数.代码如下所示.

HTML代码

  1. <b id="label">需要改变的标签</b>
  2. <script type="text/javascript">
  3. function labelAction(obj) {
  4.  
  5. document.getElementById('label').innerHTML = obj;
  6.  
  7. }
  8. </script>

然后 就是OC中的代码了

  1. 下面就是实现方法,首先我们要先通过JSContext对象获取到JS中的对应函数并且使用JSValue对象进行接收.然后我们通过使用- (JSValue *)callWithArguments:(NSArray *)arguments;进行JS函数的调用,当然了这里的JS函数没有返回值,我也就没有做接收返回值的工作.
  2.  
  3. -(void)changeWebTxet{
  4. JSValue *labelAction = self.context[@"labelAction"];
  5. [labelAction callWithArguments:@[@"你好,JS世界!"]];
  6. }

通过上面的介绍,我们可以看出来 使用JavaScriptCore 来进行OC与H5 的交互是很方便的,比以前通过WebView的一些方法交互方便多了。

iOS 开发与H5交互(JavaScriptCore框架的使用)的更多相关文章

  1. iOS开发系列—Objective-C之Foundation框架

    概述 我们前面的章节中就一直新建Cocoa Class,那么Cocoa到底是什么,它和我们前面以及后面要讲的内容到底有什么关系呢?Objective-C开发中经常用到NSObject,那么这个对象到底 ...

  2. iOS开发网络篇—使用ASI框架进行文件下载

    iOS开发网络篇—使用ASI框架进行文件下载 说明:本文介绍iOS网络编程中经常用到的框架ASI,如何使用该框架进行文件的下载. 一.简单介绍 代码示例: #import "YYViewCo ...

  3. 浅谈 iOS 与 H5 的交互- JavaScriptCore 框架

    前言 小的作为一个iOS程序猿,可能研究JavaScript以及H5相关的知识并不是为了真正的要去转行做这一方面,其实更多的为了要研究OC中的JavaScriptCore框架,JavaScriptCo ...

  4. iOS开发 UIWebView+JavaScript 交互总结

    算是个人项目经验的,印象比较深的Web+JS交互的使用 iOS原生应用与Web页面元素交互方式有很多,JavaScriptCore.拦截协议.第三方框架WebViewJavaScriptBridge. ...

  5. ios和安卓H5交互桥接

    ios交互 demo1(摘自网络) <!doctype html> <html> <head> <meta charset="UTF-8" ...

  6. iOS开发(0):框架QMUIKit的使用 | 使用第三方UI框架 | cocoapods的使用

    对于移动APP来说,客户端(iOS或android)的界面开发是必不可少的工作.为了减轻界面开发的工作量,也为了提高开发的速度,选择一个良好的界面框架,是有意义的. iOS开源的界面框架有很多,比如c ...

  7. ios开发学习笔记040-autolayout 第三方框架Masonry

    不管是是界面创建约束还是代码创建约束,苹果官方提供的方式都比较繁琐.所以出现了第三方框架. Masonry 在github地址如下: https://github.com/SnapKit/Masonr ...

  8. iOS原生与H5交互

    一.WKWebView WKWebView 初始化时,有一个参数叫configuration,它是WKWebViewConfiguration类型的参数,而WKWebViewConfiguration ...

  9. iOS开发——JS网页交互——javaScript

    JS中调用OC #import "ViewController.h" @interface ViewController () <UIWebViewDelegate> ...

随机推荐

  1. bitcoin-qt忘记密码

    客户端有钱包加密功能,输入密码可以增强安全性. 但是,如果你把钱包文件弄丢了,那即使设了密码,币也会丢. 关闭bitcoin-qt,把钱包文件wallet.dat 剪到其他地方(但不要删除),然后重新 ...

  2. HDU4674 Trip Advisor

    Problem Description There is a strange country somewhere which its transportation network was built ...

  3. Win10系统如何关闭"启用病毒防护""启用Windows防火墙"提示?

    Win10系统如何关闭"启用病毒防护""启用Windows防火墙"提示?   目前已经有不少有用户升级到了win10正式版系统,不过有一些原win7/win8. ...

  4. react-native flex 布局 详解

    而在React Native中,有4个容器属性,2个项目属性,分别是: 容器属性:flexDirection   flexWrap   justifyContent  alignItems 项目属性( ...

  5. UVA - 434 Matty&#39;s Blocks

    题意:给你正视和側视图,求最多多少个,最少多少个 思路:贪心的思想.求最少的时候:由于能够想象着移动,尽量让两个视图的重叠.所以我们统计每一个视图不同高度的个数.然后计算.至于的话.就是每次拿正视图的 ...

  6. jQuery.delegate() 函数详解

    delegate()函数用于为指定元素的一个或多个事件绑定事件处理函数. 此外,你还可以额外传递给事件处理函数一些所需的数据. 即使是执行delegate()函数之后新添加的元素,只要它符合条件,绑定 ...

  7. ASP.NET MVC深入浅出(被替换) 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式 第三节: EF调用普通SQL语句的两类封装(ExecuteSqlCommand和SqlQuery ) 第四节: EF调用存储过程的通用写法和DBFirst模式子类调用的特有写法 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性) 第十节: EF的三种追踪

    ASP.NET MVC深入浅出(被替换)   一. 谈情怀-ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态 ...

  8. MQTT--linux安装部署(CentOS)

    OS环境:CentOS6.5 1.安装依赖 yum -y install gcc gcc-c++ openssl-devel c-ares-devel libuuid-devel wget cmake ...

  9. nginx 使用ngx_cache_purge清除缓存

    location ~ ^/myclear(/.*) { allow 10.0.0.0/8; allow 10.28.100.0/24; allow 127.0.0.1; deny all;   pro ...

  10. Spring事务管理之声明式事务管理-基于注解的方式

    © 版权声明:本文为博主原创文章,转载请注明出处 案例 - 利用Spring的声明式事务(TransactionProxyFactoryBean)管理模拟转账过程 数据库准备 -- 创建表 CREAT ...