Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >小白必看,JSBridge 初探

小白必看,JSBridge 初探

作者头像
政采云前端团队
发布于 2020-02-25 10:59:59
发布于 2020-02-25 10:59:59
2.6K00
代码可运行
举报
文章被收录于专栏:采云轩采云轩
运行总次数:0
代码可运行

? 向此次肺炎疫情中逝世的同胞表示哀悼。

? 想要了解更多不掺水的原创,请戳上方蓝色字体:政采云前端团队 关注我们吧~

本文首发于政采云前端团队博客:小白必看,JSBridge 初探 https://www.zoo.team/article/jsbridge

JSBridge 的起源

近些年,移动端普及化越来越高,开发过程中选用 Native 还是 H5 一直是热门话题。Native 和 H5 都有着各自的优缺点,为了满足业务的需要,公司实际项目的开发过程中往往会融合两者进行 Hybrid 开发。Native 和 H5 分处两地,看起来无法联系,那么如何才能让双方协同实现功能呢?

这时我们想到了 Codova ,Codova 提供了一组与设备相关的 API,是早期 JS 调用原生代码来实现原生功能的常用方案。不过 JSBridge 真正在国内广泛应用是由于移动互联网的盛行。

JSBridge 是一种 JS 实现的 Bridge,连接着桥两端的 Native 和 H5。它在 APP 内方便地让 Native 调用 JS,JS 调用 Native,是双向通信的通道。JSBridge 主要提供了 JS 调用 Native 代码的能力,实现原生功能如查看本地相册、打开摄像头、指纹支付等。

H5 与 Native 对比

name

H5

Native

稳定性

调用系统浏览器内核,稳定性较差

使用原生内核,更加稳定

灵活性

版本迭代快,上线灵活

迭代慢,需要应用商店审核,上线速度受限制

受网速 影响

较大

较小

流畅度

有时加载慢,给用户“卡顿”的感觉

加载速度快,更加流畅

用户体验

功能受浏览器限制,体验有时较差

原生系统 api 丰富,能实现的功能较多,体验较好

可移植性

兼容跨平台跨系统,如 PC 与 移动端,iOS 与 Android

可移植性较低,对于 iOS 和 Android 需要维护两套代码

JSBridge 的双向通信原理

  • JS 调用 Native

JS 调用 Native 的实现方式较多,主要有拦截 URL Scheme 、重写 prompt 、注入 API 等方法。

拦截 URL Scheme

AndroidiOS 都可以通过拦截 URL Scheme 并解析 Scheme 来决定是否进行对应的 Native 代码逻辑处理。

Android 的话,Webview 提供了 shouldOverrideUrlLoading 方法来提供给 Native 拦截 H5 发送的 URL Scheme 请求。代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CustomWebViewClient extends WebViewClient {
  @Override
  public boolean shouldOverrideUrlLoading(WebView view, String url) {
  ......
    // 场景一:拦截请求、接收 scheme
    if (url.equals("xxx")) {

       // handle
       ...
       // callback
       view.loadUrl("javascript:setAllContent(" + json + ");")
       return true;
     }
     return super.shouldOverrideUrlLoading(url);
   }
}

iOS 的 WKWebview 可以根据拦截到的 URL Scheme 和对应的参数执行相关的操作。代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    if ([navigationAction.request.URL.absoluteString hasPrefix:@"xxx"]) {
        [[UIApplication sharedApplication] openURL:navigationAction.request.URL];
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

这种方法的优点是不存在漏洞问题、使用灵活,可以实现 H5 和 Native 页面的无缝切换。例如在某一页面需要快速上线的情况下,先开发出 H5 页面。某一链接填写的是 H5 链接,在对应的 Native 页面开发完成前先跳转至 H5 页面,待 Native 页面开发完后再进行拦截,跳转至 Native 页面,此时 H5 的链接无需进行修改。但是使用 iframe.src 来发送 URL Scheme 需要对 URL 的长度作控制,使用复杂,速度较慢。

重写 prompt 等原生 JS 方法

Android 4.2 之前注入对象的接口是 addJavascriptInterface ,但是由于安全原因慢慢不被使用。一般会通过修改浏览器的部分 Window 对象的方法来完成操作。主要是拦截 alert、confirm、prompt、console.log 四个方法,分别被 Webview 的 onJsAlert、onJsConfirm、onConsoleMessage、onJsPrompt 监听。其中 onJsPrompt 监听的代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public boolean onJsPrompt(WebView view, String origin, String message, String 		defaultValue, final JsPromptResult result) {
  String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message,			 defaultValue);
  xxx;
  return true;
}

