Swift与JS的交互

原理

同Object-C与JS交互的大同小异,只是方法形式改变了。
首先我们需要引入iOS7.0出来的JavaScriptCore.framework

JavaScriptCore

  • JSContext是JS的执行环境。

  • JSValue是Swift或者OC与JS交互的中间媒体,可以转化为Swift对 象或者OC对象,也可以获取JS对象或方法。

  • JSExport 是Swift或者OC与JS交互的协议,构造一个类,遵循JSExport协议,实现协议的方法和初始化协议的属性,然后把Swift或OC对象与JS对象关联,我们就可以在JS环境下使用关联的对象调用之前实现的协议的方法或取得属性值或修改属性值。

  • JSManagedValue:JSValue的内存管理器。

  • JSVirtualMachine:JSVirtualMachine为JavaScript的运行提供了底层资源.

实战

Swift 与 JS 基本数据类型转换

在Swift中我们推荐使用let类声明类(引用类型),这是Swift加强了安全机制的结果。
首先初始化JS执行环境let context = JSContext(),并且为了捕获JS执行过程中得异常,我们给self.jsContext?.exceptionHandler闭包赋值。然后我们就正式开始与JS的交互,调用context.evaluateScript()方法执行任何JS代码,返回结果都是JSValue类型,使用toObject()方法转化成Swift对象,当然对象转换是一一对应的(如JS int类型应该转换成Swift Int类型)。我们还可以使用objectForKeyedSubscript()调用下角标函数(OC中我们直接使用[@"属性或者对象"])来取得JSContext执行环境的对象或者方法,也可以取得JSValue一系列的属性等。

代码如下

  1. //声明执行环境
  2. let context = JSContext();
  3. self.jsContext = context;
  4. //捕获异常
  5. self.jsContext?.exceptionHandler = {(jsContext:JSContext!,exception:JSValue!) ->Void in
  6. jsContext.exception = exception;
  7. print(exception);
  8. };
  9. let value = context.evaluateScript("2 + 2");
  10. print(value.toObject());
  11. //或者 区别print更简洁
  12. NSLog("\(value.toObject())");
  13. //直接定义JS数组
  14. context.evaluateScript("var array = ['徐海青',123]")
  15. //下标获取JS数组
  16. let arrayValue = context.objectForKeyedSubscript("array")
  17. if(!arrayValue.isArray){
  18. print("arrayValue不是数组")
  19. return
  20. }
  21. //两种方式获取属性
  22. print("arrayValue 长度\(arrayValue.objectForKeyedSubscript("length")),第一种方式获取的值\(arrayValue.valueAtIndex(0)),第二种方式获取的值\(arrayValue.objectAtIndexedSubscript(1)),第二种方式获取的长度\(arrayValue.valueForProperty("length"))");
  23. //两种方式设置array,越界自动扩展
  24. arrayValue.setObject("赵杰文", atIndexedSubscript: 4);
  25. arrayValue.setValue("水草草", atIndex: 6);
  26. //打印最后的array
  27. print(arrayValue);
  28. arrayValue.toArray()
  29. let array = arrayValue.toArray();
  30. //打印转换后的数组
  31. print(array);

函数调用

我们使用JS注入方法到执行环境,然后使用objectForKeyedSubscript()取出方法

  1. self.jsContext = JSContext();
  2. //JS异常处理
  3. self.jsContext?.exceptionHandler = { (jsContext:JSContext!,exception:JSValue!) ->Void in
  4. jsContext.exception = exception;
  5. print(exception);
  6. }
  7. /* js 函数
  8. var func = function(value){
  9. if(value < 0) return;
  10. if(value === 0) return 1;
  11. return value * function(value - 1);
  12. }
  13. */
  14. //拼接JS
  15. let funStr = "var fun = function (value){" +
  16. "if(value < 0) return;" +
  17. "if(value === 0) return 1;" +
  18. "return value * fun(value - 1);" +
  19. "}";
  20. //打印插入前的函数
  21. print(funStr);
  22. //插入JS
  23. self.jsContext?.evaluateScript(funStr);
  24. //下标获取函数
  25. //let jsFunc = self.jsContext?.objectForKeyedSubscript("fun");
  26. //或者
  27. let jsFunc = self.jsContext?.evaluateScript("fun");
  28. //打印插入后函数,应该和前面一样
  29. print(jsFunc);
  30. //传入参数
  31. let result = jsFunc?.callWithArguments([5]);
  32. //打印结果
  33. print("result = \(result)");

使用闭包

