jsbridge是随着Hybrid App的流行而产生的一种技术。那么Hybrid App是啥?Hybrid App又称混合App,即同时使用了前端web技术(js,css,html)和原生native技术(java,kotlin,swfit,object-c)进行开发的移动应用。

混合开发的优缺点

  • 优点:开发快,易更新,开发周期短,跨平台
  • 缺点:性能问题,兼容性问题

常见的混合开发框架

  • webview渲染:Cordova,uni-app
  • 原生渲染:React Native,Weex,Flutter
  • 混合渲染:小程序

jsbridge

现在很多App的页面,不一定都是原生实现的,可能是通过webview直接加载一个线上的h5站点。比如打开某粉红App的会员购页面,其实就是个移动端的网站。

 

粉红App

 

这么一说,好像和混合开发也没啥联系。不过你仔细看下页面的右上角,会发现有个分享按钮:点击分享图标,可以把当前页面分享到第三方平台,分享后,web页面需要知道是否分享成功。

这里就涉及了native端和web端的通信:native分享的内容,需要web端的js进行设置(js -> native);native分享成功后,需要把消息通知给js(natvie -> js)。为实现两端的双向通信机制,就需要jsbridge技术了。

Native通知JS

因为h5网页是通过原生端的webview加载的,所以原生端对当前网页拥有很高的权限:Native端可以直接在当前webview里执行js代码。

1
2
3
4
// web端
function nativeCallback(data) {
  console.log('data', data);
}

  

我们在js的执行环境里定义了一个全局方法nativeCallback,native端可以直接执行nativeCallback(123)方法,也就把数据传给了js。

这种方案是不是有点熟悉,jsonp就是类似的原理:只不过调用全局方法的时机,从服务器端改成了native端。

JS通知Native

前端常见的协议有:

1. http/https协议:https://www.baidu.com

2. 本地file协议: file:///Users/deepred/myproject/index.html

其实我们也可以自定义协议:sslocal://openModal?text=hello,客户端通过分析这段scheme就能知道web端要调用原生的哪些方法,同时数据也通过query参数进行了传递。

那web端如何发送这段scheme给native端呢?

  • 拦截consolealertprompt 全局方法。
alert('sslocal://openModal?text=hello')

native可以拦截webview中的这些方法,从而调用原生方法。

  • 拦截url请求
1
2
3
4
const ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = 'sslocal://openModal?text=hello';
document.body.appendChild(ifr);

  

web端加载了一个iframe,请求了sslocal://openModal?text=hello, native端通过拦截url请求,从而调用原生方法。

使用scheme字符串来调用方法始终不够直观,其实我们还可以向webview里注入一个js全局对象,这个全局对象拥有调用native的方法的能力。

  • API注入
// nativeApp是由native端注入的全局变量
nativeApp.openModal('hello');

双向通信

前面我们介绍的几种方法,都只能单向通信。如何进行双向通信呢?这时候就需要前端自己实现一个JS-SDK,维护js回调函数的Map。

首先,我们假设客户端会向webview中注入一个全局对象BILIAPP

// BILIAPP是原生端注入的
1
2
3
const BILIAPP = {
  invoke(methodName, param, onSuccessKey, onFailKey) {}
}

  

该对象有个invoke方法,接收4个参数:

  1. 调用的原生方法名
  2. 方法参数
  3. 成功回调函数id
  4. 失败回调函数id

我们没法直接传函数给原生方法,所以这里只能传回调函数的id,id对应的实际函数,由前端这边维护。

sdk.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
let id = 1;
 
const uuid = () => {
  return `callback_${id++}`;
};
 
// BILISDK是web端注入的
const BILISDK = {
 
  // key是回调函数的id
  // value是回调函数的值
  callbacks: {
 
  },
 
  // 暴露给前端使用的方法,支持Promise
  invokeP(methodName, param) {
    return new Promise((resolve, reject) => {
      const successCb = (data) => {
        resolve(data);
      };
      const failureCb = (data) => {
        reject(data);
      };
 
      return BILISDK._invoke(methodName, param, successCb, failureCb);
    });
  },
 
  // 实际真正调用原生对象的方法
  _invoke(methodName, param, successCb, failureCb) {
    const onSuccessKey = uuid();
    const onFailKey = uuid();
    // 存入callbacks hash表中
    this.callbacks[onSuccessKey] = successCb;
    this.callbacks[onFailKey] = failureCb;
    // BILIAPP是否注入成功
    BILIAPP && BILIAPP.invoke && BILIAPP.invoke(methodName, JSON.stringify(param), onSuccessKey, onFailKey);
  },
 
  // 暴露给原生端使用的方法
  invokeFromNative(key, param) {
    if (typeof param === "string") {
      try {
        param = JSON.parse(param)
      } catch (ex) {
 
      }
    }
    const callback = this.callbacks[key];
 
    if (callback) {
      callback(param);
    }
  }
 
}
 
// 使用BILISDK调用原生方法
BILISDK.invokeP('getVersion').then((res) => {
  console.log('res', res);
})
现在前端调原生方法,不要直接使用BILIAPP.invoke,而是通过BILISDK.invokeP间接调用。BILISDK.invokeP支持Promise化,同时维护了一个hash表
 
const BILISDK = {
  callbacks: {
    'callback_1': function() {},
    'callback_2': function() {},
  },
}

  

BILISDK.invokeFromNative是暴露给Native端使用的。当原生方法调用完成后,根据成功还是失败,Native端可以调用BILISDK.invokeFromNative(成功或者失败的id),而这个id就是当初BILIAPP.invoke调用时传进来的id。

通过上面的方法,我们就实现了js -> native -> js 的双向通信了。当然理论上,我们还需实现:native -> js -> native 的双向通信,但是原理是一样的,这时客户端就需要自己实现一个Native-SDK,维护Native端回调函数的Map。

JS-SDK的接入

前面我们实现的sdk.js,如果引入web站点呢?

把sdk打包成umd规范的js静态文件,上传到cdn或者发布到npm

  1. 在index.html里面直接通过script标签引入或者js直接import导入即可。该方案,前端维护sdk。(维护成本高)
  2. 客户端在初始化一个WebView打开页面时,直接注入sdk。该方案,客户端维护sdk。(优先推荐)

参考

  1. Hybrid App技术解析 -- 原理篇
  2. 小白必看,JSBridge 初探
  3. 2小时搞定移动端混合开发基础入门
posted on   ygunoil  阅读(435)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
历史上的今天:
2019-02-22 vue组件通信方式总结
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示