浅谈Hybrid技术的设计与实现第三弹——落地篇

前言

接上文:(阅读本文前,建议阅读前两篇文章先)

浅谈Hybrid技术的设计与实现

浅谈Hybrid技术的设计与实现第二弹

根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多朋友就会觉得这个交互很简单嘛,其实并不难嘛,事实上单从Native与前端的交互来说就那点东西,真心没有太多可说的,但要真正做一个完整的Hybrid项目却不容易,要考虑的东西就比较多了,单从这个交互协议就有:

① URL Schema

② JavaScriptCore

两种,到底选择哪种方式,每种方式有什么优势,都是我们需要深度挖掘的,而除此之外,一个Hybrid项目还应该具有以下特性:

① 扩展性好——依靠好的约定

② 开发效率高——依赖公共业务

③ 交互体验好——需要解决各种兼容问题

我们在实际工作中如何落地一个Hybrid项目,如何推动一个项目的进行,这是本次我们要讨论的,也希望对各位有用。

文中是我个人的一些开发经验,希望对各位有用,也希望各位多多支持讨论,指出文中不足以及提出您的一些建议

设计类博客

http://www.cnblogs.com/yexiaochai/p/4921635.html
http://www.cnblogs.com/yexiaochai/p/5524783.html

iOS博客

http://www.cnblogs.com/nildog/p/5536081.html#3440931

Android博客

https://home.cnblogs.com/u/vanezkw

代码地址:https://github.com/yexiaochai/Hybrid

因为IOS不能扫码下载了,大家自己下载下来用模拟器看吧,下面开始今天的内容。

总体概述在第一章,有兴趣大家去看

细节设计在第二章,有兴趣大家去看

本章主要为打补丁

账号切换&注销

账户注销本没有什么注意点,但是因为H5
push了一个个webview页面,这个重新登录后这些页面怎么处理是个问题。

我们这边设计的是一旦重新登录或者注销账户,所有的webview都会被pop掉,然后再新开一个页面,就不会存在一些页面展示怪异的问题了。

正确读取

这里可能有点杞人忧天,因为Native程序不是自己手把手开发的,总是担心APP在正在拉取增量包时,或者正在解压时,读取了静态文件,这样会不会读取错误呢,后面想了想,便继续采用了之前的md5打包的方式,将落地的html中需要的文件打包为md5引用,如果落地页下载下来后,读不到本地文件就自己会去拉取线上资源咯。 

回退更新

我们在hybrid中的跳转,事实上每次都是新开一个webview,当A->B的时候,事实上A只是被隐藏了,当B点击返回的时候,便直接将A展示了出来,而A不会做任何更新,对前端来说是无感知的。

事实上,这个是一种优化,为了解决这种问题我们做了一个下拉刷新的特性:

 1 _.requestHybrid({
 2     tagname: 'headerrefresh',
 3     param: {
 4         //下拉时候展示的文案
 5         title: '123'
 6     },
 7     //下拉后执行的回调,强暴点就全部刷新
 8     callback: function(data) {
 9         location.reload();
10     }
11 });

但,这个总没有自动刷新来的舒服,于是我们在页面第一次加载的时候约定了这些事件:

 1 // 注册页面加载事件
 2  _.requestHybrid({
 3      tagname: 'onwebviewshow',
 4      callback: function () {
 5         
 6      }
 7  });
 8 // 注册页面影藏事件
 9 _.requestHybrid({
10     tagname: 'onwebviewhide',
11     callback: function () {
12         scope.loopFlag = false;
13         clearTimeout(scope.t);
14     }
15 });

在webview展示的时候触发,和在webview隐藏的时候触发,这样用户便可以做自动数据刷新了,但是局部刷新要做到什么程度就要看开发的时间安排了,技术好时间多自然体验好。

一些小特性

为了让H5的表现更加像native我们会约定一些小的特性,这种特性不适合通用架构,但是有了会更有亮点。

不要命就用swift

苹果官方出了swift,于是我们iOS团队好事者尝试了感觉不错,便迅速在团队内部推广了起来,而我们OC本身的体量本来就有10多万行代码量,我们都知道一个道理:

重构一时爽,项目火葬场

而重构过程中肯定又会遇到一些历史问题,或者一些第三方库,代码总会有一点尿不尽一点冗余,而不知道swift是官方有问题还是怎么回事,每次稍微多一些改动就需要编译一个多小时!!!!你没看错,是要编译一个多小时。

