正如所说,我们会使用Native的功能一个很大的原因是为了防止js出错而导致app假死,而经过我们之前的设计,连back按钮的回调也是我们定义的,如果js报错的话,这个back的回调可能没注册上去也可能回调报错了,为了处理这个问题,我们这里需要一个约定:
对header的tagname为back的按钮做了特殊化,类似可能做特殊化的tagname是home、tel
① 如果back按钮没有设置回调则执行webview(浏览器)的history.back
② 如果history为1的话,默认执行退回上一页
③ 如果点击back的时候具有回调则执行回调(JavaScript回调,必须返回true)
④ 如果js回调返回true则Native流程结束,如果300ms没有返回或者返回不为true则跳转到大首页(这个根据业务而定,也可能回到上一页)
这样的话,就算js报错,或者回调报错,也可以保证APP不会陷入假死的情况。
请注意,这样只能避免用户进了某一个页面出不去的情况,并不是说页面没BUG!!! 如果这里发生了阻塞主流程的BUG,页面应该要有自动预警与在线更改机制,避免用户&订单流失
这里一旦具有回调但是依旧执行了Native回调的场景就一定是页面有问题,这个时候就应该打点上报日志,日志收集后马上短信轰炸业务开发人员,这个日志也是有一定要求的:我们希望错误日志定位到哪一个页面甚至哪一个方法出了问题,如果有具体操作路径就更好了,后面的比较难,第一条一定要做到。当错误定位到后,我们便需要快速解决问题,上线代码,这里涉及Hybrid在线更新一块的逻辑,我们后面再说。
数据请求事实上对H5来说,请求走Ajax是没有问题的,跨域等问题都有很多解决方案,真正让我们想用Native代理发出请求的是账号信息统一(后面又有Native走tcp的场景),请思考以下场景:
Native往往是可以持久化登录信息的,所以很多主流的Hybrid框架如果是直连(webview直接访问一个url)的话会直接将cookie信息注入给webview,这个时候业务就直接获取了登录态了,但总有业务可能会产生登出操作,然后换个账号登录进来,这个时候webview与Native的账号就不统一了,没有处理方案的话,这个时候用户就会懵逼了,觉得整个APP不可信!
有一种方案是可以绕过这个问题的,就是对登录登出“收口”(我们又提到收口一词了哦),限制业务开发登出必须使用APP系统提供的登录登出,因为一般大公司有统一的passport做鉴权,比如手机百度,就算你在webview中重新登录了,因为使用的是APP提供的登录登出,而其他频道应用与你皆是使用的passport鉴权,所以可以用这个方案,但是这个方案对于多数小公司可能是不可行的。
第一是很多小公司没那个意识去打造类似passport这种东西,这个也不是前端能推动的事情,就算你实现了整个passport机制,还得保证整个公司其它团队使用你的系统,如果有一个团队不买账就懵逼了。
没有统一的账号系统往往有历史包袱的因素,技术债需要及时还清
所以现在很多团队的现状是一个项目都会有自己的登陆注册(这个事实上很傻逼),频道之间登录态共享都没有做到,所以对登陆登出做收口便不适用了,但是因为Native是新业务,不存在历史包袱,APP一般又是战略性产品,前端做不到的事情,如果和APP挂钩,往往可以在某些方面完成类似的事情,就我们现在来说APP就有自己的一套鉴权机制,虽然不清楚他内部实现(后面需详细了解),但是每个业务接口对APP都是很友好的,所以请求直接走Native代理发出会是一个非常好的选择。
1 requestHybrid({ tagname: 'get', 4 param: { 5 url: 'http://api/demain.com', 6 param: {a: 1, b: 2} 7 }, 8 callback: function (data) { 9 } 10 });
解决了以上问题,事实上只需要Native端新释放一个接口即可,当然这里又会回到之前一个问题,post的参数问题,这个时候可能就需要配置为JavaScriptCore方式通信,或者将请求参数放在一个全局方法中等待Native调用获取。
业务开发中需要禁止出现登出操作,所有的登出都要走APP唯一页面的唯一登出按钮;如果APP本身未登陆,那么可以要求用户进入页面前先登陆,也可以在访问到具体需要登陆的接口时弹出登陆框让用户登陆了才能进行后续操作。
因为请求由native发出不会有跨域问题,考虑到安全性,这里会有一个域名白名单,只有白名单的请求才能发出去
NativeUI像我们前面说的Header组件与登陆框,事实上都算得上Native组件,只不过header是单纯的UI组件,登陆框算得上业务组件的,H5会用到NativeUI的场景不多,但是loading这个东西因为要降低页面白屏时间会经常用到。
一般来说在webview加载html时会有一段时间白屏时间,这个时候便需要Native的loading出场,在页面加载完成后需要在前端框架层将Native loading关闭。
1 var HybridUI = {}; 2 HybridUI.showLoading(); requestHybrid({ 5 tagname: 'showLoading' 6 }); 7 8 HybridUI.showToast({ 9 title: '111', hidesec: 3, callback: function () { } 14 }); requestHybrid({ 17 tagname: 'showToast', 18 param: { 19 title: '111', 20 hidesec: 3, 21 callback: function () { } 22 } 23 });
这一套UI组件皆需要与前端框架中的组件使用做到一致性,这种业务类组件不多说,这里说一个可能会遇到的问题:
NativeUI通信问题不可避免的,我们会遇到NativeUI组件与H5通信的问题,举个简单的例子,我们为了交互效果,新开了一Native的弹出层组件,大概这个样子:
大家这里不要把它当做单独的View,将它看做一个H5的弹出层,只不过这个弹出层是Native实现的,整个调用方式也许是这样的: