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一系列的属性等。

代码如下

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

函数调用

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

    self.jsContext = JSContext();
//JS异常处理
self.jsContext?.exceptionHandler = { (jsContext:JSContext!,exception:JSValue!) ->Void in
jsContext.exception = exception;
print(exception);
}
/* js 函数
var func = function(value){
if(value < 0) return;
if(value === 0) return 1;
return value * function(value - 1);
}
*/
//拼接JS
let funStr = "var fun = function (value){" +
"if(value < 0) return;" +
"if(value === 0) return 1;" +
"return value * fun(value - 1);" +
"}";
//打印插入前的函数
print(funStr);
//插入JS
self.jsContext?.evaluateScript(funStr);
//下标获取函数
//let jsFunc = self.jsContext?.objectForKeyedSubscript("fun");
//或者
let jsFunc = self.jsContext?.evaluateScript("fun");
//打印插入后函数,应该和前面一样
print(jsFunc);
//传入参数
let result = jsFunc?.callWithArguments([5]);
//打印结果
print("result = \(result)");

使用闭包

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

    self.jsContext = JSContext();
//JS异常处理
self.jsContext?.exceptionHandler = { (jsContext:JSContext!,exception:JSValue!) ->Void in
jsContext.exception = exception;
print(exception);
}
//往JS注入类
let block = {(name:String,qq:String) -> JSValue in
//let context = JSContext.currentContext();
let object = JSValue(newObjectInContext: self.jsContext);
object.setObject(name, forKeyedSubscript: "name");
object.setValue(qq, forProperty: "qq");
return object;
}
print(block);
self.jsContext?.setObject(block("xuhaiqing","1716329344"), forKeyedSubscript: "User");
//验证是否注入成功
let user = self.jsContext?.evaluateScript("User");
print("user.name = \(user?.objectForKeyedSubscript("name")) and user.qq = \(user?.valueForProperty("qq"))" )

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

    var user = User(name: "xuhaiqing", qq: "1716329344");
user.jsContext = self.jsContext;
user.webView = self.webView;
//关联
print(self.jsContext);
self.jsContext?.setObject(user, forKeyedSubscript: "SwiftModel");
print(user);
//修改关联后的值
self.jsContext?.evaluateScript("SwiftModel.name = 'zhaojiewen'");
self.jsContext?.evaluateScript("SwiftModel.descriptions()");
print(user.name);
print(user.qq);

User 类

    //
