EasyJsWebView 源码分析

 

最近在做hybrid相关的工作,项目中用到了EasyJsWebView,代码量不大,一直想分析一下它的具体实现,抽空写了这篇文章。

1.前言

原生代码+h5页面+甚至React Native(或其他) 的方式开发移动客户端已经成为当前的主流趋势,因此老生常谈的一个问题就是原生代码与js的交互。原生代码中执行js代码,没什么可讲的直接webView执行js代码即可,本文主要由安卓的js调用原生的方式切入,分析iOS端是如何实现类似比较方便的调用的。

2.安卓端(js -> native interface)

对安卓的开发不是很熟,只是列举一个简单的例子讲述这样一种方式。

  • native端

  • h5端

当h5页面加载时,onload方法执行,对应的native端中的Contact类中的showcontacts方法被执行。因此核心思想就是通过webView将native原生的类与自定义的js对象关联,js就可以直接通过这个js对象调用它的实例方法。

3.iOS端(js -> native interface)

上述安卓的js调用native的方式是如此简单明了,不禁想如果iOS端也有如此实现的话,这样同时即保证安卓,iOS,h5的统一性也能让开发者只用关心交互的接口即可。因此便引出了EasyJSWebView的第三方的框架(基于说明2设计),下面从该框架的使用出发,分析框架的具体实现。

说明:

  • 1.iOS端虽然也可以通过JSContext注入全局的方法但是达不到与安卓端统一
  • 2.iOS端可以通过拦截h5请求的url,通过url的格式区分类或方法,但是这样不够直观,也达不到与安卓端统一

4.EasyJsWebView

4.1 EasyJsWebView使用

本文直接列举EasyJsWebView Github README例子

  • native端

  • js端

4.2 EasyJsWebView具体实现

4.2.1 EasyJsWebView初始化

初始化设置webView的delegate,实际的webView的回调的在EasyJSWebViewProxyDelegate中实现,因此我们主要关注EasyJSWebViewProxyDelegate中的webView的回调的实现即可。

4.2.2 EasyJSWebViewProxyDelegate webView回调实现

4.2.2.1 webViewDidStartLoad回调实现

代码片段一:

  • 遍历注入的接口的列表key
  • 通过key获取注入类的实例
  • 通过类的实例获取实例方法的列表
  • 依次拼接需要执行js函数的代码
  • EasyJS对象的加载,执行EasyJS.inject方法

例子:参考Demo调试结果如下

4.2.2.2 EasyJS对象

代码片段一:

遍历注入的类的实例方法的列表,通过一个全局的window[obj]的字典维护对应方法的具体实现。下面我们具体看看EasyJS.call方法的实现。

代码片段二:

这段代码做了三件事:

  • 1.分别针对参数function类型与其他类型区分处理
  • 2.创建一个IFRAME标签元素,设置src
  • 3.将新建的IFRAME添加到root元素上

修改IFRAMEsrc默认会触发webView的回调的执行,因此便有了下面方法shouldStartLoadWithRequest的拦截。

4.2.2.3 shouldStartLoadWithRequest回调实现

代码片段一:

  • 1.拆分拦截到的requestString拆分为obj,method,formattedArgs三个部分
  • 2.获取类实例方法的签名,新建一个NSInvocation实例,指定实例与方法
  • 3.invoker设置参数,然后执行invoke,注意参数中function类型的区分,以下5中会分析回调function的处理过程。

代码片段二:

获取invoker执行的结果通过webView执行js代码返回结果值。

5.EasyJSDataFunction 与 invokeCallback

以下主要分析EasyJsWebView是如何处理回调方法参数的。

代码片段一:

js端call方法这样处理function参数,EasyJS对象一个全局的__callbacks字典存储方法实现对象

代码片段二:

native端拦截到请求,执行方法

代码片段三:

回调方法执行,将回调方法执行参数解析封装js函数字符串,注意前两个参数第一个表示js函数的唯一ID方便js端找到该函数对象,第二个表示第一次回调完成是否移除该回调执行的函数对象的bool值,然后webView主动执行,这样就完成个整个的回调过程。

例子:Demo回调执行语句调试

6.存在问题

见如下代码我们分析实现会发现jsObj全局字典方法区分的key是方法名的拼接,且去处了连接符号:,因此产生疑问这样可能还是会出现同一个key对应不同的方法。

鉴于以上的疑问我改了一下Demo工程,MyJSInterface增加一个实现的接口

这样就会与以下方法冲突

Demo改成如下调用

抛出异常,原因就是js方法全局字典的keytestWithTwoParamAndParam2所对应的方法被下一个方法覆盖。

解决:

  • 1.可以尽量避免重名问题
  • 2.也可以替换分隔符号”:”用其他特殊字符替换

本文结,本人还在不断学习积累中,如果对文章有疑问或者错误的描述欢迎提出。
或者你有hybrid iOS一块比较好的实现也欢迎分享大家一起学习,谢谢!!!

1 2 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部