前言

在JSBridge实现后,前端网页与原生的交互已经通了,接下来就要开始规划API,明确需要提供哪一些功能来供前端调用。

但是在这之前,还有一点重要工作需要做:

明确H5与Native的职责划分,确定哪一些功能可以由H5实现,哪一些功能只能由原生实现

Native与H5职责划分

使用Hybrid模式,用H5开发页面的本质是:

减少工作量(一套代码,多个平台),以及快速的更新迭代(譬如线上更新),而且还需要考虑Native端的高性能以及系统API调用能力(否则直接用纯H5就可以了)

因此在进行职责划分时,就得充分的考虑前端渲染,JS语言以及原生渲染,Java/OC等语言的特性,基本总结如下:

  • 混合页面导航栏组件由原生实现

  • 一些重要的业务页面、带有复杂动画或交互的页面以及一些固定页面由原生实现

  • 系统级UI由原生统一实现

  • 页面切换的转场由原生实现

  • CPU密集型任务、底层的优化要由原生完成

  • 其它功能能用H5实现(并且效果不错)的就尽量不要用原生

导航栏组件由Native实现

尝试过,也对比过很多的混合开发框架,譬如Dcloud的HTML5+,钉钉里的DD API,自己也尝试过不同的方式,

最终发现导航栏的最好做法还是由原生提供,核心原因如下:

  • H5页面加载过程会有白屏问题(也别是弱网络情况),如果整个页面都是H5实现,那么白屏了就体验非常差,而且连基本的交互与操作都没了

仅基于这一点,就已经拍板了由Native导航栏组件+webview(加载H5)来组成页面,而原生提供一些API来供网页操控导航栏(譬如标题,按钮等)

整体页面布局如下:

而H5端可以通过原生提供的API来操控导航栏,以下举例为quick中规划的API:

// 仅提供一部分示例
quick.navigator.setTitle({
title: '标题',
subTitle: '子标题',
success: function(result) {},
error: function(error) {}
}); quick.navigator.setRightBtn({
isShow: 1,
text: '按钮右1',
// 设置图片的优先级会较高
//imageUrl: 'http://xxx/test.png',
// 从右数起第几个
which: 0,
success: function(result) {
/**
* 按钮点击后回调
*/
},
error: function(error) {}
});

多tab页面也由原生提供

实际开发中Native导航栏组件+webview也就满足绝大部分的页面需求了,但是还有一些特殊页面是这种实现达不到的,譬如多Tab页面

上述这种内含多tab的页面,每一个tab里都是单独的页面,而且可以通过滑动等手势来切换,甚至tab还会有一些渐变动画,导航栏也配合改变等(常见于APP首页)

为了统一实现,这类页面的导航栏与底部tab均是由原生实现,由H5通过API打开这类原生页面,并将需要加载的网页地址传入,如下

quick.page.openLocal({
className: '那种原生页面的标识,可以唯一查询到相应的界面',
data: {
// 需要加载的n个url
url1: 'http://...',
urln: 'http://...',
},
success: function(result) {},
error: function(error) {}
});

然后,在每一个前端页面(webview里加载的内容),可以分别在对于页面的脚本里进行自己的交互控制

重要的业务页面由原生实现

对于一些重要的业务页面,如登陆,注册,支付等,处于安全性以及交互性的考虑(就是一个APP的门面),会采用完全由Native实现

(当然了,一般这些页面的变动频率也不大)

一些默认提示页面采用原生实现

webview加载网页时,一般情况原生都是会对加载情况进行监听的,比如是否网络异常。服务器响应异常,页面加载崩溃等,

为了防止APP假死,原生会提高一些默认提示页面

上述只是一个原型示例,实际上,很多情况都可以由原生提供统一提示页面,

如404,页面崩溃,网络错误等

交互性强、动画复杂的页面采用原生实现

除了关键性页面,还有一类,就是H5不好实现的(或者说达不到要求的、实现代价过大的),也应该由原生实现

譬如以某图像处理软件某个界面截图为例

这种页面涉及到了明显不太适合H5实现的图像处理,因此原生才是更佳的选择(当然了,实际上H5的canvas是由图像处理能力的)

系统级UI由原生统一实现

前面提到了页面的选择,但页面内的内容也是需要抉择的,比如一些UI显示控件(alert,toast等)

虽然H5完成可以实现这些UI控件,并且可以和原生模拟的一样,但是基于以下考虑,所有系统级的UI全部由原生实现并提供API:(原生和H5需统一风格)

  • 每一个合格的原生应用本身就会有一套自己风格的UI,因此不存在重复开发问题

  • H5本身可以实现这些组件,但是如果要模拟的和原生一摸一样的话代价并不小,而且体验并不能完全接近原生(比如遮罩无法覆盖导航栏)

  • 如果是原生提供的,更改风格时原生改掉就行了,其它无效变动,如果H5单独维护一套,那么就被迫一起同步,平白新增很多的工作量

  • 而且H5还会存在一些坐标、尺寸计算偏差问题