iOS 由于安全机制, WKWebView 对 alert、confirm、prompt 等方法做了拦截,如果通过此方式进行 Native 与 JS 交互,需要实现 WKWebView 的三个 WKUIDelegate 代理方法。代码示例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{

  UIAlertController *alertController = [UIAlertController					alertControllerWithTitle:nil message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];

  [alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

      completionHandler();

  }])];

  [self presentViewController:alertController animated:YES completion:nil];

}

使用该方式时,可以与 Android 和 iOS 约定好使用传参的格式,这样 H5 可以无需识别客户端,传入不同参数直接调用 Native 即可。剩下的交给客户端自己去拦截相同的方法,识别相同的参数,进行自己的处理逻辑即可实现多端表现一致。如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
alert("确定xxx?", "取消", "确定", callback());

另外,如果能与 Native 确定好方法名、传参等调用的协议规范,这样其它格式的 prompt 等方法是不会被识别的,能起到隔离的作用。

注入 API

基于 Webview 提供的能力,我们可以向 Window 上注入对象或方法。JS 通过这个对象或方法进行调用时,执行对应的逻辑操作,可以直接调用 Native 的方法。使用该方式时,JS 需要等到 Native 执行完对应的逻辑后才能进行回调里面的操作。

Android 的 Webview 提供了 addJavascriptInterface 方法,支持 Android 4.2 及以上系统。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gpcWebView.addJavascriptInterface(new JavaScriptInterface(), 'nativeApiBridge');
public class JavaScriptInterface {
  Context mContext;

  JavaScriptInterface(Context c) {
    mContext = c;
  }

  public void share(String webMessage){	    	
    // Native 逻辑
  }
}

JS 调用示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
window.NativeApi.share(xxx);

iOS 的 UIWebview 提供了 JavaScriptScore 方法,支持 iOS 7.0 及以上系统。WKWebview 提供了 window.webkit.messageHandlers 方法,支持 iOS 8.0 及以上系统。UIWebview 在几年前常用,目前已不常见。以下为创建 WKWebViewConfiguration 和 创建 WKWebView 示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKPreferences *preferences = [WKPreferences new];
preferences.javaScriptCanOpenWindowsAutomatically = YES;
preferences.minimumFontSize = 40.0;
configuration.preferences = preferences;
    

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"share"];
  	[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"pickImage"];
}
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self.webView.configuration.userContentController 	removeScriptMessageHandlerForName:@"share"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"pickImage"];
}

JS 调用示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
window.webkit.messageHandlers.share.postMessage(xxx);
  • Native 调用 JS

Native 调用 JS 比较简单,只要 H5 将 JS 方法暴露在 Window 上给 Native 调用即可。

Android 中主要有两种方式实现。在 4.4 以前,通过 loadUrl 方法,执行一段 JS 代码来实现。在 4.4 以后,可以使用 evaluateJavascript 方法实现。loadUrl 方法使用起来方便简洁,但是效率低无法获得返回结果且调用的时候会刷新 WebView。evaluateJavascript 方法效率高获取返回值方便,调用时候不刷新WebView,但是只支持 Android 4.4+。相关代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
webView.loadUrl("javascript:" + javaScriptString);
webView.evaluateJavascript(javaScriptString, new ValueCallback<String>() {
  @Override
  public void onReceiveValue(String value){
    xxx
  }
});