一次,我的小伙伴在打游戏,被我揪着说了两句,他说他在编译,我尼玛很不屑的骂了他,后面开始调iOS时,编译了2小时!!!从那以后看见他打游戏我一点脾气都没有了!!!

这种编译的感觉,就像吃坏了肚子,在厕所蹲了半天却什么也没拉出来一样!!!所以,不要命就全部换成swift吧。

如果有一定历史包袱的业务,或者新业务,最好不要全面使用新技术,不成熟的技术,如果有什么不可逆的坑,那么会连一点退路都没有了。

iOS静态资源缓存

Android有一个全局开关,控制静态资源部读取缓存,但是iOS中研究了好久,都没有找到这个开关,而他读取缓存又特别厉害,所以所有的请求资源在有增量包的情况下,最好加上时间戳或者md5

iOS静态资源缓存

Android有一个全局开关,控制静态资源部读取缓存,但是iOS中研究了好久,都没有找到这个开关,而他读取缓存又特别厉害,所以所有的请求资源在有增量包的情况下,最好加上时间戳或者md5

调试

一个Hybrid项目,要最大限度的符合前端的开发习惯,并且要提供可调试方案

我们之前说过直接将所有请求用native发出有一个最大的问题就是调试不方便,而正确的hybrid的开发应该是有70%以上的时间,纯业务开发者不需要关心native联调,当所有业务开发结束后再内嵌简单调一下即可。

因为调试时候需要读取测试环境资源,需要server端qa接口有个全局开关,关闭所有的增量读取

关于代理调试的方法已经很多人介绍过了,我这里不再多说,说一些native中的调试方案吧,其实很多人都知道。

native代理请求

在H5想要做某一块老的App业务,这个APP80%以上的业务都是Native做的,这类APP在接口方面就没有考虑过H5的感受,会要求很多信息如:

① 设备号

② 地理信息

③ 网络情况

④ 系统版本

有很多H5拿不到或者不容易拿到的公共信息,因为H5做的往往是一些比较小的业务,像什么个人主页之类的不重要的业务,Server端可能不愿意提供额外的接口适配,而使用额外的接口还有可能打破他们统一的某些规则;加之native对接口有自己的一套公共处理逻辑,所以便出了Native代理H5发请求的方案,公共参数会由Native自动带上。

 1 //暂时只关注hybrid调试,后续得关注三端匹配
 2 _.requestHybrid({
 3     tagname: 'apppost',
 4     param: {
 5         url: this.url,
 6         param: params
 7     },
 8 
 9     callback: function (data) {
10         scope.baseDataValidate(data, onComplete, onError);
11     }
12 });

这种方案有一些好处,接口统一,前端也不需要关注接口权限验证,但是这个会带给前端噩梦!

前端相对于native一个很大的优点,就是调试灵活,这种代理请求的方式,会限制请求只能在APP容器中生效,对前端调试造成了很大的痛苦

从真实的生产效果来说,也是很影响效率的,容易导致后续前端再也不愿意做那个APP的业务了,所以使用要慎重……

header-搜索

根据我们之前的约定,header是比较中规中矩的,但是由于产品和视觉强迫,我们实现了一个不一样的header,最开始虽然不太乐意,做完了后感觉还行……

图片 1

这块工作量主要是native的,我们只需要约定即可:

 1 this.header.set({
 2     view: this,
 3     //左边按钮
 4     left: [],
 5     //右边按钮
 6     right: [{
 7         tagname: 'cancel',
 8         value: '取消',
 9         callback: function () {
10             this.back();
11         }
12     }],
13     //searchbox定制
14     title: {
15         //特殊tagname
16         tagname: 'searchbox',
17         //标题,该数据为默认文本框文字
18         title: '取消',
19         //没有文字时候的占位提示
20         placeholder: '搜索医院、科室、医生和病症',
21         //是否默认进入页面获取焦点
22         focus: true,
23 
24         //文本框相关具有的回调事件
25         //data为一个json串
26         //editingdidbegin 为点击或者文本框获取焦点时候触发的事件
27         //editingdidend 为文本框失去焦点触发的事件
28         //editingchanged 为文本框数据改变时候触发的事件
29         type: '',
30         data: '' //真实数据
31     },
32     callback: function(data) {
33         var _data = JSON.parse(data);
34         if (_data.type == 'editingdidend' && this.keyword != $.trim(_data.data)) {
35             this.keyword = $.trim(_data.data);
36             this.reloadList();
37         }
38 
39     }
40 });

前言

接上文:(阅读本文前,建议阅读前两篇文章先)

浅谈Hybrid技术的设计与实现

