从 微信 JS-SDK 认识 JSBridge

2023-11-19

前言

前段时间由于要实现 H5 移动端拉取微信卡包并同步卡包数据的功能,于是在项目中引入了 微信 JS-SDK(jweixin)[1] 相关包实现功能,但也由此让我对其产生了好奇心,于是打算好好了解下相关的内容,通过查阅相关资料发现这其实属于 JSBridge 的一种实现方式。

因此,只要了解 JSBridge 就能明白 微信 JS-SDK 是怎么一回事。

为什么需要 JSBridge?

相信大多数人都有相同的经历,第一次了解到关于 JSBridge 都是从 微信 JS-SDK(WeiXinJSBridge) 开始,当然如果你从事的是 Hybrid 应用React-Native 开发的话相信你自然(应该、会)很了解。

其实 JSBridge 早就出现并被实际应用了,如早前桌面应用的消息推送等,而在移动端盛行的时代已经越来越需要 JSBridge,因为我们期望移动端(Hybrid 应用React-Native)能做更多的事情,其中包括使用 客户端原生功能 提供更好的 交互 和 服务 等。

然而 JavaScript 并不能直接调用和它不同语言(如 Java、C/C++ 等)提供的功能特性,因此需要一个中间层去实现 JavaScript其他语言 间的一个相互协作,这里通过一个 Node 架构来进行说明。

Node 架构
核心内容如下:
  • 顶层 Node Api
    提供 http 模块、流模块、fs文件模块等等,可以通过 JavaScript 直接调用
  • 中间层 Node Bindings
    主要是使 JavaScript 和 C/C++ 进行通信,原因是 JavaScript 无法直接调用 C/C++ 的库(libuv),需要一个中间的桥梁,node 中提供了很多 binding,这些称为 Node bindings
  • 底层 V8 + libuv
    v8 负责解释、执行顶层的 JavaScript 代码
    libuv 负责提供 I/O 相关的操作,其主要语言是 C/C++ 语言,其目的就是实现一个 跨平台(如 Windows、Linux 等)的异步 I/O 库,它直接与操作系统进行交互

这里不难发现 Node Bindings 就有点类似 JSBridge 的功能,所以 JSBridge 本身是一个很简单的东西,其更多的是 一种形式、一种思想

为什么叫 JSBridge?

Stack Overflow 联合创始人 Jeff Atwood 在 2007 年的博客《The Principle of Least Power[2]》中认为 “任何可以使用 JavaScript 来编写的应用,并最终也会由 JavaScript 编写”,后来 JavaScript 的发展确实非常惊人,现在我们可以基于 JavaScript 来做各种事情,比如 网页、APP、小程序、后端等,并且各种相关的生态越来越丰富。

作为 Web 技术逻辑核心的 JavaScript 自然而然就需要承担与 其他技术 进行『桥接』的职责,而且任何一个 移动操作系统 中都会包含 运行 JavaScript 的容器环境,例如 WebViewJSCore 等,这就意味着 运行 JavaScript 不用像运行其他语言时需要额外添加相应的运行环境。

JSBridge 应用在国内真正流行起来则是因为 微信 的出现,当时微信的一个主要功能就是可以在网页中通过 JSBridge 来实现 内容分享。

JSBridge 能做什么?

举个最常见的前端和后端的例子,后端只提供了一个查找接口,但是没有提供更新接口,那么对于前端来讲就是再想实现更新接口,也是没有任何法子的!

同样的,JSBridge 能做什么得看原生端给 JavaScript 提供调用 Native 什么功能的接口,比如通过 微信 JS-SDK ,网页开发者可借助微信使用 拍照、选图、语音、位置 等手机系统的能力,同时可以直接使用 微信分享、扫一扫、卡券、支付 等微信特有的能力。

JSBridge 作为 JavaScriptNative 之间的一个 桥梁,表面上看是允许 JavaScript 调用 Native 的功能,但其核心是建立 Native非 Native 间消息 双向通信 通道。

双向通信的通道:

  • JavaScript 向 Native 发送消息:
    调用 Native 功能
    通知 Native 当前 JavaScript 的相关状态等
  • Native 向 JavaScript 发送消息:
    回溯调用结果
    消息推送
    通知 JavaScript 当前 Native 的状态等

