WebViewJavascriptBridge机制解析

简介:

众所周知WebViewJavaScriptBridge是一个iOS/OSX 在UIWebViews/WebViews中obj-C和javascript发送消息的一个桥接。

WebViewJavaScriptBridge的开源项目在此:这里

下面我们来对WebViewJavaScriptBridge的机制来进行分析:(以UIWebView为例)

一、obj-c调用javascript的机制

UIWebView是iOS最常用的SDK之一,它有一个stringByEvaluatingJavaScriptFromString方法可以将javascript嵌入页面中,通过这个方法我们可以在iOS中与UIWebView中的网页元素交互。

使用stringByEvaluatingJavaScriptFromString方法,需要等UIWebView中的页面加载完成之后去调用。 

使用例子介绍:

[webView stringByEvaluatingJavaScriptFromString:@"document.location.href"]     //获取当前页面的url。

[webview stringByEvaluatingJavaScriptFromString:@"document.title"]     //获取页面title:

[webView stringByEvaluatingJavaScriptFromString:@"document.forms[0].submit();"] //表单提交:

从以上可以看出stringByEvaluatingJavaScriptFromString不仅可以执行js来获取信息,还可以通过调用js对webView执行操作。 所以可以通过此函数来实现obj-c到js的交互。

备注: stringByEvaluatingJavaScriptFromString这个方法有个地方需要注意, 算不上bug, 但确实有问题, 需要注意!

