JavaScript:浅谈iOS与H5的交互-JavaScriptCore框架


前言


小的作为一个iOS程序猿,可能研究JavaScript以及H5相关的知识并不是为了真正的要去转行做这一方面,其实更多的为了要研究OC中的JavaScriptCore框架,JavaScriptCore框架主要是用来实现iOS与H5的交互.当然了,最早我曾经写过iOS浅谈webView的JS一种用法.(去掉web显示页的广告),这种算得上最简单的iOS与H5的交互了.现在混合编程越来越多,H5的相对讲多,所以研究JavaScriptCore框架是相当有必要的.好了不扯这些没用的了,来搞今天的主题---JavaScriptCore框架,首先来说说JavaScriptCore框架几个常用的类.


JavaScriptCore的类说明


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

#import <JavaScriptCore/JavaScriptCore.h>

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

  • JSContext

JSContext代表一个JavaScript的执行环境的一个实例。所有JavaScript执行都是在上下文内进行。JSContext还用于管理对象的生命周期内JavaScript的虚拟机(API文档原文翻译)。作为上下文很多地方我们的都有可能使用过,比如CoreData,CoreGraphics等等,那么上下文对象到底是什么呢?你可以理解为是一个两者的连接桥梁,如图所示.


  • JSValue

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

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

    <script type="text/javascript">
        var myObject = "myObject";
    </script>

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

    JSValue *myObject = self.context[@"myObject"];

当然了,我们如果需要在OC中使用JSValue对象,那么我们可能需要适当的转换一下他的类型,框架提供了很多方法.比如上面的例子我们想要打印的话就可以如下所示.

    NSLog(@"%@",[myObject toString]);


  • JSManagedValue

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


  • JSVirtualMachine

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

</br>

  • JSExport

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

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


JavaScriptCore中JSContext对象的初始化


在进行iOS与H5的交互之前,我们需要做的是对JSContext对象进行初始化的设置,全程是在webView的*- (void)webViewDidFinishLoad:(UIWebView )webView这个代理方法中进行的.所以我们需要对webView进行初始化以及设置代理,这里就不过多的言语了.我们直接看一下在代理方法中如何对JSContext对象进行初始化设置.代码如下所示.

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

     //对JSContext对象进行初始化
     self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
         //验证JSContext对象是否初始化成功
     self.context.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue)
    {
        context.exception = exceptionValue;
    };
}


JavaScript调取OC代码


上一个模块我们已经对JSContext对象进行了初始化,那么要使用JavaScript调取OC代码主要有两种方式,一种是使用block(简单粗暴);另外一种是使用JSExport协议(决胜千里).

  • block方式

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

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

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

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

    __weak typeof(self)temp = self;
    self.context[@"myAction"] = ^(){
        
        [temp.navigationController popViewControllerAnimated:YES];
        
    };

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

HTML文件中的<body>标签的div标签代码(一个输入框,一个按钮)

            <input type="text" name="输入框" id="textField" placeholder="请输入要打印的信息" />

            <button onclick="log(document.getElementById('textField').value);">打印输入框信息</button>

然后我们在OC的代码中实现以下block函数.其中string参数就是网页中输入框的值.

    self.context[@"log"] = ^(NSString *string){
    
        NSLog(@"%@",string);
    
    };

效果图如下所示.坐标是手机模拟器,右边是Xcode控制台.


  • JSExport协议方式

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

            <button onclick="native.myLog();">调用OC中myLog方法</button>

我们需要把native对象指定为当前控制器,也就是自己.这句代码是在- (void)webViewDidFinishLoad:(UIWebView *)webView方法中实现的.

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

然后我们要写一个继承于JSExport的协议,协议如下所示.这里我要做一下对JSExportAs(PropertyName,Selector)这个宏定义做一下解释,也就说在PropertyName代表着JS函数的名称,而Selector代表着OC的协议方法,要注意的是Selector必须要有参数,不管是否需要传值.(不知所以然.😭,求大神讲解)

@protocol WebExport <JSExport>
JSExportAs
(myLog ,
 - (void)myOCLog :(NSString *)string
 );
@end

定义好了方法之后,我们就让当前的控制器遵守协议.实现代理方法.

@interface JavaScriptCallOCViewController ()<UIWebViewDelegate,WebExport>
  - (void)myOCLog :(NSString *)string{
    NSLog(@"你好,世界!");
}


OC调用JavaScript函数


iOS浅谈webView的JS一种用法.(去掉web显示页的广告)中我们说过一种比较简单的通过OC调取JavaScript函数的方式,当然了,我们就是使用stringByEvaluatingJavaScriptFromString方法添加了一个JS语句.代码如下所示.具体可以查看原文.

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

[webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.getElementsByClassName('adpic')[0].style.display = 'none'"];

}

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

            <b id="label">需要改变的标签</b>

    <script type="text/javascript">
        function labelAction(obj) {

            document.getElementById('label').innerHTML = obj;

        }
    </script>

然后就是OC代码中的操作了,我们依然先需要对webview和JSContext对象进行初始化设置.这里就不再重复的啰嗦了.
为了演示的效果,我把函数的调用放在了rightBarButtonItem的调用方法中.整体的代码如下所示.

    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"改变" style:UIBarButtonItemStyleDone target:self action:@selector(changeWebTxet)];

下面就是实现方法,首先我们要先通过JSContext对象获取到JS中的对应函数并且使用JSValue对象进行接收.然后我们通过使用- (JSValue *)callWithArguments:(NSArray *)arguments;进行JS函数的调用,当然了这里的JS函数没有返回值,我也就没有做接收返回值的工作.

-(void)changeWebTxet{
    JSValue *labelAction = self.context[@"labelAction"];
    [labelAction callWithArguments:@[@"你好,JS世界!"]];
}

我们看一下整体的实现效果.


尾声


JavaScriptCore框架的初步试用个人感觉还是挺好的,JavaScriptCore框架上手比较简单.当然了,对JavaScript还要要有一定理解和基础的,这样学习起来更简单一些.如果有什么问题欢迎来跟骚栋探讨,最后附上本文的实现Demo.

JavaScriptCore框架Demo传送门🚪



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容