前天同事问我公司内部的小程序怎么对接的,我回忆了一下,简单记录了一下前端同学需要注意的点。

背后还有小程序架构、网络策略等等。当时恰逢小程序架构调整,(老架构的时候我就发现了有一个问题点可以优化,但是跟那边人反馈之后,人家表示不要我管,新架构时发现这个问题还巧妙的遗留下来了)我虽然不负责那块,但是本着这样不优雅的原则,还是跟新架构的对接人讲了我的优化方案,讲明白了之后,同时上报各自直系领导,并建议我领导牵头开会推动。最后,无奈存量数据太多,老架构那边权衡之后决定不改动。(多说了几句,权当记录一下)

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方法自动替换掉我模拟实现的方法。

于是我就开始了下面的准备工作。

  1. 搞清楚JSBridge运行的原理

  2. 本地模拟JSBridge的方法

  3. 上架小程序是自动使用真实的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,文档看这里

  1. 用法
new CustomEvent(eventName, params);
  1. 示例

创建一个自定义事件

const event=new CustomEvent('mock-event');
  1. 传递参数

这里值得注意,需要把想要传递的参数包裹在一个包含detail属性的对象,否则传递的参数不会被挂载

function createEvent(params, eventName = 'mock-event') {
return new CustomEvent(eventName, { detail: params });
} const event = createEvent({ id: '0010' });
  1. 发起事件

调用dispatchEvent方法发起事件,传入你刚才创建的方法

window.dispatchEvent(event);
  1. 监听事件
window.addEventListener('mock-event', ({ detail: { id } }) => {
console.log('id',id) // 会在控制台打印0010
});
  1. 示例:
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事件

  1. 自定义deviceready事件

  2. 根据上面测试执行顺序得出的结论,我在load事件里触发自定义事件

  3. 在开发环境下模拟一些用到的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 的实现,在这种场景下其实是不合理的

只是形式上类似,其实并不是

  1. 定义
  • mixin.js
deviceReady() {
return new Promise((resolve) => {
window.addEventListener('deviceready', function () {
resolve("ready go!");
}, false);
})
}
  1. 组件内使用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);
});
})
  1. 开发环境执行效果如下

7.2、方式二(推荐)

改写成通用的事件监听函数,支持链式调用

  • 开发环境下,由mockEvent.js文件里的dispatchEvent触发自定义的deviceready事件;

  • 小程序里运行,则由真实的deviceready事件触发

  1. 定义
  • 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;
}
  1. 使用
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的更多相关文章

  1. Hybrid APP混合开发的一些经验和总结

    http://www.cnblogs.com/kingplus/p/5588339.html 写在前面: 由于业务需要,接触到一个Hybrid APP混合开发的项目.当时是第一次接触混合开发,有一些经 ...

  2. Hybrid APP混合开发

    写在前面: 由于业务需要,接触到一个Hybrid APP混合开发的项目.当时是第一次接触混合开发,有一些经验和总结,欢迎各位一起交流学习~ 1.混合开发概述 Hybrid App主要以JS+Nativ ...

  3. Hybrid App 应用开发中 9 个必备知识点复习(WebView / 调试 等)

    前言 我们大前端团队内部 ?每周一练 的知识复习计划继续加油,本篇文章是 <Hybrid APP 混合应用专题> 主题的第二期和第三期的合集. 这一期共整理了 10 个问题,和相应的参考答 ...

  4. Hybrid App混合模式开发的了解

    Hybrid App(混合模式移动应用)是指介于web-app.native-app这两者之间的app,兼具"Native App良好用户交互体验的优势"和"Web Ap ...

  5. (一)Hybrid app混合开发模式

    hybrid app是什么? 这里我们先看一下词条上的定义 Hybrid App:Hybrid App is a mobile application that is coded in both br ...

  6. SharePoint 2013 搭建app本地开发环境

    使用SharePoint App,如果要通过应用程序目录分发 SharePoint 相关应用程序,如具有完全控制权限的 SharePoint 相关应用程序(无法部署到 Office 365 网站),则 ...

  7. 【Hybrid App】Hybrid App开发实战

    [引言]近年来随着移动设备类型的变多,操作系统的变多,用户需求的增加,对于每个项目启动前,大家都会考虑到的成本,团队成员, 技术成熟度,时间,项目需求等一堆的因素.因此,开发App的方案已经变得越来越 ...

  8. 跨平台 webapp 开发技术之 Hybrid App

    前所知的 APP 开发模式有三种: 基于操作系统运行的 APP -> Native App,侧重于原生开发,用户体验好,需要安装才会升级 基于浏览器运行的 APP -> Web App,侧 ...

  9. Hybrid App开发实战

    Hybrid App开发实战 作者 李秉骏 发布于 九月 04, 2013 | [引言]近年来随着移动设备类型的变多,操作系统的变多,用户需求的增加,对于每个项目启动前,大家都会考虑到的成本,团队成员 ...

随机推荐

  1. 建立QT工程的规范型,以及重要性

    当前管理开发多个项目,故名Projects 下一级目录,具体项目,故示例Project,根据实际情况自行取名 再下一级目录,有三个子目录 bin:生成的可执行文件或者动态链接库,build:编译源码时 ...

  2. Java 常用Set集合和常用Map集合

    目录 常用Set集合 Set集合的特点 HashSet 创建对象 常用方法 遍历 常用Map集合 Map集合的概述 HashMap 创建对象 常用方法 遍历 HashMap的key去重原理 常用Set ...

  3. Unity3D学习笔记6——GPU实例化(1)

    目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成两次 ...

  4. 《Ranked List Loss for Deep Metric Learning》CVPR 2019

    Motivation: 深度度量学习的目标是学习一个嵌入空间来从数据点中捕捉语义信息.现有的成对或者三元组方法随着模型迭代过程会出现大量的平凡组导致收敛缓慢.针对这个问题,一些基于排序结构的损失取得了 ...

  5. MySQL--创建计算字段

    存储在数据库表中的数据一般不是应用程序所需要的格式.下面举几个例子.  如果想在一个字段中既显示公司名,又显示公司的地址,但这两个信息一般包含在不同的表列中.  城市.州和邮政编码存储在不同的列中 ...

  6. 如何在CentOS上找出逐渐耗尽磁盘空间的目录和文件

    起因 随着系统运行,CentOS空间不断减少,对此非常焦虑,到底磁盘空间被哪些新增文件占用了呢? 分析过程,主要使用du命令,逐层找出消耗空间的目录 1.在根目录下检索一下文件的占用情况,执行du命令 ...

  7. ExpressionChangedAfterItHasBeenCheckedError详细解释

    一个angular组件,他的生命周期是这样的 update bound properties for all child components/directives call ngOnInit, On ...

  8. JS计算文本字符串字节长度和像素长度的方法

    来源:js获取字符长度并计算px宽度 - [云]风过无痕 - 博客园 (cnblogs.com) <!DOCTYPE html> <html lang="en"& ...

  9. YII地址切换

    以/开头表示跳出当前控制器 例如 return $this->render('/code/login'// 跳出当前控制器,进入Code下login视图 ,['model' => $mod ...

  10. JPA作持久层操作

    JPA(Hibernate是jpa的实现) jpa是对实体类操作,从而通过封装好的接口直接设置数据库的表结构.虽然jpa可以直接通过编写java代码来操作数据库表结构,避免了sql的编写,但别忘了需要 ...