如果stringByEvaluatingJavaScriptFromString执行的是带参数的js函数, 这个参数里面如果带有(\r \n ')等等, js那边收不到这个值, 这些带\的需要转义,

二、 javascript调用obj-c

UIWebView对URL的跳转进行拦截,可以通过自定义协议来捕获请求,在通过obj-c的stringByEvaluatingJavaScriptFromString来获取js对于obj-c函数的调用。

UIWebView对于跳转的拦截方法:

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {

}

实质上oc与js的通信交互就是发送消息,也即函数调用,只要在交互的过程正确的指定好对方需要调用的函数和参数就ok

oc-->js   stringByEvaluatingJavaScriptFromString,其参数是一NSString 字符串内容是js代码(这又可以是一个js函数、一句js代码或他们的组合),当js函数有返回值或一句js代码有值返回可通过stringByEvaluatingJavaScriptFromString的返回值获取

js-->oc 利用webView的重定向原理(即重新在js中指定document.location的值,此为一url),只要在这个url字符串中按自定义的规则指定好所需调用oc中的函数和参数,然后通过OC中的shouldStartLoadWithRequest函数去捕获处理请求,处理完最后,如果js还想获取一些返回参数的话,同样让oc去通过stringByEvaluatingJavaScriptFromString调用刚js传过来的回调js函数就行,顺道把参数也一起传了。

三、WebViewJavaScriptBridge实现机制

webViewJavaScriptBridge 包含三个文件:

WebViewJavascriptBridge.h

WebViewJavascriptBridge.m

WebViewJavascriptBridge.js.txt

很明显:WebViewJavascriptBridge.js.txt主要用于衔接UIWebView中的web page,而WebViewJavascriptBridge.h/m则主要用于与ObjC的native code打交道。他们作为一个整体,其实起到了一个“桥梁”的作用,这三个文件封装了他们具体的交互处理方式,只开放出一些对外的涉及到业务处理的API,因此你在需要UIWebView与Native code交互的时候,引入该库,则无需考虑太多的交互上的问题。整个的Bridge对你来说都是透明的,你感觉编程的时候,就像是web编程的前端和后端一样清晰。他们使用交互如图所示:

1240

WebViewJavaScriptBridge交互图

下面我们对WebViewJavaScriptBridge的实现做出分析。

3.1 WebViewJavaScriptBridge中的初始化

WebViewJavaScriptBridge的初始化过程如下:

1. 初始化需要使用的数据结果

2. 保存registerHandler的函数名与block

3. webView 加载完成载人js代码

具体流程图如下:

1240

bridge初始化流程图

3.1 obj-c与js的交互

obj-c与js交互使用的机制是一样的,所以单项调用的处理是混在一起,所以现在按照流程单独梳理,最后在以源码为例来说明。

3.1.1 obj-c调用js过程:


1、obj-c保存回调的block,使用唯一码objc_cb_* 标识

2、obj-c拼装data(数据),handlerName(调用名),回调标识等信息

3、 对信息进行json拼装,及js一些字符的转码

4、 执行js端的分发消息的函数

5、js执行完成,执行函数块,调用register的responseCallback,发送responseId和responseData

6、 js拼装信息到消息队列中,URL重定向;obj-c端拦截请求,执行js代码拉取数据

7、obj-c端根据responseId来取得保存的block,执行block

大致流程图如下:

1240

obj-c调用js流程图


3.1.2 js调用obj-c的过程:


1、js端保存data与handlerName的映射

2、js端生成唯一码callbackId保存responseCallback映射,并封装callbackId到发送消息中

3、js端封装后的消息放入发送消息队列中, 并执行URL重定向

4、obj-c端拦截请求,判定是自定义协议后,执行js的_fetchQueue()拉取发送的信息

5、obj-c端重新封装responcallback 的block,执行时调用_queueMessage进行消息分发

6、从obj-c端的注册队列中获取handler的block,并执行

7、执行后回调block,封装了responseId和responseData数据,并进行分发

8、数据的特殊字符处理,调用js的函数_handleMessageFromObjC()来传递消息

9、js获取分发的responseId,获取保存在队列中的function

大致的流程图如下:

1240

js调用obj-c流程图

3.2 源码解读

3.2.1 obj-c端源码

因js调用涉及到自定义协议的重定向,因此定义了协议及host

#define kCustomProtocolScheme @"wvjbscheme"

#define kQueueHasMessage@"__WVJB_QUEUE_MESSAGE__"

WebViewJavaScriptBridge的初始化因为涉及到OSX端WebView与iOS端UIWebView,故根据不同的系统来做变量的统一定义,如下:

1240

OS X与iOS变量重定义

定义block,WVJBResponseCallback定义了回调block,js返回数据后回调。WVJBHandler定义了register的block,用作不同情况下的处理。

typedef   void(^WVJBResponseCallback)(id  responseData);

typedef   void(^WVJBHandler)(id   data,WVJBResponseCallback   responseCallback);

obj-c外部接口,用于native调用使用。其中register与callhandler函数封装数据后调用send处理。

1240

obj-c与js交互函数

send函数发送消息到js端的源码:

1240

send封装到调用js代码

参数data为传递给js函数的参数,可为NSString、NSDictionary等,responseCallback则为obj-C的回调,此回调函数执行流程简述为“js注册函数执行完毕后,会返回带有responseId的消息,最后在obj-c会取出(回调存储在responCallbacks字典中),并执行”,handlerName则为js定义的函数名称。

源码中在_queueMessage方法进行逻辑判断:若在H5頁面或者js资源并未加载完毕时,在obj-C的webview中就调用了js函数,则会把相关的操作(存储为Message格式)存储在startupMessageQueue,等待相关资源加载完毕(即在webview的webViewDidFinishLoad生命周期函数中执行存储在startupMessageQueue的命令数组,执行完毕并清除改队列)再調用js的函数;否則若startupMessageQueue队列为空,则直接执行暴露在js端的webViewJavascriptBridge.handleMessageFromObjC函数,获取被调用的函数名和传人参数,以及在objC的sendData:responseCallback:handlerName中设置的回调函数id—callbackId,最终执行js注册函数,并最终想obj-c端发送“doSend({ responseId:callbackResponseId, responseData:responseData })”格式的消息,待objC接收到消息,解析responseId,执行回调函数。


webView载入H5的delegate函数:

1240

finishLoad函数

H5 页面载入完成后,载入js资源,在对开始消息队列中的数据进行处理,并置nil。 在把delegate抛出。

1240

url拦截

有重定向请求时,首先判断scheme及host是自定的,使用_flushMessageQueue函数处理。

1240

obj-c端对js端处理

这段代码通过回传消息的responseId来判断是回调还是call,来进行不同的解封调用。

3.2.2 js端源码

js端定义的WebViewJavascriptBridge对象:

1240

js端WebViewJavascriptBridge类

js端的交互函数,逻辑处理,一个registerHandler和一个callHandler主要封装。_dosend函数进行消息封装放入发送消息队列,在产生一个src(url scheme),供obj-c端shouldStartLoadWithRequest捕捉

1240

消息交互函数

obj-c端通过_fetchQueue()获取发送的消息

1240

js拉取发送的消息

js中处理来自objc的消息,判断同obj-c获取到js端的消息

1240

_dispatchMessageFromObjC



文/木夜溯(简书作者)
原文链接:http://www.jianshu.com/p/8bd6aeb719ff#
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。














本文转自ljianbing51CTO博客,原文链接: http://blog.51cto.com/ljianbing/1856657,如需转载请自行联系原作者





相关文章
|
3天前
|
存储 缓存 安全
第二章 HTTP请求方法、状态码详解与缓存机制解析
第二章 HTTP请求方法、状态码详解与缓存机制解析
|
4天前
|
PHP 项目管理 开发者
深入解析PHP的命名空间和自动加载机制
【4月更文挑战第4天】 在PHP的编程世界中,命名空间和自动加载机制是构建大型应用程序时不可或缺的工具。本文将深入探讨这两个概念,揭示它们如何简化代码结构、避免类名冲突以及提高代码维护性。通过对PHP命名空间的由来、作用域和使用方法的细致剖析,以及对自动加载机制工作原理和应用实践的全面讲解,读者将获得有效管理复杂项目中依赖关系的能力。
|
4天前
|
传感器 安全 中间件
深入浅出:SOME/IP协议中的服务发现机制解析
深入浅出:SOME/IP协议中的服务发现机制解析
92 0
|
4天前
|
存储 机器学习/深度学习 搜索推荐
深入解析矢量数据库的数据模型与索引机制
【4月更文挑战第30天】本文深入探讨了矢量数据库的数据模型和索引机制。向量数据库以高维向量表示数据,采用稀疏或密集向量形式,并通过数据编码和组织优化存储与检索。索引机制包括基于树的(如KD-Tree和Ball Tree)、基于哈希的(LSH)和近似方法(PQ),加速相似性搜索。理解这些原理有助于利用矢量数据库处理大规模高维数据,应用于推荐系统、图像搜索等领域。随着技术发展,矢量数据库将扮演更重要角色。
|
4天前
|
监控 Java
解析Java线程池的异常处理机制
该内容是一个关于Java线程和线程池异常处理的总结。提到的关键点包括: 1. 引用了滑动验证页面和相关文章资源。 2. 区分了`execute`与`submit`在处理线程异常时的区别,`submit`可能会捕获并隐藏异常,而`execute`会直接抛出。 3. 提供了处理线程和线程池异常的建议,如使用try/catch直接捕获,或者自定义线程工厂和未捕获异常处理器。 4. 示例代码展示了如何通过设置`UncaughtExceptionHandler`来监控和处理线程中的异常。 请注意,由于字符限制,这里只提供了简要摘要,详细解释和代码示例请参考原文。
24 3
|
4天前
|
资源调度 算法 Linux
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
219 0
|
1天前
|
存储 Java 程序员
【Python 的内存管理机制专栏】深入解析 Python 的内存管理机制:从变量到垃圾回收
【5月更文挑战第18天】Python内存管理关乎程序性能与稳定性,包括变量存储和垃圾回收。变量存储时,如`x = 10`,`x`指向内存中值的引用。垃圾回收通过引用计数自动回收无引用对象,防止内存泄漏。了解此机制可优化内存使用,避免循环引用等问题,提升程序效率和稳定性。深入学习内存管理对成为优秀Python程序员至关重要。
【Python 的内存管理机制专栏】深入解析 Python 的内存管理机制:从变量到垃圾回收
|
4天前
|
PHP 开发者
深入解析PHP的命名空间与自动加载机制
【4月更文挑战第30天】 在现代PHP开发实践中,命名空间和自动加载机制是模块化和代码复用的关键。本文旨在提供一个全面的视角来理解这两个概念如何协同工作以优化项目结构。我们将探讨命名空间解决代码冲突的方式,以及自动加载机制如何智能地按需加载类,从而减少内存占用和提升性能。
|
4天前
|
算法 安全 Linux
深度解析:Linux内核内存管理机制
【4月更文挑战第30天】 在操作系统领域,内存管理是核心功能之一,尤其对于多任务操作系统来说更是如此。本文将深入探讨Linux操作系统的内核内存管理机制,包括物理内存的分配与回收、虚拟内存的映射以及页面替换算法等关键技术。通过对这些技术的详细剖析,我们不仅能够理解操作系统如何高效地利用有限的硬件资源,还能领会到系统设计中的性能与复杂度之间的权衡。
|
4天前
|
缓存 Java Python
Python 弱引用全解析:深入探讨对象引用机制!
Python 弱引用全解析:深入探讨对象引用机制!
22 3

推荐镜像

更多