Hybrid开发原理分析和开发中常见问题
首先,我们先来罗列一下当前市面上,移动端的各种开发方法
1.Native App
纯原生的app开发模式,android(Java)或者ios(Swift,Oc)
优点:
有最好的性能,有最好的体验
缺点:
开发和发布的成本极高,两端需要不同的技术人员来维护,原生开发人员非常的稀缺
2.WebApp
移动端运行在浏览器上的网站,我们一般称之为H5应用,就是泛指我们经常开发的spa,map页面
语言:js,vue,react,angular等
优点:
1.开发和发布非常方便
2.用户看到的页面,会随着开发人员的发布实时更新
3.可以跨平台,因为H5应用的产出其实就是一个url,测试非常的方便,chrome safari f12
4.不存在多版本的问题,维护成本很低
缺点:
1.性能和体验一般
2.受限于浏览器,能做的事情并不是很多,需要兼容各种奇怪的浏览器
3.入口强依赖浏览器
3.React Navite App / Weex App / Uniapp
都是为了跨平台而生的,支持react/vue的语法
4.Flutter
闲鱼使用flutter开发。dart语言,跨平台支持的更好
然后是Hybrid基本介绍
h5+native 混合开发 = hybrid
app -> webview ->url === hybrid??
最大的特点是h5和native可以双向交互
例:通过微信JSSDK介绍Hybrid
h5经常分享在微信聊天/朋友圈
公众号文章 -> … ->分享给好友
授权 -> 是否同意授权xxxx ->头像昵称 ->手机号
分享,支付,位置。h5开发者只需要关注微信jssdk提供了哪些api即可,其他的事情都由jssdk和微信客户端来完成
Hybrid开发架构
hybrid最核心的部分,就是native和h5的双向通讯。通讯是完全依赖于webview容器
但是有两个问题
1.具体的通讯形式又是什么样子的呢?
2.webview凭什么可以支持起native和h5的双向通讯
双向通讯市面上目前有两种方式:
1.URL schema,客户端通过拦截webview中的请求来完成通讯
2.native向webview的js执行环境中,给window对象挂在api,以此来完成通讯
原理
在webview中发出的网络请求,都会被客户端给监听到
这就是URL Schema这种模式实现的最基本基石
定义自己的私有协议
h5里面可能有无数的请求,怎么判断哪个请求需要调用内置方法呢?
1.native可以定义自己的私有协议,例如hahah://
2.随后我们在webview中如果去调用native的一些端能力,就需要在请求前面拼上这个协议头,比如我们请求是http://gogoing,就要变成hahaa://+我们的请求
3.协议的名称是自定义的,没什么特别硬性的要求,只要和native协商好就可以
请求的发送
1.iframe的方式
…js
const doc = window.document
const body = doc.body
const iframe = doc.createElement('iframe')
iframe.style.display = 'none' //不显示出来
iframe.src = 'hahah://googing' //此时还没有开始请求
body.appendChild(iframe)
setTimeout(()=>{
body.removeChild(iframe)
})
客户端要考虑的还有安全方面,还会设置一些域名的白名单
2.locaiton.href(不适用于并行的请求 setLeft setRight)
客户端拦截协议请求
当拦截到的请求是约定好的,会解析参数,解析方法,进行相关的native操作
请求处理完成后的回调
webview请求本质上还是一个异步请求,我们需要有一个回调来告诉我们请求的结果
window.addEventListener和window.dispatchEvent这两个api
业务中:
…js
webview.setTitle({title:'哈哈哈哈'},(err,response)=>{
if(err){
console.error(err);
return;
}
//执行成功,执行业务逻辑
})
JSBridge中:
…js
const handleId = 1;
const eventName = `setTitle_${handlerId}`; //每一个eventName唯一
handleId++;
const event = new Event(eventName);
window.addEventListener(eventName,(res)=>{
(res.data.errcode){
//执行失败
return
}
//执行成功
}) ;
JsBridge.send();
event.data = {errcode:0 }
window.dispatchEvent(event)
注入API
上面方法是通过iframe来发送请求,参数很容易过长而被截断
1.h5向native传递信息
前提是:native已经向window变量注入了各种api,咱们已经可以直接调用它们了
比如window.QiukuWebview = {setTile : xxxx }
...js
window.QiukuWebview.setTitle(params)
2.准备接收native的回调
…js
window[‘setTitle_callback_1’] = (err code,response) =>{
}
有可能有的公司为了安全性,会对参数进行加密或者编码
3.native调用回调函数
native执行完之后,应该怎么告诉h5我执行完了呢?我应该调用哪个函数告诉h5呢?
…js
window.QiukuWebview.setTitle(params);
…js
const callbackName = 'setTitle_callback_1';
window.QiukuWebview.setTitle({
trigger:callbackName,
...params
})
window['setTitle_callback_1'] = (err code,response) =>{
}
为了保证callback的唯一性,一般会加入各种Date.now()+id
h5在app内的运行方式
1.app的webview直接加载一个h5链接
缺点:
没有太好的体验,除了能用一些native的能力之外,和普通浏览器打开h5没什么区别,因为加载的还是网络资源
优点:
灵活,易用
2.app内置h5资源
优点:
首屏加载速度特别快,体验接近原生
可以不依赖网络,离线运行
缺点:
会增大app的体积
需要多方合作区完成方案
但是要解决的最核心问题是:如何更新内置的h5资源
开发中的常见问题
1.ios webview中滑动不流畅
如果有一个滚动容器 scroll-container , overflow:scroll
加一个css属性即可
-webkit-overflow-scrolling:touch;//控制ios中的惯性滚动
2.滚动穿透
背景页面有滚动的时候,此时有个弹窗出现了,你的手指在弹窗上滑动,你的背景也会跟着滑动。
2.1 弹窗内无滚动,背景页面有滚动
直接在弹窗容器元素上加一个监听事件就可以了
…js
document.addEventListener('touchmove',function(e){
//阻止默认事件
e.preventDefault()
})
如果是vue写的,直接加一个 @touchmove.prevent
2.2 弹窗内有滚动,背景页面有滚动
要实现的是:
弹窗出现时,背景禁止滚动
弹窗隐藏时,背景恢复滚动
vue里面只适用于v-if,v-show不行
…js
const inserted = () =>{
//弹窗出现的行为
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop
document.body.style.cssText +=`position : fixed ; width:100%;top:-${scrollTop}px;`;
}
const unbind = () =>{
const body = document.body || document.documentElement
body.style.position = '';
const top = body.style.top;
document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top,10);
body.style.top = '';
}
export const vScroll = {
inserted,
unbind
}
然后注册
Vue.directive('scroll',vScroll)
比如在一个div元素上用的时候
div(v-scroll)
3.刘海屏幕的安全区域留白
设置viewport-fit cover
…html
<meta name="viewport" content="viewport-fit=cover">
默认有一个div
div{
position:fixed;
bottom:0;
//加这2个属性,记住顺序不要颠倒,兼容性问题
bottom:calc(constant(safe-area-inset-bottom)+0);
bottom:calc(env(safe-area-inset-bottom)+0);
}
如果bottom设置一个变量的话
@bottom-height:1rem
div{
position:fixed;
bottom:@bottom-height;
//加这2个属性,记住顺序不要颠倒,兼容性问题
bottom:calc(constant(safe-area-inset-bottom)[email protected]);
bottom:calc(env(safe-area-inset-bottom)[email protected]);
}
推荐阅读
-
系统设计和开发中,方法论比技术更重要--兼谈怎样做Java服务器的性能分析和调整
-
Django项目开发中cookies和session的常用操作分析
-
php进行支付宝开发中return_url和notify_url的区别分析
-
JSP servlet与ssh等框架相比,在互联网网站开发和企业级开发中的优劣势分析?
-
php进行支付宝开发中return_url和notify_url的区别分析_PHP
-
Android6.0开发中屏幕旋转原理与流程分析
-
php进行支付宝开发中return_url和notify_url的区别分析_PHP
-
Android开发知识(八):Android事件处理机制:事件分发、传递、拦截、处理机制的原理分析(中)
-
在开发中,如果编程语言(例如PHP)和SQL(例如MySQL)都能实现某个功能,我们是用编程语言实现还是SQL?还是具体问题具体分析?
-
在开发中,如果编程语言(例如PHP)和SQL(例如MySQL)都能实现某个功能,我们是用编程语言实现还是SQL?还是具体问题具体分析?