iOS 在 WKWebview 中可以通过 evaluateJavaScript:javaScriptString 来实现,支持 iOS 8.0 及以上系统。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// swift
func evaluateJavaScript(_ javaScriptString: String,
  completionHandler: ((Any?, Error?) -> Void)? = nil)
// javaScriptString 需要调用的 JS 代码
// completionHandler 执行后的回调
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// objective-c
[jsContext evaluateJavaScript:@"ZcyJsBridge(ev, data)"]

JSBridge 的使用

  • 如何引用
    • 由 H5 引用 在我司移动端初期版本时采用的是该方式,采用本地引入 npm 包的方式进行调用。这种方式可以确定 JSBridge 是存在的,可直接调用 Native 方法。但是如果后期 Bridge 的实现方式改变,双方需要做更多的兼容,维护成本高
    • 由 Native 注入 这是当前我司移动端选用的方式。在考虑到后期业务需要的情况下,进行了重新设计,选用 Native 注入的方式来引用 JSBridge。这样有利于保持 API 与 Native 的一致性,但是缺点是在 Native 注入的方法和时机都受限,JS 调用 Native 之前需要先判断 JSBridge 是否注入成功
  • 使用规范

H5 调用 Native 方法的伪代码实例,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
params = {
  api_version: "xxx",	// API 版本
  title: "xxx",	// 标题
  filename: "xxx",	// 文件名称
  image: "xxx",	// 图片链接
  url: "xxx",	// 网址链接
  success: function (res) {
    xxx;	// 调用成功后执行
  },
  fail: function (err) {
    if (err.code == '-2') {
      fail && fail(err);	//	调用了当前客户端中不存在的 API 版本
    } else {
      const msg = err.msg;	//异常信息
      Toast.fail(msg);
    }
  }
};
window.NativeApi.share(params);

以下简要列出通用方法的抽象,目前基本遵循以下规范进行双端通信。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
window.NativeApi.xxx({
  api_version:'',
  name: "xxx",
  path: "xxx",
  id:	"xxx",
  success: function (res) {
    console.log(res);
  },
  fail: function (err) {
    console.log(err);
  }
});

由于初期版本选择了由 H5 本地引用 JSBridge,后期采用 Native 注入的方式。现有的 H5 需要对各种情况做兼容,逻辑抽象如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
reqNativeBridge(vm, fn) {
  if (!isApp()) {
    // 如果不在 APP 内进行调用
    vm.$dialog.alert({
      message: "此功能需要访问 APP 才能使用",
    });
  } else {
    if (!window.NativeApi) {
      // 针对初期版本
      vm.$dialog.alert({
        message: "请更新到最新 APP 使用该功能",
      });
    } else {
      // 此处只针对“调用了当前客户端中不存在的 API 版本”的报错进行处理
      // 其余种类的错误信息交由具体的业务去处理
      fn && fn((err) => {
        vm.$dialog.alert({
          message: "请更新到最新 APP 使用该功能",
        });
      });
    }
  }
}

总结

上述内容简要介绍了 JSBridge 的部分原理,希望对从未了解过 JSBridge 的同学能有所帮助。如果需要更深入的了解 JSBridge 的原理和实现,如 JSBridge 接口调用的封装实现,JS 调用 Native 时的回调的唯一性等。大家可以去查阅更多资料,参考更详细的相关文档或他人的整理成文的沉淀。

看完两件事

如果你觉得这篇内容对你挺有启发,我想邀请你帮我两件小事

1.点个「在看」,让更多人也能看到这篇内容(喜欢不点在看的,都是耍流氓)

2.关注公众号「政采云前端团队」,持续为你推送精选好文

