Hybrid app本地开发如何调用JSBridge
前天同事问我公司内部的小程序怎么对接的,我回忆了一下,简单记录了一下前端同学需要注意的点。
背后还有小程序架构、网络策略等等。当时恰逢小程序架构调整,(老架构的时候我就发现了有一个问题点可以优化,但是跟那边人反馈之后,人家表示不要我管,新架构时发现这个问题还巧妙的遗留下来了)我虽然不负责那块,但是本着这样不优雅的原则,还是跟新架构的对接人讲了我的优化方案,讲明白了之后,同时上报各自直系领导,并建议我领导牵头开会推动。最后,无奈存量数据太多,老架构那边权衡之后决定不改动。(多说了几句,权当记录一下)
1、背景
公司研发的一款服务软件App(姑且称为“大地”),提供了包涵消息、待办、工作台、同事圈和通讯录五大功能模块,其中,工作台里集成了包括公司的移动客户端、PC端以及第三方平台的部分功能/服务(统称为“应用”)。
我今天要讲的是这个集成平台以什么方式展现“应用”,答案是:借鉴了微信的架构,自研了“小程序”接入“应用”。
我司小程序具有一种相对开放能力(面向全公司),赋能业务快速数字化、场景敏捷迭代,并且可在“大地”上便捷的获取和使用,同时具有完善的使用体验(这就是严格的接入审核标准带来的好处)。
在“大地”开发者平台,创建小程序会自动创建配套的公众号(公众号是为了推送消息使用,可订阅)。小程序开发不限制技术选型,开发完成之后按照小程序接入规范打包上架小程序,审核发布。
简单来说,可以把“大地”看成是一个“钉钉”,我现在要把我们的业务功能投放到“大地”上,就需要接入“大地”小程序,以小程序的方式在“大地”上为用户提供服务。
小程序架构:Cordova框架做的WebView,运行我开发的前端程序,通过Nginx帮我把请求代理到微服务网关,由网关转发到目的主机处理请求。它虽然看上去是一个Native App,但只有一个UI WebView,里面访问的是一个Web App,对我来说就是开发一个H5应用调用一些所需的JSBridge,也就是所谓的Hybrid App。
下面看一下本地开发中的一些问题,以及我是怎么处理的
2、问题
Hybrid App本地开发过程中没有真实的Native环境的,同样也无法使用JSBridge,这就会带来一个问题:跟原生交互的行为只能发布小程序才可以调试,本地玩不了,这...,相当fuck。
目的是想让本地开发同小程序测试环境具有相同的体验,我的想法是在本地模拟JSBridge的方法,尽管不能带来真实的效果,至少触发了某个行为之后要有个反应,不至于让操作流程看起来像是“脱节”的(实际跟原生的交互行为并不多,比如:拍照、弹窗提示、定位等等)。
因此,我要做的就是本地模拟JSBridge的一些方法,开发时触发了这些原生交互行为之后提示一些信息,等到上架小程序测试环境时,在手机上会用真实的JSBridge方法自动替换掉我模拟实现的方法。
于是我就开始了下面的准备工作。
搞清楚
JSBridge运行的原理本地模拟
JSBridge的方法上架小程序是自动使用真实的
JSBridge
3、了解JSBridge
JSBridge:望文生义就是js和Native之前的桥梁,而实际上JSBridge确实是JS和Native之前的一种通信方式。
简单的说,JSBridge就是定义Native和JS的通信,Native只通过一个固定的桥对象调用JS,JS也只通过固定的桥对象调用Native。JSBridge另一个叫法及大家熟知的Hybrid app技术。

了解即可,更多的请参考
下图展示了JSBridge的工作流程

上图中左侧部分正式我要做的,具体请看下文
看累了,三连一下,回看不迷路哟
3.1、我们的JSBridge
推测“大地”那边的JSBridge应该是自己写的,没有初始化JSBridge的操作
当调用JSBridge时,必须在页面完全加载完成之后才能够拿到全局的JSBridge,Cordova框架提供deviceready事件,该事件触发的时候表示全局的JSBridge挂载成功。(注意:这就是我接下来操作的切入点,嘻嘻)
简单写下如下:
document.addEventListener('deviceready', function () {
console.log('deviceready OK!');
JSAPI.showToast(0, '提示信息')
}, false)
需要注意的是,在开发环境,是没有 deviceready 事件的,所以上面的代码并不会执行,只有在app里面运行的时候才会执行。
思考:
JSBridge必须是在deviceready事件触发后方能使用的,因此首先要做的就是自定义deviceready事件,本地环境可以在load事件里触发自定义deviceready事件,生产环境下监听deviceready事件即可