一般情况下H5通过如下API即可调用

quick.ui.toast('xxxx');
quick.ui.alert('xxxx'); quick.ui.alert({
title: "标题",
message: "信息",
buttonName: "确定",
success: function(result) {
// 点击 alert的按钮后回调
},
error: function(err) {}
});

页面切换的转场由原生实现

一般PC浏览器中,页面之间的调整直接通过a标签完成(或者改变href跳转),

但是这种跳转有一个缺点:

无法使用转场动画,每次都是干巴巴的等浏览器加载进度条,体验很差

因此针对这种情况,原生需要提供特点的API来供页面调用,可以有原生转场动画,在新的webview中打开这个页面

quick.page.open({
pageUrl: "./xxx.html",
data: {
// 额外传递的数据
key1: 'value1'
},
success: function(result) {},
error: function(error) {}
});

采用这种方式打开的页面不再是在本webview中跳转,而是直接用新的webview打开,有过渡动画,而且以前的页面仍然存在内存中,接近原生体验

譬如

页面A -> 页面B -> 页面C

可以看到,如果是直接调整,页面A和B是不存存在的,而是会被替换,但是采用原生webview打开后,三个页面同时存在

仍然支持第三方页面的href跳转

虽然说可以有API打开的增强方式,但是仍然需要支持href跳转,这在集成第三方页面时十分重要(将已经写好的第三方纯网页集成到容器中,作为某个子模块)

这里有一点需要注意:

这类页面一般由a标签或href跳转直接打开,没有转场动画,但是需要webview容器保存访问历史记录,
以避免多次跳转后一个后退就直接退出了整个模块

CPU密集型任务、底层的优化要由原生完成

当涉及到一些大量计算时,尽量避免直接在网页端完成,而是应该由原生提供API完成。

譬如对一张图片进行图像处理(曝光、水印、压缩等等),如果直接由网页完成的话会发现非常卡,发热也严重,而原生则没有这么多的问题

关于底层优化,其实整套混合开发框架中,底层容器的实现是核心部分

容器是否健壮,优化的如何,直接影响整个应用的体验

关于原生容器应该如何进行优化,后续会有专门的文章,这里不赘述,只是稍微提及一下:

  • 支持H5页面的离线访问(有线上版本和离线版本,通过本地路由表映射)

  • 离线资源动态更新(结合离线访问一起,比较复杂)

  • 资源缓存(如图片的缓存,脚本样式的缓存等)

  • 统一数据埋点采样等(手机应用使用数据)

  • ajax请求等等(还有很多,不一一列举)

能用H5实现的就尽量不要用原生

接下来就是在实际开发过程遵循的准则:

  • 能用H5实现的就尽量不要用原生

乍看之下可能和上述的有矛盾,但其实又是合理的,在排除了一些不适合H5实现的页面,剩余的绝大部分都是普通的业务页面,

这类页面基本可以毫无压力的采用H5。

所以,这时候,第一想法都是采用H5完成(因为一套代码可以在至少三个平台运行-浏览器,Android,iOS),

遇到一些比较困难的页面再去考虑原生实现(从开发效率上,维护代价上,更新方便上都比较麻烦)

那些H5开发中遇到最多的页面

最后,看下实际开发过程中遇到的最多的页面吧(以实际遇到的N个项目的总结)

  • 列表页面(下拉刷新,加载更多)

  • 纯详情展示页面(标题,关键字,内容)

  • 九宫格首页

  • 图片轮播(时常结合列表和九宫格)

  • 标准的表单提交页面

没错,80%都是上述这种可以算非常简单的页面。

譬如封装过一个下拉刷新组件,基本别人基于这个组件来开发,列表的代码几乎是千篇一律。(当然了,剥离了业务逻辑而言)

结束语

时至今日,Hybrid模式已经过了它最火的时候,市面上也出现如weexreact-native等直接写原生组件的框架,

但是,现在使用最多,应用最广的仍然要属这种传统的Hybrid模式,它已经进入了稳定期(可以说,传统H5开发(泛概念)不被APP淘汰,这种模式很难被挤下舞台)

返回根目录

源码

github上这个框架的实现

quickhybrid/quickhybrid

附录

参考资料