JSBridge 是如何实现的?

JavaScript 的运行需要 JS 引擎的支持,包括 Chrome V8、Firefox SpiderMonkey、Safari JavaScriptCore 等,总之 JavaScript 运行环境 是和 原生运行环境 是天然隔离的,因此,在 JSBridge 的设计中我们可以把它 类比 成 JSONP 的流程:

  • 客户端通过 JavaScript 定义一个回调函数,如: function callback(res) {…},并把这个回调函数的名称以参数的形式发送给服务端
  • 服务端获取到 callback 并携带对应的返回数据,以 JS 脚本形式返回给客户端
  • 客户端接收并执行对应的 JS 脚本即可

JSBridge 实现 JavaScript 调用的方式有两种,如下:

  • JavaScript 调用 Native

  • Native 调用 JavaScript

在开始分析具体内容之前,还是有必要了解一下前置知识 WebView

WebView 是什么?

(—说白了就是浏览器,个人理解哈—)
WebView 是 原生系统 用于 移动端 APP 嵌入 Web 的技术,方式是内置了一款高性能 webkit 内核浏览器 (—这里的意思是APP自己内置了一款高性能的内核浏览器,例如微信,微信会自己内置一款高性能的内核浏览器。—),一般会在 SDK 中封装为一个 WebView 组件。
WebView 具有一般 View 的属性和设置外,还对 url 进行请求、页面加载、渲染、页面交互进行增强处理,提供更强大的功能。
WebView 的优势 在于当需要 更新页面布局业务逻辑发生变更 时,能够更便捷的提供 APP 更新:

  • 对于 WebView 而言只需要修改前端部分的 Html、Css、JavaScript 等,通知用户端进行刷新即可
  • 对于 Native 而言需要修改前端内容后,再进行打包升级,重新发布,通知用户下载更新,安装后才可以使用最新的内容
微信小程序中的 WebView

小程序的主要开发语言是 JavaScript ,其中 逻辑层 和 渲染层 是分开的,分别运行在不同的线程中,而其中的渲染层就是运行在 WebView 上:

运行环境 逻辑层 渲染层
iOS JavaScriptCore WKWebView
安卓 V8 chromium 定制内核
centered 文本居中 right-aligned 文本居右 ight-aligned 文本居右
小程序开发者工具 NWJS Chrome WebView

在开发过程中遇到的一个 坑点 就是:

  • 在真机中,需要实现同一域名下不同子路径的应用实现数据交互(纯前端操作,不涉及接口),由于同域名且是基于同一个页面进行跳转的(当然只是看起来是),而且这个数据是 临时数据,因此觉得使用 sessionStorage 实现数据交互是很合适的
  • 实际上从 A 应用 跳转到 B 应用 中却无法获取对应的数据,而这是因为 sessionStorage 是基于当前窗口的会话级的数据存储,移动端浏览器 或 微信内置浏览器 中在跳转新页面时,可能打开的是一个新的 WebView,这就相当于我们在浏览器中的一个新窗口中进行存储,因此是没办法读取在之前的窗口中存储的数据

JavaScript 调用 Native — 实现方案一

通过 JavaScript 调用 Native 的方式,又会分为:

  • 注入 API
  • 劫持 URL Scheme
  • 弹窗拦截
【 注入 API 】

核心原理:

通过 WebView 提供的接口,向 JavaScript 的上下文(window)中注入 对象 或者 方法
允许 JavaScript 进行调用时,直接执行相应的 Native 代码逻辑,实现 JavaScript 调用 Native
这里不通过 iOS 的 UIWebView 和 WKWebView 注入方式来介绍了,感兴趣可以自行查找资料,咱们这里直接通过 微信 JS-SDK[3] 来看看。

当通过 <script src=“https://res2.wx.qq.com/open/js/jweixin-1.4.0.js”> 的方式引入 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 对象
  • 而在 N 对象中定义的各种方法实际上又是通过 e.WeixinJSBridge 上的方法来实际执行的
  • e.WeixinJSBridge 就是由 微信内置浏览器 向 window 对象中注入 WeiXinJsBridge 接口实现的
