Hybrid混合开发最强小白攻略

3,145 阅读5分钟

我正在参加跨端技术专题征文活动,详情查看:juejin.cn/post/710123…

介绍

移动端开发过程早期,都会讨论是选择APP原生开发还是H5来做,实际过程中,很多团队结合了两点都各取所长选用了混合开发来实现。本期我们就会根据混合开发展开分析讨论,以及实际中完成开发的一些手段进行讲解。

正文

混合开发

那什么又是混合开发呢?混合开发(即Hybrid App)其实是一种开发模式,它混合使用了Native和Web技术开发来实现同一个应用。接下来,我们先来对比一下,原生和H5的优缺点是什么吧:

特点NativeH5
流畅性较为流畅,且响应快有时会出现卡顿,响应会稍慢
受网络影响比较弱非常大
开发周期较长较短
灵活度迭代慢,需要等待应用商店审核版本迭代快,更新即可
可移植性较弱,受系统影响比较出色,跨平台跨系统
功能限制较少,API丰富,能实现绝大部分功能需求受浏览器限制严重,很多功能无法实现

通过上面的分析,我们大概就会设想,如果我们把他们的优点结合起来,去使用那么这个开发过程岂不是要起飞了。其实就是这样,目前,混合开发明确会出现的优点是开发快,易更新迭代,还有开发周期较短(至少比原生短很多),但依旧没有解决的还是很多兼容问题和性能问题,但这些缺点在Android 5.0+与IOS9.0+以后的好了很多。目前最成功的案例应该就是微信公众号了,它通过JSSDK让原生和H5双向互通起来。

说到这里,其实从2011年PhoneGap诞生开始直到现在这10多年的时间,我们一直在找寻一个流畅性较高,开发周期较短,功能齐全并且其中业务板块可以快速更新迭代的跨平台跨系统的解决方案。主流跨端目前还是比较多的,分了以下这几大类:

  1. web整体渲染为主: Cordova(前身为PhoneGap)
  2. 原生渲染组件为主: React Native,weex
  3. 开放底层渲染能力: Flutter
  4. 较封闭的混合渲染: 微信/支付宝/抖音/百度等小程序 (通常会用到taro或者uniapp做技术栈)

JSBridge桥接器

或许,很多人总会有这疑问,我们要把前端页面渲染到app上的webview中,那么中间必然少不了交互,那么原生与h5如何进行双向通信原理的?这里的答案就是——JSBridge桥接器,它并非是一种具体的手段,而是一种通信机制,它以js引擎或webview容器为媒介进行协议约定进行一个双向通信。在开发过程中,往往原生开发会与前端开发做出一个类似于接口文档形式的API使用文档的东西,根据文档来进行协助,即原生开发只注重如何封装成JS接口,然后给webview容器注入,而前端开发只要清楚调用即可,以下是之前本人使用过的一个简单API使用说明:

接口文档.png

JSBridge实现的两种方案

拦截URL Schema

拦截WebView请求的URL Schema是H5对原生发起通信最早的一个方案,URL Schema是类URL的一种请求格式,

即 :<protocol>://<domain>/<path>?<query>

如:"jsbridge://getUserInfo?a=1&b=2" ,当然 <protocol> 协议头 是自定义的,不一定非要是 jsbridge

其原理就是,如下图:

拦截请求流程.png

原生移动端是可以拿到我们发出的任何一个请求的,他们会对这些请求进行处理,如果带上<protocol> 协议头 后就进行拦截处理,然后解析出对应的功能来返回给我们使用。

当与移动端协议好某个功能后,就可以调取了,有如下几种方式:

  1. a标签:

    <a href="jsbridge://getUserInfo?a=1&b=2">
    
  2. location.href:

    location.href = "jsbridge://getUserInfo?a=1&b=2"
    
  3. window.open:

    window.open("jsbridge://getUserInfo?a=1&b=2")
    
  4. iframe.src:

    var iframe = document.createElement('iframe')
    iframe.src = "jsbridge://getUserInfo?a=1&b=2"
    
  5. 发送ajax请求

    $ajax.get("jsbridge://getUserInfo?a=1&b=2")
    

WebView容器注入JSAPI

可能刚才你会发现上面的拦截URL Schema这个方案,其实写起来是非常的丑陋的不直观,即便后面加深它的封装,也是不太优雅,而且最致命的问题就是URL是有长度限制的,当然可以通过扩展 ajax post 方式来解决URL长度问题但这样相对于使用方式又受到了限制,总之不太好,此时又有了另一种方案,就是向WebView容器注入JSAPI。

它的原理就是说App直接往Webview里注入js对象,这样Webview可以使用这些注入的js对象,就可以实现调取原生的功能了。

通常我们主要会选择使用DSBridge库,它是一个三端易用的现代跨平台 JSBridge,支持以类的方式集中统一管理API,同时还支持同步调用和异步调用。

dsBridge.call("callApp",{"action":"getUserInfo","params":{"a":1,"b":2}},res=> { 			      
   alert(JSON.stringify(res)); 
})

上面可以看到,我们调用原生API是多么的直白清晰,但凡事没有什么绝对的完美,它也有个致命的缺陷,就是安卓低端机是不支持注入JSAPI的,如果开发的app需要兼容性非常高的话,这样就无法使用这个方案了。

结语

在这几年的实践中,感觉一些活动类小页面还是比较适合H5 Hybrid来实现的,至于用拦截还是注入,见仁见智了,如果感觉直观好维护选择注入的方式,如果认为兼容性更重要则选择拦截的方式。但它觉不适合在app大规模使用,一则是app审核很有可能不通过,二则是影响用户体验,三则是如果配合不当那么开发周期反而会变长。

另外,如果有需求是让我们开发一个完整的模块嵌入app时,不妨嵌入wgt包来实现(HBuilder X中可生成wgt包),它类似于小程序嵌入了app中,响应流畅性还有维护方面都是个较为稳妥的方案。