【quickhybrid】H5和原生的职责划分的更多相关文章

  1. H5和原生的职责划分

    前言 在JSBridge实现后,前端网页与原生的交互已经通了,接下来就要开始规划API,明确需要提供哪一些功能来供前端调用. 但是在这之前,还有一点重要工作需要做: 明确H5与Native的职责划分, ...

  2. APP中的 H5和原生页面如何分辨、何时使用

    一.APP内嵌H5和原生的区别 1.原生的页面运行速度快,比较流畅. H5页面相对原生的运行性能低,特别是一些动画效果有明显卡顿. 2.H5页面的很多交互都没有原生的好,比如弹层.输入时候的页面滑动 ...

  3. APP中的 H5和原生页面如何分辨?

    一.APP内嵌H5和原生的区别 1.原生的页面运行速度快,比较流畅.H5页面相对原生的运行性能低,特别是一些动画效果有明显卡顿. 2.H5页面的很多交互都没有原生的好,比如弹层.输入时候的页面滑动 等 ...

  4. H5和原生APP之间的区别

    最近项目中因各种客观因素,移动端都是默认用的纯H5 APP,感受最深的就是各种坑啊,好大的坑啊.产品上线后,带着各种坑后的总结原因方发现很多人都说纯H5 APP一次编写就能支持android和IOS两 ...

  5. h5 与原生 app 交互的原理

    现在移动端 web 应用,很多时候都需要与原生 app 进行交互.沟通(运行在 webview中),比如微信的 jssdk,通过 window.wx 对象调用一些原生 app 的功能.所以,这次就来捋 ...

  6. 客户端相关知识学习(二)之h5与原生app交互的原理

    前言 现在移动端 web 应用,很多时候都需要与原生 app 进行交互.沟通(运行在 webview中),比如微信的 jssdk,通过 window.wx 对象调用一些原生 app 的功能.所以,这次 ...

  7. H5嵌入原生开发小结----兼容安卓与ios的填坑之路

    一开始听说开发H5,以为就是做适配现代浏览器的移动网页,心想不用管IE了,欧也.到今天,发现当初too young too simple,兼容IE和兼容安卓与IOS,后者让你更抓狂.接下来数一下踩过的 ...

  8. H5获取原生传过来的值

    项目开发中,可能会涉及到原生页面跳转到H5页面,然后H5页面要返回原生页面,通常使用的方法就会失效:this.$router.go(-1);怎么解决呢,这样就需要原生跳转H5页面的时候,在URL里传递 ...

  9. h5启动原生APP总结

    许久没有写博客了,最近有个H5启动APP原生页面的需求,中间遇上一些坑,看了些网上的实现方案,特意来总结下 一.需要判断客户端的平台以及是否在微信浏览器中访问 1.客户端判断 在启动APP时,Andr ...

随机推荐

  1. Datatable转换为Json

    /// <summary> /// Datatable转换为Json /// </summary> /// <param name="table"&g ...

  2. 关于帧动画steps属性的理解

    CSS3的Animation有八个属性 animation-name animation-duration animation-delay animation-iteration-count anim ...

  3. iOS开发针对对Masonry下的FPS优化讨论

    今天博客的内容就系统的讨论一下Masonry对FSP的影响,以及如何更好的使用Masonry.如果你对iOS开发足够熟悉的话,那么对Masonry框架应该不陌生.简单的说,Masonry的诞生让Aut ...

  4. HttpClient发送Post请求,get请求

    // 创建默认的httpclient实例 CloseableHttpClient httpclient = getHttpClient(); CloseableHttpResponse respons ...

  5. C#用panel实现子窗体的切换

    今天编程的时候,遇到一个问题:在同一个窗体区域加载两个不同的窗体,每次只显示一个子窗体并能够对这两个子窗体做切换. 对于这个问题用panel控件是非常简单的,只要每次清空panel控件上的子窗体,然后 ...

  6. [转载] java垃圾回收机制

    转载自http://blog.csdn.net/randyjiawenjie/article/details/7551228 http://www.daniel-journey.com/archive ...

  7. How To Use Linux epoll with Python

    http://scotdoyle.com/python-epoll-howto.html Line 1: The select module contains the epoll functional ...

  8. SICK激光雷达LMS511测量数据说明

    帧结构说明 LMS511的官方手册存在几个版本,在<Laser Measurement Systems of the LMS500 Product Family>的英文手册中,对单次(连续 ...

  9. StackExchange.Redis学习笔记(三)

    这一章主要写一些StackExchange.Redis的配置及不太经常用到的函数 数据库连接 下面是我的连接字符串,里面指定了地址,密码,及默认的数据库 Redis启动后默认会分成0-15个数据库,不 ...

  10. python 标准模块shlex

    shlex模块为基于Uninx shell语法的语言提供了一个简单的lexer(也就是tokenizer) 举例说明: 有一个文本文件quotes.txt This string has embedd ...