!(function (e, n) {
  'function' == typeof define && (define.amd || define.cmd)
    ? define(function () {
        return n(e)
      })
    : n(e, !0)
})(this, function (e, n) {
   ...
   function i(n, i, t) {
    e.WeixinJSBridge
      ? WeixinJSBridge.invoke(n, o(i), function (e) {
          c(n, e, t)
        })
      : u(n, t)
   }
   
   if (!e.jWeixin) {
    
    var N = {
        config(){
          i(...)
        },
        ready(){},
        error(){},
        ...
    }
    
    return (
      S.addEventListener(
        'error',callback1,
        !0
      ),
      S.addEventListener(
        'load',callback2,
        !0
      ),
      n && (e.wx = e.jWeixin = N),
      N
    )
  }
})
【 劫持 URL Scheme 】

URL Scheme 是什么?
URL Scheme 是一种特殊的 URL,一般用于在 Web 端唤醒 App(或是跳转到 App 的某个页面),它能方便的实现 App 间互相调用(例如 QQ微信 相互分享讯息)。

URL Scheme 的形式和 普通 URL(如:https://www.baidu.com)相似,主要区别是 protocolhost 一般是对应 APP 自定义的。

通常当 App 被安装后会在系统上注册一个 自定义的 URL Scheme,比如 weixin:// 这种,所以我们在手机浏览器里面访问这个 scheme 地址,系统就会唤起对应的 App

例如,当在浏览器中访问 weixin:// 时,浏览器就会询问你是否需要打开对应的 APP:

劫持原理
Web 端通过某种方式(如 iframe.src)发送 URL Scheme 请求,之后 Native 拦截到请求并根据 URL Scheme携带的参数 进行对应操作。

例如,对于谷歌浏览器可以通过 chrome://version/chrome://chrome-urls/chrome://settings/ 定位到不同的页面内容,假设 跳转到谷歌的设置页并期望当前搜索引擎改为百度,可以这样设计 chrome://settings/engine?changeTo=baidu&callbak=callback_id:

  • 谷歌客户端可以拦截这个请求,去解析对应参数 changeTo 来修改默认引擎
  • 然后通过 WebView 上面的 callbacks 对象来根据 callback_id 进行回调

以上只是一个假设哈,并不是说真的可以这样去针对谷歌浏览器进行修改,当然它要是真的支持也不是不可以。

是不是感觉确实和 JSONP 的流程很相似呀 ~ ~

【 弹窗拦截 】

弹窗拦截核心:利用弹窗会触发 WebView 相应事件来实现的
一般是在通过拦截 PromptConfirmAlert 等方法,然后解析它们传递过来的消息,但这种方法存在的缺陷就是 iOS 中的 UIWebView 不支持,而且 iOS 中的 WKWebView 又有更好的 scriptMessageHandler,因此很难统一。

Native 调用 JavaScript — 实现方案二

Native 调用 JavaScript 的方式本质就是 执行拼接 JavaScript 字符串,这就好比我们通过 eval() 函数来执行 JavaScript 字符串形式的代码一样,不同的系统也有相应的方法执行 JavaScript 脚本。

Android

Android 中需要根据版本来区分:
安卓 4.4 之前的版本使用 loadUrl()

webView.loadUrl("javascript:foo()")

loadUrl() 不能获取 JavaScript 执行后的结果,这种方式更像在 <a href=“javascript:void(0)”> 的 href 属性中编写的 JavaScript 代码

安卓 4.4 以上版本使用 evaluateJavascript()

webView.evaluateJavascript("javascript:foo()", null);
IOS

IOS 中需要根据不同的 WebView 进行区分:
UIWebView 中通常使用 stringByEvaluatingJavaScriptFromString

results = [self.webView stringByEvaluatingJavaScriptFromString:"foo()"];

WKWebView 中通常使用 evaluateJavaScript

[self.webView evaluateJavaScript:@"document.body.offsetHeight;" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
  // 获取返回值
}];

最后

以上通过 微信 JS-SDKJSBridge 的一个简单介绍,大家现在应该不至于认为 JSBridge 是一个高大上、深不可测的东西了,毕竟其核心思想是清晰明了的,而且本质上还是需要强依赖于原生端的具体实现。