浅谈Hybrid技术的设计与实现第二弹

根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多朋友就会觉得这个交互很简单嘛,其实并不难嘛,事实上单从Native与前端的交互来说就那点东西,真心没有太多可说的,但要真正做一个完整的Hybrid项目却不容易,要考虑的东西就比较多了,单从这个交互协议就有:

① URL Schema

② JavaScriptCore

两种,到底选择哪种方式,每种方式有什么优势,都是我们需要深度挖掘的,而除此之外,一个Hybrid项目还应该具有以下特性:

① 扩展性好——依靠好的约定

② 开发效率高——依赖公共业务

③ 交互体验好——需要解决各种兼容问题

我们在实际工作中如何落地一个Hybrid项目,如何推动一个项目的进行,这是本次我们要讨论的,也希望对各位有用。

文中是我个人的一些开发经验,希望对各位有用,也希望各位多多支持讨论,指出文中不足以及提出您的一些建议

设计类博客

http://www.cnblogs.com/yexiaochai/p/4921635.html
http://www.cnblogs.com/yexiaochai/p/5524783.html

iOS博客

http://www.cnblogs.com/nildog/p/5536081.html\#3440931

Android博客

https://home.cnblogs.com/u/vanezkw

代码地址:https://github.com/yexiaochai/Hybrid

因为IOS不能扫码下载了,大家自己下载下来用模拟器看吧,下面开始今天的内容。

总体概述在第一章,有兴趣大家去看

细节设计在第二章,有兴趣大家去看

本章主要为打补丁

交互约定

根据之前的学习,我们知道与Native交互有两种交互:

① URL Schema

② JavaScriptCore

而两种方式在使用上各有利弊,首先来说URL
Schema是比较稳定而成熟的,如果使用上文中提到的“ajax”交互方式,会比较灵活;而从设计的角度来说JavaScriptCore似乎更加合理,但是我们在实际使用中却发现,注入的时机得不到保障。

iOS同事在实体JavaScriptCore注入时,我们的原意是在webview载入前就注入所有的Native能力,而实际情况是页面js已经执行完了才被注入,这里会导致Hybrid交互失效,如果你看到某个Hybrid平台,突然header显示不正确了,就可能是这个问题导致,所以JavaScriptCore就被我们弃用了。

JavaScriptCore可能导致的问题:
① 注入时机不唯一(也许是BUG)
② 刷新页面的时候,JavaScriptCore的注入在不同机型表现不一致,有些就根本不注入了,所以全部hybrid交互失效

如果非要使用JavaScriptCore,为了解决这一问题,我们做了一个兼容,用URL
Schema的方式,在页面逻辑载入之初执行一个命令,将native的一些方式重新载入,比如:

1 _.requestHybrid({
2     tagname: 'injection'
3 });

这个能解决一些问题,但是有些初始化就马上要用到的方法可能就无力了,比如:

① 想要获取native给予的地理信息

② 想要获取native给予的用户信息(直接以变量的方式获取)

作为生产来讲,我们还是求稳,所以最终选择了URL Schema。

明白了基本的边界问题,选取了底层的交互方式,就可以开始进行初步的Hybrid设计了,但是这离一个可用于生产,可离落地的Hybrid方案还比较远。

正确读取

这里可能有点杞人忧天,因为Native程序不是自己手把手开发的,总是担心APP在正在拉取增量包时,或者正在解压时,读取了静态文件,这样会不会读取错误呢,后面想了想,便继续采用了之前的md5打包的方式,将落地的html中需要的文件打包为md5引用,如果落地页下载下来后,读不到本地文件就自己会去拉取线上资源咯。 

回退更新

我们在hybrid中的跳转,事实上每次都是新开一个webview,当A->B的时候,事实上A只是被隐藏了,当B点击返回的时候,便直接将A展示了出来,而A不会做任何更新,对前端来说是无感知的。

事实上,这个是一种优化,为了解决这种问题我们做了一个下拉刷新的特性:

 1 _.requestHybrid({
 2     tagname: 'headerrefresh',
 3     param: {
 4         //下拉时候展示的文案
 5         title: '123'
 6     },
 7     //下拉后执行的回调,强暴点就全部刷新
 8     callback: function(data) {
 9         location.reload();
10     }
11 });

