当前位置: 首页 > 后端技术 > Node.js

从微信JS-SDK理解JSBridge

时间:2023-04-03 16:04:19 Node.js

前言前段时间因为需要在H5移动端实现拉取微信卡包和同步卡包数据的功能,微信JS的相关包实现功能-项目中引入了SDK(jweixin)。不过这也让我很好奇,于是打算仔细了解一下相关内容,通过查阅相关资料发现这其实是JSBridge的一种实现方法。因此,只要了解了JSBridge,就可以了解微信JS-SDK是怎么回事了。为什么需要JSBridge?我相信大多数人都有同样的经历。第一次了解JSBridge是从微信JS-SDK(WeiXinJSBridge)。当然,如果你是从事Hybrid应用或者React-Native开发的,相信你自然会(should,will)熟知。其实JSBridge已经出现并在实践中使用了很长时间,比如早先的桌面应用的消息推送,但是在移动端普及的时代,越来越需要JSBridge,因为我们期望移动端(Hybrid应用或者React-Native)能够做更多的事情,包括使用客户端原生功能提供更好的交互和服务。但是JavaScript不能直接调用不同语言(如Java、C/C++等)提供的特性,因此需要一个中间层来实现JavaScript与其他语言的相互协作。这里用一个Node架构来说明。Node架构的核心内容如下:顶层的NodeApi提供了http模块、stream模块、fs文件模块等,可以通过JavaScript直接调用中间层NodeBindings主要是让JavaScript和C/C++实现通信,因为JavaScript不能直接调用C/C++库(libuv),需要一个中间桥梁。Node提供了许多绑定。这些称为节点绑定。底层的V8+libuvv8负责解释和执行顶层的JavaScript代码。libuv负责提供I/O相关的操作。它的主要语言是C/C++语言,其目的是实现一个跨平台(如Windows、Linux等)的异步I/O库,直接与操作系统交互。不难发现,NodeBindings有一个类似JSBridge的功能,所以JSBridge本身就是一个很简单的东西,更多的是一种形式,一种思想。为什么叫JSBridge?StackOverflow的联合创始人JeffAtwood在2007年的博客《The Principle of Least Power》中相信“任何可以用JavaScript编写的应用程序最终都会用JavaScript编写”。做各种各样的事情,网页、APP、小程序、后端等等,各种相关的生态也越来越丰富。JavaScript作为Web技术的逻辑核心,自然需要承担起与其他技术“桥接”的责任,而任何移动操作系统都会包含一个运行JavaScript的容器环境,如WebView、JSCore等,这意味着运行JavaScript不需要像其他语言运行时,需要添加相应的运行环境。由于微信的出现,JSBridge应用程序在中国真正流行起来。当时微信的主要功能之一就是通过JSBridge分享网页内容。JSBridge能做什么?举个最常见的前后端的例子,后端只提供了搜索接口,没有提供更新接口,所以前端没办法实现更新接口!同样,JSBridge能做什么,取决于native端提供了哪些函数供JavaScript调用Native函数。直接使用微信独有的分享、扫一扫、优惠券、支付等功能。JSBridge是JavaScript和Native之间的桥梁。从表面上看,它允许JavaScript调用Native函数,但其??核心是在Native和非Native消息之间建立双向通信通道。双向通信通道:JavaScript向Native发送消息:调用Native函数通知NativeJavaScript当前状态等Native向JavaScript发送消息:回溯调用结果消息推送通知JavaScript当前Native状态等HowJSBridge实现了吗?JavaScript的运行需要JS引擎的支持,包括ChromeV8、FirefoxSpiderMonkey、SafariJavaScriptCore等,简而言之,JavaScript运行环境与原生运行环境是天然隔离的。因此,在JSBridge的设计中,我们可以类比JSONP的过程:客户端通过JavaScript定义一个回调函数,如:functioncallback(res){...},将回调函数的名称发送给参数形式的服务器。服务端获取回调并携带相应的返回数据。以JS脚本的形式返回给客户端。客户端接收并执行相应的JS脚本。JSBridge实现JavaScript调用的方式有两种,具体如下:JavaScript调用NativeNative调用JavaScript在开始分析具体内容之前,有必要了解一下WebView的前置知识。什么是WebView?WebView是一种将移动APP嵌入到Web中的原生系统技术。方法是构建一个高性能的webkit内核浏览器,一般在SDK中封装为WebView组件。WebView除了具备一般View的属性和设置外,还增强了url请求、页面加载、渲染、页面交互等功能,提供更强大的功能。WebView的优势在于当页面布局需要更新或者业务逻辑发生变化时,可以更方便的提供APP更新:对于WebView来说,只需要修改前端的Html、Css、JavaScript等即可结束部分,并通知用户刷新。对于Native需要修改前端内容,然后打包升级,重新发布,通知用户下载更新,安装后使用最新内容。微信小程序中WebView小程序的主要开发语言是JavaScript,其中逻辑层和渲染层是分开的,运行在不同的线程中,渲染层运行在WebView上:运行环境逻辑层渲染层iOSJavaScriptCoreWKWebViewAndroidV8chromium自定义内核小程序开发者工具NWJSChromeWebView在开发过程中遇到了一个坑重点是:在真机中,需要实现同域名下不同子路径的应用程序之间的数据交互(纯前端操作,不涉及接口)。),而这个数据是临时数据,所以用sessionStorage来实现数据交互是非常合适的。其实从A应用跳转到B应用是获取不到相应数据的,这是因为sessionStorage是基于当前窗口的session级别的在手机浏览器或者微信内置浏览器跳转到新页面的时候,可能会打开一个新的WebView,相当于在浏览器中存储了一个新的窗口,所以没有办法读取上一个窗口存储的数据JavaScript调用Native——实现方案1通过JavaScript调用Native的方法将分为:注入API劫持URLScheme弹窗拦截【注入API】核心原理:通过WebView提供的接口,在JavaScript上下文(窗口)中注入对象或方法让JavaScript调用时,直接执行相应的Native实现JavaScript调用Native的代码逻辑。这里就不通过iOS的UIWebView和WKWebView的注入方式来介绍了。有兴趣的可以自己找。资料直接通过微信JS-SDK看一下吧。引入JS-SDK时,可以在页面API中使用微信相关,例如://微信授权window.wx.config(wechatConfig)//授权回调window.wx.ready(function(){...})//异常处理window.wx.error(function(err){...})//拉起微信名片包window.wx.invoke('chooseInvoice',invokeConf,function(res){...})如果是内部编译打包的代码(简化版),不难发现此时this(即参数e)指向的是全局window对象。代码中使用的window.wx其实就是e.jWeixin也是里面定义的N对象。其中定义的各种方法,其实都是通过e.WeixinJSBridge上的方法来执行的。e.WeixinJSBridge是通过微信内置浏览器向window对象注入WeiXinJsBridge接口实现的!(function(e,n){'function'==typeofdefine&&(define.amd||define.cmd)?define(function(){returnn(e)}):n(e,!0)})(this,function(e,n){...functioni(n,i,t){e.WeixinJSBridge?WeixinJSBridge.invoke(n,o(i),function(e){c(n,e,t)}):u(n,t)}if(!e.jWeixin){varN={config(){我(...)},就绪(){},错误or(){},...}return(S.addEventListener('error',callback1,!0),S.addEventListener('load',callback2,!0),n&&(e.wx=e.jWeixin=N),N)}})【劫持URLScheme】什么是URLScheme?URLScheme是一个特殊的URL,一般用于在Web上唤醒App(或者跳转到App的某个页面)。可以方便的实现App之间的相互调用(比如QQ和微信互相分享信息)就是protocol和host一般都是为对应的APP定制的。通常App在安装时,会在系统上注册一个自定义的URLScheme,比如weixin://,那么当我们在手机浏览器中访问这个scheme地址时,系统就会调用相应的App。比如你在浏览器中访问weixin://,浏览器会询问你是否需要打开对应的APP:然后Native拦截它的Request,根据URLScheme和携带的参数进行相应的操作。例如,对于谷歌浏览器,你可以通过chrome://version/,chrome://chrome-urls/,chrome://settings/定位不同的页面内容,假设你跳转到谷歌的设置页面,期望当前搜索引擎换成百度,可以这样设计chrome://settings/engine?changeTo=baidu&callbak=callback_id:谷歌客户端可以拦截这个请求,解析对应的参数changeTo修改默认引擎,然后使用WebView上的callbacks对象根据callback_id回调以上只是一个假设,并不是说真的可以这样修改谷歌浏览器,当然如果真的支持的话也不是不可以。是不是感觉和JSONP的流程真的很像~~【弹窗拦截】弹窗拦截的核心:是通过弹窗触发WebView的相应事件来实现的。一般是拦截Prompt、Confirm、Alert等方法,然后解析它们传递过来的消息,但是这种方法的缺陷是iOS中的UIWebView不支持,而iOS中的WKWebView有更好的scriptMessageHandler,所以是很容易很难统一。Native调用JavaScript——实现方案2Native调用JavaScript的本质是执行拼接的JavaScript字符串,就像我们使用eval()函数执行JavaScript字符串形式的代码一样。不同的系统也有相应的方法来执行JavaScript脚本。Android在Android中需要根据版本来区分:Android4.4之前的版本使用loadUrl()loadUrl()无法获取JavaScript执行后的结果,这个方法比较像href属性中写的JavaScript代码webView.loadUrl("javascript:foo()")Android4.4及以上使用evaluateJavascript()webView.evaluateJavascript("javascript:foo()",null);IOS需要根据不同的WebView来区分:UIWebView通常使用stringByEvaluatingJavaScriptFromStringresults=[self.webViewstringByEvaluatingJavaScriptFromString:"foo()"];WKWebView通常使用evaluateJavaScript[self.webViewevaluateJavaScript:@"document.body.offsetHeight;"completionHandler:^(id_Nullableresponse,NSError*_Nullableerror){//获取返回值}];最后,以上是通过微信JS-SDK对JSBridge的简单介绍。大家不要觉得JSBridge是个高深莫测的东西。毕竟其核心思想清晰明了,本质上还是需要强烈依赖native端的具体实现。希望本文对您有所帮助!!!本文参加了SegmentFault思维写作挑战赛,欢迎正在阅读的你加入。