参考资料:
JSBridge 的原理
JS Bridge 通信原理与实践
webview到底是什么?

参考资料:
[1] 微信 JS-SDK(jweixin): https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

[2] The Principle of Least Power: https://link.zhihu.com/?target=https%3A//blog.codinghorror.com/the-principle-of-least-power/

[3] 微信 JS-SDK: https://res2.wx.qq.com/open/js/jweixin-1.4.0.js

作者: 熊的猫
https://juejin.cn/post/7199297355748458551

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 微信 JS-SDK 认识 JSBridge 的相关文章

  • 计算字符串中的唯一单词

    下面我尝试将字符串数组提供给一个函数 该函数将唯一单词添加到单词数组中 并且如果该单词已经在数组中 则增加计数数组中相应元素的计数 var words var counts calculate a b calculate a c funct
  • 有没有办法根据渲染的字符串创建 DOM 对象?

    有没有办法从整个字符串而不只是innerHTML 创建DOM 对象 我有一个完整呈现的 DOM 形式的字符串
  • 不使用 PHP 提交联系表单

    我还是一名学生 今天我们的讲师告诉我们 无需使用 mailto 函数即可提交联系我们表单的唯一方法是使用 PHP 我发誓去年另一位讲师向我们展示了一种仅使用 javascript 的方法 是否可以使用基本表单和 javascript 提交反
  • 使用 Jquery 附加链接

    我正在尝试根据您所在的页面添加指向我的页面的链接 我使用 Squarespace 来构建这个网站 因此对我来说最简单的方法是使用 Javascript 或 Jquery 我认为我缺少的这个语法有问题 我已经尝试用 来打破引号 但这不起作用
  • AngularJS:选择非 2 路绑定到模型

    我正在使用选择来显示客户名称 用户应该能够选择现有客户端 然后更新范围属性 控制器 初始化 首选 if scope clients length gt 0 scope existingClient scope clients 0 View
  • React Native TypeError:无法读取未定义的属性“createClient”

    我是 React 本机框架的新手 我使用 create react native app AwesomeProject 创建了应用程序 我想在我的项目中使用 BLE 因此我安装了 react native ble plx 模块 但是当我创建
  • 如何解构 React props 并仍然访问其他 props?

    我很好奇如果我想要所有的 props 但也想要解构单个属性 那么组件的参数 props 是否可以像导入一样解构 我想这更像是一个 JavaScript 问题 而不是一个 React 问题 但是举个例子 import React useEff
  • 将事件添加到 Google Maps API InfoWindow 内的元素

    我想在 Google Maps API v3 InfoWindow 内放置一个带有输入字段和提交按钮的表单 提交后 我想调用一个函数 该函数使用输入字段中输入的地址启动方向服务 这是我的代码 我目前只测试方向事件是否被触发 我已经编写了完整
  • 将字符串(是一个函数)转换回 Javascript 中的函数

    我在下面将此函数作为字符串 我如何将其转换回函数 我正在从 JQuery 事件中提取事件处理程序 我想将它们存储为字符串 然后将它们转换回来 因为它们将保存在 mySQL 中 function if GActiveClick return
  • 如何在 Angular 2 应用程序中使 DateAdapter 单例?

    我正在开发一个带有延迟加载模块的 Angular 7 应用程序 我也使用有角度的材料组件 我想在日期选择器组件中本地化并支持多个区域设置 当应用程序语言发生变化时 我想在整个应用程序中全局更改它 可以通过 DateAdapter setLo
  • 在电子生成器反应电子应用程序后,在 Windows 中出现空白屏幕

    在电子生成器反应电子应用程序后 Windows 中出现空白屏幕 这是package json 在电子生成器反应电子应用程序后 Windows 中出现空白屏幕 name SmallBusinessManagement version 0 1
  • 在 Chrome 中加载analytics.js时出现307重定向

    我正在构建一个网络应用程序并使用 Google Analytics analytics js 进行分析 我最近注意到 Chrome 中的分析功能无法正常工作 我使用单独模块中的标准代码片段加载分析并通过 requirejs 包含 我已验证该
  • JavaScript 中的最短路径

    几周来我一直在寻找一种在 JavaScript 中计算最短路径的方法 我一直在玩书数据结构和算法作者 格罗纳 Groner 名字恰如其分 https github com loiane javascript datastructs algo
  • 如何使用 Jquery .animate() 函数创建连续滚动内容? [复制]

    这个问题在这里已经有答案了 可能的重复 在jquery中实现圆形滚动条 https stackoverflow com questions 812049 implementing circular scroller in jquery 我想
  • 在React组件中使用的字符串变量中插入html

    我正在为我的投资组合网站构建一个反应应用程序 目前我已经用 JSX 编写了应用程序 因此我可以添加以下内容 class Project extends React Component render return div h1 this pr
  • Babel/RequireJS + typeof“RangeError:超出最大调用堆栈大小”

    我有一个非常基本的 JS 错误 我很羞愧无法解决它 我正在使用 ES6 和 Babel 进行开发 并且正在做一些实验 请注意 我在 Babel 中使用了这些参数 presets es2015 plugins transform es2015
  • 有没有办法从画布上清除一个元素而不消除其他元素?

    我正在使用画布构建页面加载器 并使用 es6 类 虽然目前我无法使其正常工作 原因之一是我找不到清除画布的方法进展 到目前为止 这是我的代码 class Loader constructor width height this width
  • 这个 JQuery 指令做什么 $(function(){...}) [重复]

    这个问题在这里已经有答案了 我最近一直在研究JQuery 尽管我知道一些东西 但书上有这样一句话我根本无法理解 function current entry 1 有谁知道这条线是如何工作的以及它的作用是什么 它类似于 JQuery 函数中的
  • 如何在 Firefox 插件中追加到文件?

    var tabs require sdk tabs var iofile require sdk io file var widgets require sdk widget var selection require sdk select
  • JavaScript 中“键”的类型是什么?

    当我失去焦点并开始思考一个愚蠢的问题时 我遇到了这样的时刻 var a b value b 的类型是什么 我的意思不是 值 的类型 而是标记为 b 的实际键 背景 当我必须创建一个字符串键时 我开始想知道这一点 var a b value