申明Swift闭包block,通过 self.jsContext?.setObject() 赋值

  1. self.jsContext = JSContext();
  2. //JS异常处理
  3. self.jsContext?.exceptionHandler = { (jsContext:JSContext!,exception:JSValue!) ->Void in
  4. jsContext.exception = exception;
  5. print(exception);
  6. }
  7. //往JS注入类
  8. let block = {(name:String,qq:String) -> JSValue in
  9. //let context = JSContext.currentContext();
  10. let object = JSValue(newObjectInContext: self.jsContext);
  11. object.setObject(name, forKeyedSubscript: "name");
  12. object.setValue(qq, forProperty: "qq");
  13. return object;
  14. }
  15. print(block);
  16. self.jsContext?.setObject(block("xuhaiqing","1716329344"), forKeyedSubscript: "User");
  17. //验证是否注入成功
  18. let user = self.jsContext?.evaluateScript("User");
  19. print("user.name = \(user?.objectForKeyedSubscript("name")) and user.qq = \(user?.valueForProperty("qq"))" )

使用JSExport 方便构造,我们强烈推荐使用这种方式与JS交互

  1. var user = User(name: "xuhaiqing", qq: "1716329344");
  2. user.jsContext = self.jsContext;
  3. user.webView = self.webView;
  4. //关联
  5. print(self.jsContext);
  6. self.jsContext?.setObject(user, forKeyedSubscript: "SwiftModel");
  7. print(user);
  8. //修改关联后的值
  9. self.jsContext?.evaluateScript("SwiftModel.name = 'zhaojiewen'");
  10. self.jsContext?.evaluateScript("SwiftModel.descriptions()");
  11. print(user.name);
  12. print(user.qq);

User 类

  1. //
  2. // User.swift
  3. // SwiftJSDemo
  4. //
  5. // Created by haodf on 15/11/12.
  6. // Copyright © 2015年 haodf. All rights reserved.
  7. //
  8. import Foundation
  9. import UIKit
  10. import JavaScriptCore
  11. @objc protocol UserJsToSwiftDelegate : JSExport{
  12. var name:(String){get set};
  13. var qq:(String){get set};
  14. func callSystemCamera();
  15. func showAlert(title:String,msg:String);
  16. func callWithDict(dic:[String:AnyObject]);
  17. func descriptions();
  18. }
  19. @objc class User :NSObject,UserJsToSwiftDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
  20. var name:(String);
  21. var qq:(String);
  22. var webView:UIWebView?
  23. var jsContext:JSContext?
  24. //author 徐海青
  25. //
  26. //初始化
  27. init(name:(String),qq:(String)){
  28. self.name = name;
  29. self.qq = qq;
  30. }
  31. //author 徐海青
  32. //
  33. //调用系统照相机
  34. @objc func callSystemCamera(){
  35. let imagePickerViewController = UIImagePickerController();
  36. imagePickerViewController.delegate = self;
  37. UIApplication.sharedApplication().keyWindow?.addSubview(imagePickerViewController.view);
  38. UIApplication.sharedApplication().keyWindow?.rootViewController?.addChildViewController(imagePickerViewController);
  39. }
  40. //author 徐海青
  41. //
  42. //弹框显示提示信息
  43. @objc func showAlert(title:String, msg: String) {
  44. //调用系统的alert
  45. // let alertViewController = UIAlertController();
  46. // UIApplication.sharedApplication().keyWindow?.addSubview(alertViewController.view);
  47. // UIApplication.sharedApplication().keyWindow?.rootViewController?.addChildViewController(alertViewController);
  48. //调用JS的alert
  49. let jsValue = self.jsContext?.objectForKeyedSubscript("alertFunc");
  50. jsValue?.callWithArguments([title,msg]);
  51. }
  52. //author 徐海青
  53. //
  54. //双向交互
  55. @objc func callWithDict(dic: [String : AnyObject]) {
  56. print(self.jsContext);
  57. let funStr = "var swiftInsertIntoJsFunc = function(arg){" +
  58. "document.getElementById('swiftInsertIntoJsSpan').innerHTML = arg['name'];" +
  59. "}";
  60. //打印插入前的函数
  61. print(funStr);
  62. //插入JS
  63. self.jsContext?.evaluateScript(funStr);
  64. //下标获取函数
  65. //let jsFunc = self.jsContext?.objectForKeyedSubscript("fun");
  66. //或者
  67. let jsFunc = self.jsContext?.evaluateScript("swiftInsertIntoJsFunc");
  68. //let insertFunc = self.jsContext?.objectForKeyedSubscript("swiftInsertIntoJsFunc");
  69. print(dic);
  70. print(jsFunc);
  71. jsFunc?.callWithArguments([dic]);
  72. }
  73. //author 徐海青
  74. //
  75. //打印时显示的信息
  76. @objc func descriptions() {
  77. print("user.name = \(self.name) and user.qq = \(self.qq)")
  78. }
  79. @objc func imagePickerControllerDidCancel(picker: UIImagePickerController) {
  80. picker.view.removeFromSuperview();
  81. picker.removeFromParentViewController();
  82. }
  83. }

