代码地址如下:
http://www.demodashi.com/demo/12754.html

JS-OC-Swift

JS和OC/Swift相互调用,主要总结了JS和OC交互的三种方式

1.使用UIWebView,利用JavaScriptCore实现

2.使用WKWebView,利用WKScriptMessageHandler实现

3.使用第三方框架WebViewJavascriptBridge实现

部分效果图

JavaScriptCore

JavaScriptCore介绍

JavaScriptCore框架是基于webkit中以C/C++实现的JavaScriptCore的一个包装,该框架让Objective-C和JavaScript代码直接的交互变得更加的简单方便,主要由下面几个类组成。

**1.JSContext **

JS执行的环境,同时也通过JSVirtualMachine管理着所有对象的生命周期,每个JSValue都和JSContext相关联并且强引用context。可以通过[webView valueForKeyPath:@”documentView.webView.mainFrame.javaScriptContext”]来从webview上获取相应的JSContext。

**2.JSValue **

JS对象在JSVirtualMachine中的一个强引用,其实就是Hybird对象。我们对JS的操作都是通过它。并且每个JSValue都是强引用一个context。同时,OC和JS对象之间的转换也是通过它。

**3.JSManagedValue **

JS和OC对象的内存管理辅助对象。由于JS内存管理是垃圾回收,并且JS中的对象都是强引用,而OC是引用计数。如果双方相互引用,势必会造成循环引用,而导致内存泄露。我们可以用JSManagedValue保存JSValue来避免。

**4.JSVirtualMachine **

JS运行的虚拟机,有独立的堆空间和垃圾回收机制。

**5.JSExport **

一个协议,如果JS对象想直接调用OC对象里面的方法和属性,那么这个OC对象只要实现这个JSExport协议就可以了。

在Swift中获取JS的context

context = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as? JSContext

注入JS需要的对象,对象命名与html中使用的保持一致.self是遵守了JSExport协议,也可是其他遵守协议的对象。

context?.setObject(self, forKeyedSubscript:  "OC" as NSCopying & NSObjectProtocol)

JS调用Swift的方法,在Swift中实现协议

@objc protocol JSDelegate :JSExport {
//包含参数的func,需要注意参数名对函数名称的影响
func showMessageToYou(_ message:String) /*
对应html中“showAAndB”,此方法包含两个参数,需要在参数前加“_”
func showA(_ aString: String, andB: String)
func showAAndB(_ aString:String,_ bStr:String)
以上两个方法等同
*/
func showAAndB(_ aString:String,_ bStr:String) func doActionCallBack()
}

Swift调用JS的方法

let jsStr = String(format:"callback('%@')",(textField?.text)!)
self.context?.evaluateScript(jsStr)

OC中可使用block和实现JSExport协议两种方式实现,代码实现:

JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.context = context;
//注入JS需要的“OC”对象,该对象与html中的保持一致即可
self.context[@"OC"] = self;

WKScriptMessageHandler

初始化WKWebView后,添加供js调用oc/Swift的桥梁,这里的name对应WKScriptMessage中的name

webView.configuration.userContentController.add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)

遵守协议WKScriptMessageHandler,实现以下方法,可实现JS把消息发送给OC/Swift。

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)

OC/Swift调用JS

let jsStr = String(format:"callback('%@')",(textField?.text)!)
self.webView.evaluateJavaScript(jsStr as String, completionHandler: { (result:Any?, error:Error?) in
print("error:",error as Any)
})

WebViewJavascriptBridge

WebViewJavascriptBridge是一个Objective-C与JavaScript进行消息互通的第三方库,可以很方便的实现OC和Javascript互调的功能。WebViewJavascriptBridge实现互调的过程也容易理解,就是在OC环境和Javascript环境各自保存一个相互调用的bridge对象,每一个调用之间都有id和callbackid来找到两个环境对应的处理。从Github上下载源码之后,可以看到核心类主要包含如下几个:

WebViewJavascriptBridge_JS:Javascript环境的Bridge初始化和处理。负责接收OC发给Javascript的消息,并且把Javascript环境的消息发送给OC。

WKWebViewJavascriptBridge/WebViewJavascriptBridge:主要负责OC环境的消息处理,并且把OC环境的消息发送给Javascript环境。

WebViewJavascriptBridgeBase:主要实现了OC环境的Bridge初始化和处理。

初始化WKWebViewJavascriptBridge

self.webViewBridge = [WKWebViewJavascriptBridge bridgeForWebView:self.webView];
[self.webViewBridge setWebViewDelegate:self];

JS调用OC需要注册事件

[self.webViewBridge registerHandler:@"handlerName" handler:^(id data, WVJBResponseCallback responseCallback) {
//code
}];

OC调用JS

[self.webViewBridge callHandler:@"handlerName" data:@[textField.text] responseCallback:^(id responseData) {
NSLog(@"%@",responseData);
}];

html中需要放置以下代码

/*这段代码是固定的,必须要放到js中*/
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
/*与OC交互的所有JS方法都要放在此处注册,才能调用通过JS调用OC或者让OC调用这里的JS*/
setupWebViewJavascriptBridge(function(bridge) {
bridge.registerHandler('callback', function(data, responseCallback) {
callback(data);
responseCallback('js执行过了'+data);
})
})