4、JS发起自定义事件
我是用 CustomEvent 构造函数,继承至 Event,文档看这里
- 用法
new CustomEvent(eventName, params);
- 示例
创建一个自定义事件
const event=new CustomEvent('mock-event');
- 传递参数
这里值得注意,需要把想要传递的参数包裹在一个包含detail属性的对象,否则传递的参数不会被挂载
function createEvent(params, eventName = 'mock-event') {
return new CustomEvent(eventName, { detail: params });
}
const event = createEvent({ id: '0010' });
- 发起事件
调用dispatchEvent方法发起事件,传入你刚才创建的方法
window.dispatchEvent(event);
- 监听事件
window.addEventListener('mock-event', ({ detail: { id } }) => {
console.log('id',id) // 会在控制台打印0010
});
- 示例:
document.body.addEventListener('show', (event) => { console.log(event.detail); });
// 触发
let myEvent = new CustomEvent('show', {
detail: {
username: 'xixi',
userid: '2022'
}
});
document.body.dispatchEvent(myEvent);
了解了自定义事件之后,通过自定义事件模拟触发
deviceready事件,这样上面的deviceready事件监听就可以执行了。注意:这里还要确定一个问题,在什么时候触发自定义事件
deviceready呢?
5、确定 deviceready 事件执行时机
- 只需要编写如下代码,查看输出结果即可
window.addEventListener('load', function () {
console.log('load OK!');
}, false);
document.addEventListener('deviceready', function () {
console.log('deviceready OK!');
}, false);
- 结果输出
load OK!
deviceready OK!
由此可知,执行顺序:load --> deviceready
6、自定义事件模拟Cordova deviceready事件
自定义
deviceready事件根据上面测试执行顺序得出的结论,我在
load事件里触发自定义事件在开发环境下模拟一些用到的
JSBridge-API,比如下面写到的JSAPI.showToast()方法
- mockEvent.js
if (process.env.NODE_ENV === 'development') {
// 自定义事件
let myEvent = new CustomEvent('deviceready');
// 模拟JSAPI事件
window['JSAPI'] = {
showToast(type, desc) {
console.log(type, desc);
}
}
// ...
// 开发环境下,在 原生 load 方法之后 触发自定义事件
window.addEventListener('load', function () {
console.log('load OK!');
setTimeout(() => {
document.body.dispatchEvent(myEvent);
}, 100)
}, false);
}
7、封装deviceReady方法
实现在Cordova框架触发deviceready事件的时候感知到,以便于在deviceReady事件触发后执行JS-API。
可用于开发环境和非开发环境
7.1、方式一
这里采用链式调用的方式,
以下这种借助 Promise 的实现,在这种场景下其实是不合理的
只是形式上类似,其实并不是
- 定义
- mixin.js
deviceReady() {
return new Promise((resolve) => {
window.addEventListener('deviceready', function () {
resolve("ready go!");
}, false);
})
}
- 组件内使用
JS-API
使用JSAPI可以如下这么写
this.deviceReady().then((res) => {
console.log(res); // ready go!
JSAPI.showToast(0, '提示')
})
this.deviceReady().then((res) => {
JSAPI.getUserInfo((res) => {
console.log(res);
}, (err) => {
console.log(err);
});
})
- 开发环境执行效果如下

7.2、方式二(推荐)
改写成通用的事件监听函数,支持链式调用
开发环境下,由
mockEvent.js文件里的dispatchEvent触发自定义的deviceready事件;小程序里运行,则由真实的
deviceready事件触发
- 定义
- mixin.js
receiver(type) {
let callbacks = {
fns: [],
then: function(cb){
this.fns.push(cb);
return this;
}
};
document.addEventListener(type, function(ev) {
let fns = callbacks.fns.slice();
for(let i = 0, l = fns.length; i < l; i++){
fns[i].call(this, ev);
}
});
return callbacks;
}
- 使用
this.receiver('deviceready').then((ev) => {
console.log(ev);
JSAPI.getUserInfo(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
)
})
this.receiver("click")
.then(() => console.log("hi"))
.then(()=> console.log(22));
最后
当应用发布到app上,就是监听的真实的 Cordova框架的 deviceready 事件了,之后也就可以拿到真实的JSAPI了,以上只是为了在开发环境的时候模拟使用JSAPI。防止在开发环境下直接调用JSAPI飘红的情况,当然也是可以加try catch处理的,只不过个人感觉模拟事件使得代码看起来更加优雅别致一点,使用更加丝滑,酌情食用。
软件架构非常有意思,感兴趣的可以交流探索,嘻嘻。