Swift与JS的交互的更多相关文章

  1. 【Swift】WKWebView与JS的交互使用

    一.前言 近日,有朋友问我关于WKWebView与JS的交互问题,可我之前一直使用的是UIWebView,也不曾做过WKWebView的交互啊!接下来大家一块学习下WKWebView是怎么实现原生代码 ...

  2. [转]OC与JS的交互详解

    事情的起因还是因为项目需求驱动.折腾了两天,由于之前没有UIWebView与JS交互的经历,并且觉得这次在功能上有一定的创造性,特此留下一点文字,方便日后回顾. 我要实现这样一个需求:按照本地的CSS ...

  3. OC与JS的交互详解

    事情的起因还是因为项目需求驱动.折腾了两天,由于之前没有UIWebView与JS交互的经历,并且觉得这次在功能上有一定的创造性,特此留下一点文字,方便日后回顾. 我要实现这样一个需求:按照本地的CSS ...

  4. iOS与JS开发交互总结

    hybrid.jpg 前言 Web 页面中的 JS 与 iOS Native 如何交互是每个 iOS 猿必须掌握的技能.而说到 Native 与 JS 交互,就不得不提一嘴 Hybrid. Hybri ...

  5. android 从 phonegap 到 js webview 交互

    像生活类.办公协同类. 动态添加,下载等. 1.phonegap 我这里用了旧的版本,可能新版本变化大了. 创建asset资源文件夹,然后新建index.html copy 相应的js 文件进来. 创 ...

  6. Android与H5交互(java与js的交互)

    一.理论概述 1.js调用java方法 直接调用WebView的该方法就可以添加接口了,不过先要启动交互 // 启用javascript mWebView.getSettings().setJavaS ...

  7. android code 和js的交互

    小弟现在需要android code 和js的交互.出现了问题,求大家带一带啊. 我的页面:<!DOCTYPE html><html lang="en">& ...

  8. iOS: 学习笔记, Swift与C指针交互(译)

    Swift与C指针交互 Objective-C和C API经常需要使用指针. 在设计上, Swift数据类型可以自然的与基于指针的Cocoa API一起工作, Swift自动处理几种常用的指针参数. ...

  9. iOS中使用UIWebView与JS进行交互

    iOS中使用UIWebView与JS进行交互 前一段忙着面试和复习,这两天终于考完试了,下学期的实习也有了着落,把最近学的东西更新一下,首先是使用UIWebView与JS进行交互 在webView中我 ...

随机推荐

  1. nginx location分析

  2. Python Selenium element is not reachable by keyboard

    碰到这个问题,没法解决, 最后这么搞的 pcAction.move_by_offset(571, 534).click().perform() #激活输入框 driver.switch_to.acti ...

  3. ManyToManyField 增加记录

    class BOMView(View): def get(self,request): obj=BOMForm() return render(request,'bom.html',{'obj':ob ...

  4. JavaWeb中的资源映射

    一./与/* <url-pattern>/</url-pattern>  会匹配到/login这样的路径型url,不会匹配到模式为*.jsp这样的后缀型url< url- ...

  5. Net中应用 Redis 扩展类

    GIt地址:https://gitee.com/loogn/stackexchange-redis-typedextensions 1.stackexchange 类调用 using System; ...

  6. 关于我在17号“一个查询任意年份中任意月份的天数”程序编写中的代码&第二种方法!

    PS:下面的代码是我对于17号的练习题的一些新的看法(其实就是从另一个角度思考问题) package day20180917;import java.util.Scanner;//导包public c ...

  7. Java字节码浅析(—)

    英文原文链接,译文链接,原文作者:James Bloom,译者:有孚 明白Java代码是如何编译成字节码并在JVM上运行的非常重要,这有助于理解程序运行的时候究竟发生了些什么.理解这点不仅能搞清语言特 ...

  8. AnswerOpenCV(0826-0901)一周佳作欣赏

    1.OpenCV to detect how missing tooth in equipment Hello everyone. I am just starting with OpenCV and ...

  9. php的缓冲/缓存 js对象 ,php编程的深入思考-1

    proto- 表示前缀, 表示"原始的, 主要的, 原型的, 最初的. 所以 prototype: 是原型的意思. webserver服务器apach, 的角色,就像一个 仓库/仓库保管员而 ...

  10. NodeJs 在window中安装使用

    Nodejs: 官网下载长期版本zip格式解压 D:\Program Files\nodejs 查看版本 D:\Git\SpringBootDemo (master) $ node -v v8.11. ...