项目结构

JS与原生OC/Swift相互调用总结

代码地址如下:
http://www.demodashi.com/demo/12754.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

JS与原生OC/Swift相互调用总结的更多相关文章

  1. iOS下JS与原生OC互相调用(总结)

    这是去年总结的一篇文章,也一并先放到这个目录下好了. iOS开发免不了要与UIWebView打交道,然后就要涉及到JS与原生OC交互,今天总结一下JS与原生OC交互的两种方式. JS调用原生OC篇 方 ...

  2. Swift与OC的相互调用

    Swift经过四年的发展已经趋于成熟,是时候学一下了,感谢公司swift大佬的不吝赐教.心有所感记录一下,如有不足欢迎指正批评. 新建swift项目 新建Swift.OC类文件 可在新建OC文件时,建 ...

  3. js和vue方法的相互调用(iframe父子页面的方法相互调用)。

    项目是前后端不分离的,模板引擎使用的JSP. 但是使用了Vue+ElementUI,这里列举一些常用的调用方式,有时候可能. 在js里调用vue方法 我们需要把方法注册到vue对象之外的页面,所以对与 ...

  4. iOS OC与swift相互调用

    小哥("我"的自称)个人混编的时候喜欢先创建OC项目,然后在项目中创建swift类.这样有个好处就是桥文件可以自动创建的同事路径不需要我手动去写了,另外还有个目的就是现在小哥自我感 ...

  5. OC与swift相互调用

    一.OC调用swift文件 二.swift调用OC文件 三.注意和总结 添加: 四.自定义桥接文件 一.OC调用swift文件 在OC项目中创建一个swift文件的时候,Xcode 会提示 需要创建一 ...

  6. iOS开发--JS调用原生OC篇

    JS调用原生OC篇 方式一(反正我不用) 第一种方式是用JS发起一个假的URL请求,然后利用UIWebView的代理方法拦截这次请求,然后再做相应的处理. 我写了一个简单的HTML网页和一个btn点击 ...

  7. WebView中Js与Android本地函数的相互调用

    介绍 随着Html5的普及,html在表现力上不一定比原生应用差,并且有很强的扩展兼容性,所以越来越多的应用是采用Html与Android原生混合开发模式实现. 既然要实现混合开发,那么Js与Andr ...

  8. Hybrid App开发模式中, IOS/Android 和 JavaScript相互调用方式

    IOS:Objective-C 和 JavaScript 的相互调用 iOS7以前,iOS SDK 并没有原生提供 js 调用 native 代码的 API.但是 UIWebView 的一个 dele ...

  9. iOS下JS与原生的交互一

    本篇主要讲的是UIWebView和JS的交互,在下一节会有wkWebView和JS交互的详解https://www.cnblogs.com/llhlj/p/9144110.html JS调用原生OC ...

随机推荐

  1. Sqlite 教程

    http://www.runoob.com/sqlite/sqlite-functions.html

  2. hdu 5163(前缀和+分类讨论)

    Taking Bus Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  3. 天猫首页迷思之-jquery实现左侧广告牌图片轮播

    本次要实现的是天猫首页每个楼层左侧的图片轮播效果.见图: 功能点有:点击右箭头向右滑动:点击左箭头向左滑动:什么都不点自动滑动. 1.实现样式.简单分析一下大概的html结构.一个大的div里面包含两 ...

  4. J.U.C并发框架源码阅读(十三)ThreadPoolExecutor

    基于版本jdk1.7.0_80 java.util.concurrent.ThreadPoolExecutor 代码如下 /* * ORACLE PROPRIETARY/CONFIDENTIAL. U ...

  5. 洛谷 ——2925干草出售Hay For Sale

    题目描述 Farmer John suffered a terrible loss when giant Australian cockroaches ate the entirety of his ...

  6. C++模拟链表

    C++模拟链表 简易模拟链表,工厂设计模式.. 注意:请不要在操作时产生环状链表,会造成输出链表时陷入无限循环. #include <iostream> #include <stri ...

  7. ReactiveCocoa(二)

    前言 通过ReactiveCocoa(一)的学习,相信大家对ReactiveCocoa有了一些基本认识吧.下面就让我们来学习ReactiveCocoa的一些基本使用吧! ReactiveCocoa基本 ...

  8. 解魔方的机器人攻略14 – 安装Lejos(下)

    由 动力老男孩 发表于 2009/12/27 17:16:11 第四步:安装Lejos 登陆 Lejos 主页点击 NXT 图片进入 Lejos 下载页面,点击 NXJ 的下载链接: 下载完成后将下载 ...

  9. Bluetooth篇 开发实例之五 为什么无线信号(RSSI)是负值?

    原文:http://www.cnblogs.com/lele/articles/2832885.html   为什么无线信号(RSSI)是负值 答:其实归根到底为什么接收的无线信号是负值,这样子是不是 ...

  10. How to Use Auto Layout in XCode 6 for iOS 7 and 8 Development

    The Auto Layout is available on the Storyboard for iOS or OS X development since XCode 5. But, I did ...