小工具      在线工具  汉语词典  css  js  c++  java

iOS与JS交互实战文章(ObjC版)

额外说明

收录于:45天前

http://mp.weixin.qq.com/s?__biz=MzIzMzA4NjA5Mw==&mid=214063688&idx=1&sn=903258ec2d3ae431b4d9ee55cb59ed89#rd 转载自:

ObjectiveC和Js之间的交互是常见的需求,但对于新手或所谓的专家来说并不是那么简单和清晰。这里我们只介绍iOS7.0之后出来的JavaScriptCore框架。

关于 JavaScriptCore

本教程涵盖的几种类型:

  • JSContext, JSContext是代表JS的执行环境,通过-evaluateScript:方法就可以执行一JS代码
  • JS值, JSValue封装了JS与ObjC中的对应的类型,以及调用JS的API等
  • JS导出, JSExport是一个协议,遵守此协议,就可以定义我们自己的协议,在协议中声明的API都会在JS中暴露出来,才能调用

ObjC 如何与 JS 交互

通过JSContext,我们有两种调用JS代码的方法:

  • 1.直接调用JS代码
  • 2、在ObjC中通过JSContext注塑成型,然后调用模型的方法

直接调用JS代码

 // 一个JSContext对象,就类似于Js中的window,
 // 只需要创建一次即可。
 self.jsContext = [[JSContext alloc] init];

 //  jscontext可以直接执行JS代码。
 [self.jsContext evaluateScript:@"var num = 10"];
 [self.jsContext evaluateScript:@"var squareFunc = function(value) { return value * 2 }"];
 // 计算正方形的面积
 JSValue *square = [self.jsContext evaluateScript:@"squareFunc(num)"];

 // 也可以通过下标的方式获取到方法
 JSValue *squareFunc = self.jsContext[@"squareFunc"];
 JSValue *value = [squareFunc callWithArguments:@[@"20"]];
 NSLog(@"%@", square.toNumber);
 NSLog(@"%@", value.toNumber);

该方法不会将模型注入到JS中。这种方法不适合使用。 JS中通常有很多全局函数。为了防止重名,最好使用模型。通过我们协商好的模型名称,直接通过JS中的模型调用我们在ObjC中定义的模型暴露的API。

通过注入模型进行交互

首先,我们需要定义一个协议,该协议必须符合 JSExport 协议。

@protocol JavaScriptObjectiveCDelegate <JSExport>

// JS调用此方法来调用OC的系统相册方法
- (void)callSystemCamera;
// 在JS中调用时,函数名应该为showAlertMsg(arg1, arg2)
// 这里是只两个参数的。
- (void)showAlert:(NSString *)title msg:(NSString *)msg;
// 通过JSON传过来
- (void)callWithDict:(NSDictionary *)params;
// JS调用Oc,然后在OC中通过调用JS方法来传值给JS。
- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary *)params;

@end

接下来,我们还需要定义一个模型:

// 此模型用于注入JS的模型,这样就可以通过模型来调用方法。
@interface HYBJsObjCModel : NSObject <JavaScriptObjectiveCDelegate>

@property (nonatomic, weak) JSContext *jsContext;
@property (nonatomic, weak) UIWebView *webView;

@end

实现这个模型:

@implementation HYBJsObjCModel

- (void)callWithDict:(NSDictionary *)params {
 NSLog(@"Js调用了OC的方法,参数为:%@", params);
}

// Js调用了callSystemCamera
- (void)callSystemCamera {
 NSLog(@"JS调用了OC的方法,调起系统相册");

 // JS调用后OC后,又通过OC调用JS,但是这个是没有传参数的
 JSValue *jsFunc = self.jsContext[@"jsFunc"];
 [jsFunc callWithArguments:nil];
}

- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary *)params {
 NSLog(@"jsCallObjcAndObjcCallJsWithDict was called, params is %@", params);

 // 调用JS的方法
 JSValue *jsParamFunc = self.jsContext[@"jsParamFunc"];
 [jsParamFunc callWithArguments:@[@{@"age": @10, @"name": @"lili", @"height": @158}]];
}

- (void)showAlert:(NSString *)title msg:(NSString *)msg {
 dispatch_async(dispatch_get_main_queue(), ^{
   UIAlertView *a = [[UIAlertView alloc] initWithTitle:title message:msg delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
   [a show];
 });
}

@end

接下来,我们在 webview 加载后将模型注入到控制器中的 JS 中。

#pragma mark - UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
 self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
 // 通过模型调用方法,这种方式更好些。
  HYBJsObjCModel *model  = [[HYBJsObjCModel alloc] init];
 self.jsContext[@"OCModel"] = model;
 model.jsContext = self.jsContext;
 model.webView = self.webView;

 self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
   context.exception = exceptionValue;
   NSLog(@"异常信息:%@", exceptionValue);
 };
}

我们是通过webView的valueForKeyPath获取的,其路径为documentView.webView.mainFrame.javaScriptContext
这样就可以获取到JS的context,然后为这个context注入我们的模型对象。

我们先写两个JS方法:

 var jsFunc = function() {
   alert('Objective-C call js to show alert');
 }

 var jsParamFunc = function(argument) {
   document.getElementById('jsParamFuncSpan').innerHTML
   = argument['name'];
 }

这里我们定义了两个JS方法,一个是jsFunc,不带参数。
另一个是jsParamFunc,带一个参数。

接下来,我们将以下代码添加到html中的body中:

<div style="margin-top: 100px">
<h1>Test how to use objective-c call js</h1>
<input type="button" value="Call ObjC system camera" onclick="OCModel.callSystemCamera()">
<input type="button" value="Call ObjC system alert" onclick="OCModel.showAlertMsg('js title', 'js message')">
</div>

<div>
<input type="button" value="Call ObjC func with JSON " onclick="OCModel.callWithDict({'name': 'testname', 'age': 10, 'height': 170})">
<input type="button" value="Call ObjC func with JSON and ObjC call js func to pass args." onclick="OCModel.jsCallObjcAndObjcCallJsWithDict({'name': 'testname', 'age': 10, 'height': 170})">
</div>

<div>
<span id="jsParamFuncSpan" style="color: red; font-size: 50px;"></span>
</div>

现在您可以测试代码了。

当我们点击第一个按钮:Call ObjC system camera时,
通过OCModel.callSystemCamera(),就可以在HTML中通过JS调用OC的方法。
在OC代码中,我们的callSystemCamera方法体中,添加了以下两行代码,就是获取HTML中所定义的JS就去jsFunc,然后调用它。

 JSValue *jsFunc = self.jsContext[@"jsFunc"];
 [jsFunc callWithArguments:nil];

这样,当JS调用OC方法时,OC也可以反馈给JS。

看看下面传递的字典参数:

- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary *)params {
 NSLog(@"jsCallObjcAndObjcCallJsWithDict was called, params is %@", params);

 // 调用JS的方法
 JSValue *jsParamFunc = self.jsContext[@"jsParamFunc"];
 [jsParamFunc callWithArguments:@[@{@"age": @10, @"name": @"lili", @"height": @158}]];
}

获取我们在 HTML 中定义的 jsParamFunc 方法,并通过传递字典作为参数来调用它。

好了,就讲这么多吧,如果想要Demo源代码,请到
github:https://github.com/CoderJackyHuang/IOSCallJsOrJsCallIOS

想学习Swift版的?请阅读:
http://mp.weixin.qq.com/s?__biz=MzIzMzA4NjA5Mw==&mid=214070747&idx=1&sn=57b45fa293d0500365d9a0a4ff74a4e1#rd


. . .

相关推荐

额外说明

使用IO流操作Jdbc连接MySql数据库

1.写连接MySql数据配置文件: 文件名称:dbconfig.properties DRIVER = com.mysql.jdbc.Driver URL = jdbc:mysql://localhost:3306/javadb USER = root

额外说明

SQL Server初始化表:删除数据及主键复位(二)

上一篇用的是临时表,执行之后特殊应用都会消失。后面有讲到SQL Server本身只怎么操作的,就模拟了一个——添加触发器特殊应用。   1、创建S_ENTITY表和insert测试数据上一篇有这一篇就不写了。   2、创建Table2表并添加测试触发器:

额外说明

docker Error: {:plugins_not_found, [:“rabbitmq_delayed_message_exchange-3.8.0.ez“]}

1. rabbitMQ 插件下载 官网地址 下载完毕,借助xftp传到linux 查看插件位置. docker cp rabbitmq_delayed_message_exchange-3.8.0.ez 58c062ae8ab5:/plugins # 进

额外说明

uniapp——uni-app介绍 环境搭建 创建项目运行

QQ 1274510382 Wechat JNZ_aming 商业联盟 QQ群538250800 技术搞事 QQ群599020441 解决方案 QQ群152889761 加入我们 QQ群649347320 共享学习 QQ群674240731 纪年科技am

额外说明

SpringBoot+SpringSecurity+dubbo图书电商后台实战-对象映射-基本属性映射

QQ 1274510382 Wechat JNZ_aming 商业联盟 QQ群538250800 技术搞事 QQ群599020441 解决方案 QQ群152889761 加入我们 QQ群649347320 共享学习 QQ群674240731 纪年科技am

额外说明

Java后台——点餐小程序菜品订单取消失败问题讲解

QQ 1274510382 Wechat JNZ_aming 商业互捧 QQ群538250800 技术搞事 QQ群599020441 技术合作 QQ群152889761 加入我们 QQ群649347320 纪年科技aming 网络安全 ,深度学习,嵌入式

额外说明

行人属性识别数据集总结

文章目录 摘要 1、PA-100K数据集 下载链接: 行人属性 提取mat里面的信息 2、PETA 数据集 数据集下载 行人属性 摘要 行人属性识别,是一个多标签分类任务。Paper With Code主页链接如下: Pedestrian Attribu

额外说明

Spring Boot基础学习笔记20:Spring Security入门

文章目录 零、学习目标 一、Spring Security (一)Spring Security概述 (二)Spring Boot整合Spring Security实现的安全管理功能 二、基础环境搭建 (一)创建Spring Boot项目 - Sprin

额外说明

window.open跳转页面,并传递参数

var url= /index_hj/audit_add_new.html; window.open(‘url?id=’+id); 备注:1、如果传递常量直接在id=的后面,即写单引号前面写入常量值即可 2.如果是变量,要在单引号后面用:+变量名 3.如

额外说明

如何在WordPress中添加WhatsApp共享按钮

WhatsApp 等消息应用程序正在成为与朋友分享事物的新方式。最近,我们的一位用户询问我们如何在他们的帖子中添加 WhatsApp 分享按钮。在本文中,我们将向您展示如何在 WordPress 中添加 WhatsApp 分享按钮。 WhatsApp 等

ads via 小工具