// User.swift
// SwiftJSDemo
//
// Created by haodf on 15/11/12.
// Copyright © 2015年 haodf. All rights reserved.
// import Foundation
import UIKit
import JavaScriptCore
@objc protocol UserJsToSwiftDelegate : JSExport{
var name:(String){get set};
var qq:(String){get set};
func callSystemCamera();
func showAlert(title:String,msg:String);
func callWithDict(dic:[String:AnyObject]);
func descriptions();
}
@objc class User :NSObject,UserJsToSwiftDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
var name:(String);
var qq:(String);
var webView:UIWebView?
var jsContext:JSContext?
//author 徐海青
//
//初始化
init(name:(String),qq:(String)){
self.name = name;
self.qq = qq;
}
//author 徐海青
//
//调用系统照相机
@objc func callSystemCamera(){
let imagePickerViewController = UIImagePickerController();
imagePickerViewController.delegate = self;
UIApplication.sharedApplication().keyWindow?.addSubview(imagePickerViewController.view);
UIApplication.sharedApplication().keyWindow?.rootViewController?.addChildViewController(imagePickerViewController);
}
//author 徐海青
//
//弹框显示提示信息
@objc func showAlert(title:String, msg: String) {
//调用系统的alert
// let alertViewController = UIAlertController();
// UIApplication.sharedApplication().keyWindow?.addSubview(alertViewController.view);
// UIApplication.sharedApplication().keyWindow?.rootViewController?.addChildViewController(alertViewController);
//调用JS的alert
let jsValue = self.jsContext?.objectForKeyedSubscript("alertFunc");
jsValue?.callWithArguments([title,msg]); }
//author 徐海青
//
//双向交互
@objc func callWithDict(dic: [String : AnyObject]) {
print(self.jsContext);
let funStr = "var swiftInsertIntoJsFunc = function(arg){" +
"document.getElementById('swiftInsertIntoJsSpan').innerHTML = arg['name'];" +
"}";
//打印插入前的函数
print(funStr);
//插入JS
self.jsContext?.evaluateScript(funStr);
//下标获取函数
//let jsFunc = self.jsContext?.objectForKeyedSubscript("fun");
//或者
let jsFunc = self.jsContext?.evaluateScript("swiftInsertIntoJsFunc");
//let insertFunc = self.jsContext?.objectForKeyedSubscript("swiftInsertIntoJsFunc");
print(dic);
print(jsFunc);
jsFunc?.callWithArguments([dic]);
} //author 徐海青
//
//打印时显示的信息
@objc func descriptions() {
print("user.name = \(self.name) and user.qq = \(self.qq)")
} @objc func imagePickerControllerDidCancel(picker: UIImagePickerController) {
picker.view.removeFromSuperview();
picker.removeFromParentViewController();
} }

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. DOS下读取PCI配置空间信息的汇编程序(通过IOCF8/IOCFC)

    汇编程序编写的读取PCI配置空间信息的代码(通过IOCF8/IOCFC): ;------------------------------------------------ ;功能: 读取PCI 配 ...

  2. A-作业01

    #1 简单作业 1. 系统的日志文件/var/log/secure /var/log/messages /var/log/cron会自动的进行轮询,系统是通过什么实现的? 2. 写出下面特殊符号在定时 ...

  3. php 通过array_merge()和array+array合并数组的区别和效率比较

    众所周知合并两个数组可以使用array_merge(),这是php提供的一个函数.另外还可以通过 array 的方式来合并数组,这两种直接有什么区别,哪一个的效率更高呢? array_merge() ...

  4. Golang两种执行流程以及区别

    Go语言的执行方式有两种,一种是编译后再执行,另一种直接go run执行. 一.先编译后执行 .go文件(源代码)--->go build指令把源代码编译(如果是windows下会编译出一个.e ...

  5. FAT16/32不等于ESP:windows安装程序无法将windows配置为在此计算机的硬件上运行

    今天给公司电脑装系统,由于公司特殊需要,要给新电脑装win7系统.三台完全一样的华硕adol笔记本,前两台都和win10并存装成了双系统,第三台被不懂系统的人尝试装win7搞坏了,只能全盘格式化后再装 ...

  6. Kali linux 2018安装后全屏乱码解决

    安装的时候选择了中文, 后来安装成功后成了全部乱码的. 原因是,系统没有中文字体显示安装包, 下载一个 sudo apt-get install ttf-wqy-zenhei 重启解决!

  7. 2018-2019-1 20189206 《Linux内核原理与分析》第五周作业

    linux内核分析学习笔记 --第四章 系统调用的三层机制 学习重点--系统调用 用户态.内核态和中断 Intel x86 CPU有四种不同的执行级别,分别是0,1,2,3其中数字越小,特权越高. L ...

  8. opencvbase 实现opencv打开摄像头和初步处理等效果操作(附源码)

    // TwoCameraOnTimer2Dlg.cpp : 实现文件 /* CvMat, Mat, IplImage之间的互相转换 IpIImage -> CvMat CvMat mathead ...

  9. Black Hat Python3 Chapter4

    mail sniffer 现在的邮箱应用我能找到的都是加密传输了,因此相像书中那样直接从抓到的包里获取到用户名和密码信息除非是自己专门搭建一个邮箱服务器,不然很难做到,为了便于理解代码的运行,多添加一 ...

  10. Selenium Java Selection的使用

    用于向具有drop-down的选择框中输入内容 new Select(new ChromeDriver().findElement(By.cssSelector(" ..."))) ...