但,这个总没有自动刷新来的舒服,于是我们在页面第一次加载的时候约定了这些事件:

 1 // 注册页面加载事件
 2  _.requestHybrid({
 3      tagname: 'onwebviewshow',
 4      callback: function () {
 5         
 6      }
 7  });
 8 // 注册页面影藏事件
 9 _.requestHybrid({
10     tagname: 'onwebviewhide',
11     callback: function () {
12         scope.loopFlag = false;
13         clearTimeout(scope.t);
14     }
15 });

在webview展示的时候触发,和在webview隐藏的时候触发,这样用户便可以做自动数据刷新了,但是局部刷新要做到什么程度就要看开发的时间安排了,技术好时间多自然体验好。

落地项目

真实落地的业务为医联通,有兴趣的朋友试试:

图片 2

图片 3

native代理请求

在H5想要做某一块老的App业务,这个APP80%以上的业务都是Native做的,这类APP在接口方面就没有考虑过H5的感受,会要求很多信息如:

① 设备号

② 地理信息

③ 网络情况

④ 系统版本

有很多H5拿不到或者不容易拿到的公共信息,因为H5做的往往是一些比较小的业务,像什么个人主页之类的不重要的业务,Server端可能不愿意提供额外的接口适配,而使用额外的接口还有可能打破他们统一的某些规则;加之native对接口有自己的一套公共处理逻辑,所以便出了Native代理H5发请求的方案,公共参数会由Native自动带上。

 1 //暂时只关注hybrid调试,后续得关注三端匹配
 2 _.requestHybrid({
 3     tagname: 'apppost',
 4     param: {
 5         url: this.url,
 6         param: params
 7     },
 8 
 9     callback: function (data) {
10         scope.baseDataValidate(data, onComplete, onError);
11     }
12 });

这种方案有一些好处,接口统一,前端也不需要关注接口权限验证,但是这个会带给前端噩梦!

前端相对于native一个很大的优点,就是调试灵活,这种代理请求的方式,会限制请求只能在APP容器中生效,对前端调试造成了很大的痛苦

从真实的生产效果来说,也是很影响效率的,容易导致后续前端再也不愿意做那个APP的业务了,所以使用要慎重……

边界问题

在我们使用Hybrid技术前要注意一个边界问题,什么项目适合Hybrid什么项目不适合,这个要搞清楚,适合Hybrid的项目为:

① 有60%以上的业务为H5

② 对更新(开发效率)有一定要求的APP

不适合使用Hybrid技术的项目有以下特点:

① 只有20%不到的业务使用H5做

② 交互效果要求较高(动画多)

任何技术都有适用的场景,千万不要妄想推翻已有APP的业务用H5去替代,最后会证明那是自讨苦吃,当然如果仅仅想在APP里面嵌入新的实验性业务,这个是没问题的。

Android webview兼容

Android webview的表现不佳,闪屏等问题比较多,遇到的几个问题有:


使用hybrid命令(比如跳转),如果点击快了的话,Android因为响应慢要开两个新页面,需要对连续点击做冻结


4.4以下低版本不能捕获js回调,意思是Android拿不到js的返回值,一些特殊的功能就做不了,比如back容错

③ ……

header-搜索

根据我们之前的约定,header是比较中规中矩的,但是由于产品和视觉强迫,我们实现了一个不一样的header,最开始虽然不太乐意,做完了后感觉还行……

图片 4

这块工作量主要是native的,我们只需要约定即可:

 1 this.header.set({
 2     view: this,
 3     //左边按钮
 4     left: [],
 5     //右边按钮
 6     right: [{
 7         tagname: 'cancel',
 8         value: '取消',
 9         callback: function () {
10             this.back();
11         }
12     }],
13     //searchbox定制
14     title: {
15         //特殊tagname
16         tagname: 'searchbox',
17         //标题,该数据为默认文本框文字
18         title: '取消',
19         //没有文字时候的占位提示
20         placeholder: '搜索医院、科室、医生和病症',
21         //是否默认进入页面获取焦点
22         focus: true,
23 
24         //文本框相关具有的回调事件
25         //data为一个json串
26         //editingdidbegin 为点击或者文本框获取焦点时候触发的事件
27         //editingdidend 为文本框失去焦点触发的事件
28         //editingchanged 为文本框数据改变时候触发的事件
29         type: '',
30         data: '' //真实数据
31     },
32     callback: function(data) {
33         var _data = JSON.parse(data);
34         if (_data.type == 'editingdidend' && this.keyword != $.trim(_data.data)) {
35             this.keyword = $.trim(_data.data);
36             this.reloadList();
37         }
38 
39     }
40 });

更新率