我是 甜点cc
热爱前端,也喜欢专研各种跟本职工作关系不大的技术,技术、产品兴趣广泛且浓厚,等待着一个创业机会。主要致力于分享实用技术干货,希望可以给一小部分人一些微小帮助。
我排斥“新人迷茫,老人看戏”的现象,希望能和大家一起努力破局。营造一个良好的技术氛围,为了个人、为了我国的数字化转型、互联网物联网技术、数字经济发展做一点点贡献。数风流人物还看中国、看今朝、看你我。
Hybrid app本地开发如何调用JSBridge的更多相关文章
- Hybrid APP混合开发的一些经验和总结
http://www.cnblogs.com/kingplus/p/5588339.html 写在前面: 由于业务需要,接触到一个Hybrid APP混合开发的项目.当时是第一次接触混合开发,有一些经 ...
- Hybrid APP混合开发
写在前面: 由于业务需要,接触到一个Hybrid APP混合开发的项目.当时是第一次接触混合开发,有一些经验和总结,欢迎各位一起交流学习~ 1.混合开发概述 Hybrid App主要以JS+Nativ ...
- Hybrid App 应用开发中 9 个必备知识点复习(WebView / 调试 等)
前言 我们大前端团队内部 ?每周一练 的知识复习计划继续加油,本篇文章是 <Hybrid APP 混合应用专题> 主题的第二期和第三期的合集. 这一期共整理了 10 个问题,和相应的参考答 ...
- Hybrid App混合模式开发的了解
Hybrid App(混合模式移动应用)是指介于web-app.native-app这两者之间的app,兼具"Native App良好用户交互体验的优势"和"Web Ap ...
- (一)Hybrid app混合开发模式
hybrid app是什么? 这里我们先看一下词条上的定义 Hybrid App:Hybrid App is a mobile application that is coded in both br ...
- SharePoint 2013 搭建app本地开发环境
使用SharePoint App,如果要通过应用程序目录分发 SharePoint 相关应用程序,如具有完全控制权限的 SharePoint 相关应用程序(无法部署到 Office 365 网站),则 ...
- 【Hybrid App】Hybrid App开发实战
[引言]近年来随着移动设备类型的变多,操作系统的变多,用户需求的增加,对于每个项目启动前,大家都会考虑到的成本,团队成员, 技术成熟度,时间,项目需求等一堆的因素.因此,开发App的方案已经变得越来越 ...
- 跨平台 webapp 开发技术之 Hybrid App
前所知的 APP 开发模式有三种: 基于操作系统运行的 APP -> Native App,侧重于原生开发,用户体验好,需要安装才会升级 基于浏览器运行的 APP -> Web App,侧 ...
- Hybrid App开发实战
Hybrid App开发实战 作者 李秉骏 发布于 九月 04, 2013 | [引言]近年来随着移动设备类型的变多,操作系统的变多,用户需求的增加,对于每个项目启动前,大家都会考虑到的成本,团队成员 ...
随机推荐
- XML方式配置切面
1. 概述 一个切面中需要包含什么,才能够作用到连接点?切面中是包含通知的,通知作用到连接点需要有切入点表达式. 除了使用AspectJ注解声明切面,Spring也支持在bean配置文件中声明切面. ...
- Java8 Stream 的最佳实践
Java8 Stream 的最佳实践 java8stream提供了对于集合类的流失处理,其具有以下特点: Lazy Evaluation(长度可以无限) 只能使用一次 内部迭代 Lazy Evalua ...
- 基于单层决策树的AdaBoost算法原理+python实现
这里整理一下实验课实现的基于单层决策树的弱分类器的AdaBoost算法. 由于是初学,实验课在找资料的时候看到别人的代码中有太多英文的缩写,不容易看懂,而且还要同时看代码实现的细节.算法的原理什么的, ...
- 聊聊 C++ 中的四种类型转换符
一:背景 在玩 C 的时候,经常会用 void* 来指向一段内存地址开端,然后再将其强转成尺度更小的 char* 或 int* 来丈量一段内存,参考如下代码: int main() { void* p ...
- Eolink 全局搜索介绍【翻译】
随着前后端分离成为互联网项目开发的标准模式, API 成为了前后端联通的桥梁.而面对越来越频繁和复杂的调用需求,项目里的 API 数量也越来越多,我们需要通过搜索功能来快速定位到对应的 API来进行使 ...
- Nginx配置解决NetCore的跨域
使用Nginx配置解决NetCore的跨域 废话不多说,直接上Nginx配置 server { listen 80; server_name 你的Id或域名; location / { add_hea ...
- SpringMVC底层——请求参数处理流程描述
在DispatcherServlet.java的doDispatch方法中,springmvc通过handlermapping里面找哪个handler能处理请求,handler封装了目标方法的信息, ...
- pinia 入门及使用
自上月从上海结束工作回来 在家闲来无事 想写点东西打发时间 也顺便学习学习新的技术.偶然发现了 pinia 据说比vuex好用些 所以便搭了个demo尝试着用了下 感觉确实不错,于是便有了这篇随笔. ...
- 虚言妙诀终虚见,面试躬行是致知,Python技术面试策略与技巧实战记录
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_183 2021年,对于正在找工作的朋友来说,笼罩在新冠肺炎疫情之下,今年的就业季显得更加具有挑战性,更有意思的是,每当这个时候,各 ...
- Changes in GreatSQL 5.7.36 (2022-4-7)
目录 1.新增特性 1.2 新增MGR角色列 1.2 采用全新的流控机制 1.3 新增MGR网络开销阈值 1.4 调整MGR大事务限制 2.稳定性提升 3.性能提升 4.bug修复 文章推荐: 关于 ...