招贤纳士

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 政采云技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
网站最终产品页使用单一入口还是多入口?
一般来说,网站的首页和分类页面收录不会有什么问题,除非在主导航有严重的蜘蛛陷阱,或网站已经被惩罚。大部分网站在结构方面面对的挑战,是使更多最终产品页面被收录。
茹莱神兽
2022/08/05
1K0
网站最终产品页使用单一入口还是多入口?
SEO操作不当,造成网站页面重复,如何解决?
网站重复内容页面过多会造成资源和精力的浪费、关键词的内部竞争,还会分散权重,得不偿失。若是因为站内重复内容页面过多被搜索引擎误判为采集站就麻烦了。
茹莱神兽
2022/06/07
5810
SEO操作不当,造成网站页面重复,如何解决?
网站筛选功能页面不收录,还有优化的必要么?
网站信息筛选功能页面是网站因为网页过多,数据过于庞大,为了方便用户浏览和查询所需要的信息而制作出来的多个条件的功能页面,目的是让用户能够快速通过筛选条件找到想要的内容。
茹莱神兽
2022/03/13
7900
网站筛选功能页面不收录,还有优化的必要么?
大二级分类产品页权重低,不收录怎么办?
典型树形结构首页链接到一级分类,一级分类页面再列出二级分类,这样,只要二级分类数目相差不太悬殊,权重值在二级分类页面上是大致平均分配的。
茹莱神兽
2022/07/07
4130
大二级分类产品页权重低,不收录怎么办?
浅谈网站导航系统中锚文字的分布及变化
合理的网站结构实在网站中分配锚文字的重要方法之一。最灵活常见的是在页面正文中或人工或自动加上其他页面的内部链接,链接锚文字可以有各种选择,这方面的应用学习目标非维基百科莫属。
茹莱神兽
2022/08/15
3640
浅谈网站导航系统中锚文字的分布及变化
CMS系统应该具备哪些基本功能呢?
绝大多数网站是通过CMS系统制作和管理的,SEO人员优化网站就会受制于CMS系统本身的灵活性和功能。市面上有很多开源免费的CMS系统,如中文的DEDE织梦、帝国、WordPress,英文的Joomla、Drupal等。
茹莱神兽
2022/09/03
9500
CMS系统应该具备哪些基本功能呢?
如何降低用户关注的非必要页面的权重传递?
每个网站都有一些在功能及用户体验方面很有必要、但在SEO角度没有必要的页面,比如隐私政策、用户登陆页面、用户注册页面、联系我们、甚至还包括“关于我们”页面。
茹莱神兽
2022/06/28
3750
如何降低用户关注的非必要页面的权重传递?
网站SEO诊断分析应该从哪方面入手?
网站SEO诊断是针对网站是否利于搜索引擎搜索、是否利于浏览和给浏览者美好的交互体验以及是否利于网络营销的一种综合判断行为,网站主要看打开速度和用户体验度。SEO推广人员的本质工作是围绕网站来展开,网站的优化效果好不好,离不开SEO诊断分析,如何对网站进行SEO诊断分析呢?
茹莱神兽
2022/01/21
7160
网站SEO诊断分析应该从哪方面入手?
站内SEO优化中相关文章调用及注意事项
众所周知,网站内链优化是搜索引擎算法中的重要组成部分,而相关文章推荐模块则是站内SEO优化必不可少的一环,在网站内页设置相关文章推荐模块能够提高整个网站粘度,最大程度上的留住用户,完成转化。
茹莱神兽
2022/03/31
4640
站内SEO优化中相关文章调用及注意事项
百度不收录,可能与网站的病态内链接有关
自从2021年4月百度批量整顿了3.8亿个网站之后,网站的收录速度明显下降了,很多网站关键词排名呈断崖式下跌,这是一场互联网浩劫。对于网站收录慢或者不收录现象,百度官方给的说法是,采集站、文章伪原创、与网上部分内容重合都是影响搜索引擎收录的因素。
茹莱神兽
2022/01/04
5530
百度不收录,可能与网站的病态内链接有关
大中型网站列表页翻页过多怎么优化?
稍大型的商务或信息类网站都可能会在产品列表,也就是最末一级的分类页面上,存在翻页过多的问题。通常产品列表会显示10个或20个产品,然后列出翻页链接,除了“上一页”和“下一页”,网站可能列出5个、10个翻页链接。
茹莱神兽
2022/08/01
8560
大中型网站列表页翻页过多怎么优化?
分类页权重高,产品页权重低不收录咋办?
树形结构对大部分网站来说是最优化的,若是域名权重比较低,就算网站扁平,最终产品页还是权重过低,无法达到搜索引擎蜘蛛抓取的最低标准,这个时候可以考虑彻底改变树形结构了。
茹莱神兽
2022/08/24
9780
分类页权重高,产品页权重低不收录咋办?
什么是description,如何优化描述标签?
网站优化中常说的description实际上是描述标签,它是HTML代码中Head部分除标题标签外与SEO有关的另一个标签,用于说明页面的主体内容。
茹莱神兽
2022/09/14
5840
什么是description,如何优化描述标签?
网站导航设计与站内链接优化汇总
网页导航表现为网页的栏目菜单设置、辅助菜单、其他在线帮助等形式。网页导航设置是在网页栏目结构的基础上,进一步为用户浏览网页提供的提示系统,由于各个网页设计并没有统一的标准,不仅菜单设置各不相同,打开网页的方式也有区别,有些是在同一窗口打开新网页,有些在新打开一个浏览器窗口。
茹莱神兽
2022/02/01
1.4K0
网站导航设计与站内链接优化汇总
怎样判断网站超链接的相关性呢?
任何行业都有权威网站作为整个行业的先行者,他们的最新动态便是这个圈内的权威,是大家关注的重点,同时也会影响这个行业的整体格局。网站要进行SEO推广,依托行业权威网站作为介质推荐网站,从而能快速达到好的排名获取订单转化,这便是网站SEO外链相关性带来的好处。
茹莱神兽
2022/01/22
7650
怎样判断网站超链接的相关性呢?
什么是符合搜索引擎友好的网站设计?
如果我们从搜索引擎蜘蛛的角度去看一个网站,在抓取、索引和排名时会出现一系列问题,解决了这些问题的网站设计就是对搜索引擎友好的网站。
茹莱神兽
2022/04/03
4930
什么是符合搜索引擎友好的网站设计?
个人博客网站如何做好SEO优化?
做网站不懂SEO其实是件很可怕的事情,好的SEO会对网站建设起到事半功倍的效果。相反,如果不懂,只是胡乱操作也会给自己带来众多困扰,网站seo优化的目标就是提升网站关键词的排名,帮助企业获得知名度以及更高的利益。
茹莱神兽
2022/02/11
1.9K0
个人博客网站如何做好SEO优化?
页面标题的优化要注意11个SEO问题
页面标题是包含Title标签中的文字,是页面优化最重要的因素。用户访问网站是,页面标题文字显示在浏览器窗口最上方,建议Title紧接着写在之后,然后再写其他标题和代码,尤其不要在中间插上JavaScript程序,这样搜索引擎可以快速找到标题标签。
茹莱神兽
2022/09/09
6690
页面标题的优化要注意11个SEO问题
网站导航系统设计应该注意哪些问题?
清晰的导航系统是网站设计的重要目标,对网站信息架构、用户体验影响重大,SEO也越来越成为导航设计时需要考虑的因素之一了。
茹莱神兽
2022/04/10
6040
网站导航系统设计应该注意哪些问题?
SEO如何建立优化网站关键词词库?
建立关键词词库,是SEO优化工作非常重要的事情。高权重的网站,必然需要强大的关键词库支持。实际上,网站权重的提升是一个增加网站词汇的过程。但大部分SEO人员,却没有合理的规划关键词库,甚至连最基本的Excel表格都没有,实际上这是一种盲目而又随意的行为。
茹莱神兽
2020/11/16
2.2K0
SEO如何建立优化网站关键词词库?
推荐阅读
相关推荐
网站最终产品页使用单一入口还是多入口?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验