我们有时候想要的是一旦增量包发布,用户拿着手机就马上能看到最新的内容了,而这样需要app调用增量包的频率增高,所以我们是设置每30分钟检查一次更新。

推动感悟

从项目调研到项目落地再到最近一些的优化,已经花了三个月时间了,要做好一件事是不容易的,而且我们这个还涉及到持续优化,和配套业务比如:

① passport

② 钱包业务

③ 反馈业务

…..

等同步制作,很多工作的意义,或者作用,是非技术同事看不到的,但是如果我们不坚持做下去,迫于业务压力或者自我松懈放纵,那么就什么也没有了,我们要推动一件事情,不可能一站出来就说,嘿,小样,我们这个不错,你拿去用吧,这样人家会猜疑你的,我们一定是要先做一定demo让人有一定初步印象,再强制或者偷偷再某一个生产业务试用,一方面将技术依赖弄进去,一方面要告诉其他同事,看看嘛,也没有引起多大问题嘛,呵呵。

做事难,推动难,难在坚持,难在携手共进,这里面是需要信念的,在此尤其感谢团队3个伙伴的无私付出(杨杨、文文、文文)。

后续,我们在持续推动hybrid建设的同时,会尝试React
Native,找寻更好的更适合自己的解决方案。

微博求粉

最后,我的微博粉丝极其少,如果您觉得这篇博客对您哪怕有一丝丝的帮助,微博求粉博客求赞!!!

图片 5

http://www.bkjia.com/HTML5/1167532.htmlwww.bkjia.comtruehttp://www.bkjia.com/HTML5/1167532.htmlTechArticle浅谈Hybrid技术的设计与实现第三弹——落地篇,浅谈hybrid技术落地
前言 接上文:(阅读本文前,建议阅读前两篇文章先)
浅谈Hybrid技术的…

落地项目

真实落地的业务为医联通,有兴趣的朋友试试:

图片 6

图片 7

账号体系

一般来说,一个公司的账号体系健壮灵活程度会很大程度反映出这个研发团队的整体实力:

① 统一的鉴权认证

② 短信服务图形验证码的处理

③ 子系统的权限设计、公共的用户信息导出

④ 第三方接入方案

⑤ 接入文档输出

⑥ ……

这个技术方案,有没有是一回事(说明没思维),有几套是一回事(说明比较乱,技术不统一),对外的一套做到了什么程度又是一回事,当然这个不是我们讨论的重点,而账号体系也是Hybrid设计中不可或缺的一环。

账号体系涉及了接口权限控制、资源访问控制,现在有一种方案是,前端代码不做接口鉴权,账号一块的工作全部放到native端。

结语

希望此文能对准备接触Hybrid技术的朋友提供一些帮助,关于Hybrid的系列这里是最后一篇实战类文章介绍,这里是demo期间的一些效果图,后续git库的代码会再做整理:

 图片 8

图片 9

图片 10

交互约定

根据之前的学习,我们知道与Native交互有两种交互:

① URL Schema

② JavaScriptCore

而两种方式在使用上各有利弊,首先来说URL
Schema是比较稳定而成熟的,如果使用上文中提到的“ajax”交互方式,会比较灵活;而从设计的角度来说JavaScriptCore似乎更加合理,但是我们在实际使用中却发现,注入的时机得不到保障。

iOS同事在实体JavaScriptCore注入时,我们的原意是在webview载入前就注入所有的Native能力,而实际情况是页面js已经执行完了才被注入,这里会导致Hybrid交互失效,如果你看到某个Hybrid平台,突然header显示不正确了,就可能是这个问题导致,所以JavaScriptCore就被我们弃用了。

JavaScriptCore可能导致的问题:
① 注入时机不唯一(也许是BUG)
② 刷新页面的时候,JavaScriptCore的注入在不同机型表现不一致,有些就根本不注入了,所以全部hybrid交互失效

如果非要使用JavaScriptCore,为了解决这一问题,我们做了一个兼容,用URL
Schema的方式,在页面逻辑载入之初执行一个命令,将native的一些方式重新载入,比如:

1 _.requestHybrid({
2     tagname: 'injection'
3 });

这个能解决一些问题,但是有些初始化就马上要用到的方法可能就无力了,比如:

① 想要获取native给予的地理信息

② 想要获取native给予的用户信息(直接以变量的方式获取)

作为生产来讲,我们还是求稳,所以最终选择了URL Schema。

明白了基本的边界问题,选取了底层的交互方式,就可以开始进行初步的Hybrid设计了,但是这离一个可用于生产,可离落地的Hybrid方案还比较远。

相关文章