随机推荐

  • 软件工程毕业设计题目100例

    文章目录 0 简介 1 如何选题 2 最新软件工程毕设选题 3 最后 0 简介 学长搜集分享最新的软件工程业专业毕设选题 难度适中 适合作为毕业设计 大家参考 学长整理的题目标准 相对容易 工作量达标 题目新颖 1 如何选题 最近非常多的学
  • 练手Demo(一)

    配置文件 spring redis host localhost username root password port 6379 datasource url jdbc mysql localhost 3306 base admin Un
  • 泛微OA项目引入jar包说明

    项目引入的jar包说明 WEB INF lib 依赖 存在dom4j 以及httpclient jar包 Resin lib 存在的是resin组件本身自带的依赖 ecology classbean 开发java类编译存放目录 系统目前已有
  • Java基础——strictfp关键字

    关键字strictfp是strict float point的缩写 指的是精确浮点 它是用来确保浮点数运算的准确性 JVM在执行浮点数运算时 如果没有指定strictfp关键字 此时计算结果可能会不精确 而且计算结果在不同平台或厂商的虚拟机
  • Windows 开机启动脚本 (不询问自动以管理员权限运行bat)

    方式一 系统级开机自启 不用登陆 获取开机启动文件夹 使用环境变量 ProgramData 或者 SYSTEMDRIVE echo SYSTEMDRIVE ProgramData Microsoft Windows Start Menu P
  • 对象的知识点补充

    认识对象 对象 object 是 键值对 的集合 表示属性和值的映射关系 JS中 大括号表示对象 var xiaoming 属性名 键名 key name 小明 age 12 sex 男 hobbies 足球 编程 对象的语法 k和v之间用
  • 进程间通信的方式总结(特点,以及code demo)

    进程间通信 IPC InterProcess Communication 是指在不同进程之间传播或交换信息 一 简单的进程间通信 命令行 父进程通过exec函数创建子进程时可以附加一些数据 环境变量 父进程通过exec函数创建子进程顺便传递
  • MOS管之增强型和耗尽型

    Depletion and enhancement modes In field effect transistors FETs depletion mode and enhancement mode are two major trans
  • 通过路由器端口映射实现外网IP访问内网服务器

    1 确认路由器的公网IP是不是真的公网IP 特别重要 如果不是可以不用看后面的了 通过www ip138 com网站可以查询当前网络的公网IP 再进入路由器控制界面查看wan口IP和公网IP是否相同 如果不同 大概率是私网IP 服务商在公网
  • cookie格式化

    字符串转成字典 使用场景 selenium尝试试用cookie登陆时 Network中cookie是一段字符串 需要转成字典使用 使用split和列表解析式 str thor 8954F43 Id d32def3ffSNw pn adsad
  • 数据结构---二叉查找树(二叉搜索树)

    二叉查找树 特性 插入 删除 待删除节点没有子节点 待删除节点有一个子节点 待删除节点有两个子节点 JAVA实现 缺陷 二叉查找树 二叉排序树 在二叉树的基础上 增加了 如果左子树不为空 则左子树上所有节点的值都小于根节点的值 如果右子树不
  • B站粉丝数显示器,播放数、获赞数失效解决。

    之前在B站看见很多人做B站粉丝数显示器 于是便在网上买了一块ESP8266的开发版回来尝试着折腾一个出来 便在网上搜索适合买回来的开发板和0 96 oled显示器的代码 显示部分的主要代码是在 果果小师弟的博客上找到的 然后自己又找了个可以
  • WORD中字号没有中文编号的解决办法

    今天一同事反映说 WORD中没有像 五号 四号 之类的字号 只有数字字号如 8 72 解决过程如下 一 删除office中normal dot模版文件 不行 二 开始 gt 程序 gt Microsoft Office 工具 gt Mics
  • 参数与超参数

    写在前面 关于训练深度学习模型最难的事情之一是你要处理的参数的数量 无论是从网络本身的层宽 宽度 层数 深度 连接方式 还是损失函数的超参数设计和调试 亦或者是学习率 批样本数量 优化器参数等等 这些大量的参数都会有网络模型最终的有效容限直
  • ftp的主动模式active mode和被动模式 passive mode的配置和区别

    共同点 客户端先发起命令连接 不同点 主动模式 服务端发起数据连接 客户端生成随机数据端口 被动模式 客户端发起数据连接 客户端和服务端都是随机数据端口 客户端与服务器的命令连接 服务器返回命令 PORT 2024 告诉客户端 服务器 用哪
  • SpringData使用ES报错 org.elasticsearch.index.mapper.MapperParsingException: No type specified for field

    原因就像mysql的字段要跟Java基本类型对应一样 ES的字段也要与Java的基本类型相对应 一 而且这个最好新建一个ES索引库 否则可能会有问题 我用Restful操作初始化了一个ES索引库 并增加数据 再用Java操作的时候 Spri
  • 父组件传来的值和子组件自己定义的data的值有什么区别?

    props和data的区别 1 data中的数据是组件内自己的数据 状态 可以随意修改data中的值 2 props的数据是父组件传递过来的数据 是只读的 只能供子组件使用 不能随意修改 下面进行演示 1 首先创建一个父组件HomeView
  • Windows Server 2019下搭建FTP服务器

    在服务器管理器中选择 添加角色和功能 连续点击下一步 跳过开始之前和安装类型界面 在服务器选择界面中 选择从服务器池中选择服务器 默认选中一台服务器 选中web服务复选框 点击下一步 选中FTP服务器复选框 点击安装 安装完毕后 可以在Wi
  • [YOLOv8/YOLOv7/YOLOv5系列算法改进NO.5]改进特征融合网络PANET为BIFPN(更新添加小目标检测层yaml)

    前 言 作为当前先进的深度学习目标检测算法YOLOv5 已经集合了大量的trick 但是在处理一些复杂背景问题的时候 还是容易出现错漏检的问题 此后的系列文章 将重点对YOLOv5的如何改进进行详细的介绍 目的是为了给那些搞科研的同学需要创
  • 从 微信 JS-SDK 认识 JSBridge

    前言 前段时间由于要实现 H5 移动端拉取微信卡包并同步卡包数据的功能 于是在项目中引入了 微信 JS SDK jweixin 1 相关包实现功能 但也由此让我对其产生了好奇心 于是打算好好了解下相关的内容 通过查阅相关资料发现这其实属于