Swift与JS交互

关于JavaScriptCore

本文中所涉及到的几种类型:

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

Swift与JS交互方式

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

  1. 直接调用JS代码。
  2. 在Swift中通过JSContext注入模型,然后调用模型的方法。

直接调用JS代码

我们可以不通过模型来调用方法,也可以直接调用方法。

let context = JSContext() 
context.evaluateScript(“var num = 10”)
context.evaluateScript(“function square(value) { return value * 2}”)

// 直接调用
let squareValue = context.evaluateScript(“square(num)”)
print(squareValue)

// 通过下标来获取到JS方法。
let squareFunc = context.objectForKeyedSubscript(“square”)
print(squareFunc.callWithArguments([“10”]).toString());

这种方式是没有注入模型到JS中的。这种方式使用起来不太合适,通常在JS中有很多全局的函数,为了防止名字重名,使用模型的方式是最好不过了。通过我们协商好的模型名称,在JS中直接通过模型来调用我们在Swift中所定义的模型所公开的API。

注入模型的交互

首先,我们需要先定义一个协议,而且这个协议必须要遵守JSExport协议。
All methods that should apply in Javascript,should be in the following protocol.注意,这里必须使用@objc,因为JavaScriptCore库是ObjectiveC版本的。如果不加@objc,则调用无效果。

@objc protocol JavaScriptSwiftDelegate: JSExport { 
 func callSystemCamera();
 func showAlert(title: String, msg: String);
 func callWithDict(dict: [String: AnyObject]);
 func jsCallObjcAndObjcCallJsWithDict(dict: [String: AnyObject]);
}

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

@objc classJSObjCModel: NSObject, JavaScriptSwiftDelegate { 
  weak var controller: UIViewController? 
  weak var jsContext: JSContext? 

  func callSystemCamera() {   
    print(“js call objc method: callSystemCamera”);
    let jsFunc = self.jsContext?.objectForKeyedSubscript(“jsFunc”); 
    jsFunc?.callWithArguments([]);  
  }

  func showAlert(title: String, msg: String) {     
    dispatch_async(dispatch_get_main_queue()) { () -> Void in   
      let alert = UIAlertController(title: title, message: msg, preferredStyle: .Alert)   
      alert.addAction(UIAlertAction(title: “ok”, style: .Default, handler: nil))      
      self.controller?.presentViewController(alert, animated: true, completion: nil)   
    }   
  }  

  // JS调用了我们的方法   
  func callWithDict(dict: [String : AnyObject]) {   
    print(“js call objc method: callWithDict, args: %@”, dict) 
  }

  // JS调用了我们的就去  
  func jsCallObjcAndObjcCallJsWithDict(dict: [String : AnyObject]) {     
    print(“js call objc method: jsCallObjcAndObjcCallJsWithDict, args: %@”, dict) 
    let jsParamFunc = self.jsContext?.objectForKeyedSubscript(“jsParamFunc”); 
    let dict = NSDictionary(dictionary: [“age”: 18, “height”: 168, “name”: “lili”])
    jsParamFunc?.callWithArguments([dict]) 
  }
}

接下来,我们在controller中在webview加载完成的代理中,给JS注入模型:

// MARK: - UIWebViewDelegate
func webViewDidFinishLoad(webView: UIWebView) {
  let context = webView.valueForKeyPath(“documentView.webView.mainFrame.javaScriptContext”) as? JSContextlet 
  model = JSObjCModel() 
  model.controller = self
  model.jsContext = context
  self.jsContext = context

  // 这一步是将OCModel这个模型注入到JS中,在JS就
  // 可以通过OCModel调用我们公暴露的方法了。
  self.jsContext?.setObject(model, forKeyedSubscript: “OCModel”)
  self.jsContext?.exceptionHandler = { (context, exception) in 
     print(“exception @”, exception) 
  }
}

我们是通过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中添加以下代码:

Test how to use objective-c call js

现在就可以测试代码了。
当我们点击第一个按钮:Call ObjC system camera时,
通过OCModel.callSystemCamera(),就可以在HTML中通过JS调用OC的方法。

在Swift代码中,我们的callSystemCamera方法体中,添加了以下两行代码,就是获取HTML中所定义的JS就去jsFunc,然后调用它。

let jsFunc = self.jsContext?.objectForKeyedSubscript(“jsFunc”); jsFunc?.callWithArguments([]);

这样就可以在JS调用Siwft方法时,也让Swift反馈给JS。
注意:这里是通过objectForKeyedSubscript方法来获取变量jsFunc。
方法也是变量。看看下面传字典参数:

(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方法,然后调用它并传了一个字典作为参数。

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

推荐阅读更多精彩内容

  • 开发中移动端经常涉及到与js交互的功能,例如:js需要调用oc的方法,或者oc需要调用js的方法。 一、js调用o...
    年轻就要活出样阅读 406评论 0 0
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,090评论 4 62
  • 前言 ObjectiveC与Js交互是常见的需求,可对于新手或者所谓的高手而言,其实并不是那么简单明了。这里只介绍...
    一路向北客阅读 366评论 0 4
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,709评论 0 9
  • (2016-01-17-Sun 03:54:24) Search Web Use Search Web in th...
    菜五阅读 278评论 1 0