前端解读Webview
作为盛行已久的开发方式,Hybrid的相关介绍已经是相当普遍了。不过看到博客园里基本上都是从android或者ios的角度来讲解的,对于h5的前端来说看起来只能是一直半解。感觉有必要从前端的角度来理解和解读一下Hybrid相关内容。作为移动开发技术中不可或缺的一项,Hybrid 凭借其特有的优势牢牢的占据了一席之地。这里就不展开讨论讨论Hybrid的优劣了(想了解请查看http://www.cnblogs.com/yexiaochai/p/4921635.html)
html作为一种解释性语言,需要运行于解释器之上。我们常用的的pc端浏览器就是其一。作为移动端的一种混合开发的模式,Hybrid是如何解决这一问题的呢。这就引出了webview这一概念。hybride中的h5依托于webview容器来(对应于ios和安卓,应该有不同实现,这里就不是前端可以细说的了)解释运行。下面就看一下webview相关的部分。
一、webview的概念:
先放一段基本定义:A View that displays web pages. This class is the basis upon which you can roll your own web browser or simply display some online content within your Activity. It uses the WebKit rendering engine to display web pages and includes methods to navigate forward and backward through a history, zoom in and out, perform text searches and more.
自己的理解:webview用来展示网页的view组件,该组件是你运行自己的浏览器或者在你的线程中展示线上内容的基础。使用webkit渲染引擎来展示,并且支持前进后退等基于浏览历史,放大缩小,等更多功能。
简单来说WebView是手机中内置了一款高性能 webkit 内核浏览器,在 SDK 中封装的一个组件。不给过没有提供地址栏和导航栏,只是单纯的展示一个网页界面。
作为hybrid中的webview,相比较于native中原生组件,给人最直观的印象可能就是慢,不给过为什么这么慢呢,当然影响因素是很多的,除去一些外部因素。与webview自身的初始化和加载过程也是分不开的 ,下面来看一下webview的初始化过程
二、webview初始化
当App首次打开时,默认是并不初始化浏览器内核的;只有当创建WebView实例的时候,才会创建WebView的基础框架。所以与浏览器不同,App中打开WebView的第一步并不是建立连接,而是启动浏览器内核。
在浏览器中,我们输入地址时(甚至在之前),浏览器就可以开始加载页面。
在客户端中,客户端需要先花费时间初始化WebView完成后,才开始加载。
而这段时间,由于WebView还不存在,所有后续的过程是完全阻塞的。简单对比下两个的渲染过程:
浏览器:

webview:

可以看出在webview初始化之前,后面的步骤根本无从走起,耗时当然变长了。并且每次打开webview都要走这个过程。
三、Webview优化
从上面可以看出来webview相对浏览器来说,影响点在于webview的初始化并且阻塞后面action的这个过程,其实说来也简单(我只是说概念上,native的东西对我来说还是很难的)对应问题的两种表现形式,对应有两个方向上的优化。
3.1、减少webview初始化的消耗:
鉴于每次打开都要进行初始化webview组件的这种场景,很自然的对应起来一种设计模式即单例模式,既然每次都要走相同步骤完全可以实例化一个全局对象,从而免去其他过程的消耗。当然客户端的同学们也是这样做的: 初始完全可以建一个全局,隐藏的webview。以供使用。省去了每次的初始化过程。
不过这样的缺点也是有的,就看如何取舍了:
1、内存消耗:毕竟这货一直存在
2、页面间的跳转:毕竟只有一个webview实例,每次不同的加载需要处理的情况就比较多了。
3.2、针对阻塞的过程
每次的阻塞加载过程等待时间消耗也是很大的,就看能不能将串行的过程并行化。不过对于webview来说只能是这个样子,不过我们需要跳出仅仅局限于webview的视线,webview仅仅是移动系统的一个组件,统计存在其他组件,网络请求的过程完全可以交给native来做,也正如native一直在做的一样,完全是可以处理该过程的。例如后端同学经常要开发的mapi,就是针对native的接口。
四、webview与native的交互
上面提到native可以并行执行网络请求,以加快webview的呈现时间。又一个问题出现了,webview如何调用native接口去请求数据并获取native拿到的数据呢。除此之外还涉及到调用底层api等需求都需要借助native实现,问题的核心就是两者的交互如何实现,作为两者之间的沟通桥梁,jsbridge就应运而生了。
所谓交互无外乎两大块:一是h5调用native,另一个是native调用h5。
一、Native调用JS:
原生调用h5比较简单,可以直接调用。毕竟这里存在一个宿主的关系,脱离了webview,js就没有生命力了,而native其他功能是在webview外部的。所以反过来不能直接调用。
例如有如下代码:
<script type="text/javascript">
function myFunc() {
return "Text from web"
}
</script>
ios可以直接通过webview的属性调用(前端只能从方法名来看了,将js代码当做字符串读出来再解析)
NSString * result = [self.webView stringByEvaluatingJavaScriptFromString:@"myFunc()"];
2.H5网页的JS调用Native
本质还是用uiwebview的代理方法进行字段拦截(判断url的scheme),实现js间接调用native的method。
android可以直接给网页中js函数注入一个原生代码接口。
//相当于添加一个js回调接口可以直接通过window全局对象调用对应接口了:
mWebView.addJavascriptInterface(this, "native");
<button onClick="window.native.actionFromJs()">点击调用Native代码</button>
ios说起来也是注入只不过没有android那么方便。
在 webView 的 delegate 的 - (void)webViewDidFinishLoad:(UIWebView *)webView 里用下边的方式注入 JavaScript
NSString *js = @"(function() {\
window.JSBridge = {};\
window.JSBridge.callFunction = function(functionName, args){\
var url = \"bridge-js://invoke?\";\
var callInfo = {};\
callInfo.functionname = functionName;\
if (args)\
{\
callInfo.args = args;\
}\
url += JSON.stringify(callInfo);\
var rootElm = document.documentElement;\
var iFrame = document.createElement(\"IFRAME\");\
iFrame.setAttribute(\"src\",url);\
rootElm.appendChild(iFrame);\
iFrame.parentNode.removeChild(iFrame);\
};\
return true;\
})();";
[webView stringByEvaluatingJavaScriptFromString:js];
以前端的角度来看这段代码,是在 window 里创建一个叫 JSBridge 的对象,然后在里边定义一个方法 callFunction,
这个方法的作用是把两个参数打包为 JSON 字符串,然后附带到我们自定义的 URL bridge-js://invoke? 后边,
最后用 IFRAME 的方式来加载这个 URL当加载 IFRAME 的时候,就会调用 webView 的 delegate 的
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
(即特定方法来处理)方法。对url进行处理,把以约定字符开头的url后面的json解析出来,执行对应方法。
至此webview与native的交互即jsbridge的实现从前端的角度也大概就是这样子结束了,关于上面的客户端代码可以自行研究,不给过前端来看也是不太难看懂。以上就是我对webview的理解了,欢迎大家相互交流共同进步。
参考文章:WebView性能、体验分析与优化
前端解读Webview的更多相关文章
- 前端解读控制反转(IOC)
前言 随着前端承担的职责越来越重,前端应用向着复杂化.规模化的方向发展.大型项目模块化是一种趋势,不可避免模块之间要相互依赖,此外还有很多第三方包.这样的话如何去管理这些繁杂的文件,是一个不可避免的话 ...
- 前端解读面向切面编程(AOP)
前言 面向对象(OOP)作为经典的设计范式,对于我们来说可谓无人不知,还记得我们入行起始时那句经典的总结吗-万事万物皆对象. 是的,基于OOP思想封装.继承.多态的特点,我们会自然而然的遵循模块化.组 ...
- 谈一谈前端多容器(多webview平台)处理方案
文中是我个人的一些开发经验,希望对各位有用,也希望各位多多支持讨论,指出文中不足以及提出您的一些建议. 双容器 得益于近几年移动端的发展,前端早已今非昔比,从大型框架来说angularJS.react ...
- Android launchMode SingleTask newIntent 的问题
前置条件 项目中,采用 MainActivity + 3个 fragment 的模式作为主要框架.MainActivity 使用 singleTask 模式启动.Fragment 采用 show/hi ...
- CORS跨域模型浅析及常见理解误区分析
CORS跨域资源共享是前后端跨域十分常用的一种方案,主要依赖Access-Control-Allow(ACA)系列header来实现一种协商性的跨域交互. 基本模型 其中的具体流程大致可以分为以下几步 ...
- Mustache.js前端模板引擎源码解读
mustache是一个很轻的前端模板引擎,因为之前接手的项目用了这个模板引擎,自己就也继续用了一会觉得还不错,最近项目相对没那么忙,于是就抽了点时间看了一下这个的源码.源码很少,也就只有六百多行,所以 ...
- 前端webview开发中遇到的一些问题及其解决方法
最近做了一个webview中的兑换页面,本来以为很简单,想不到遇到了远远超出预期数量的BUG,记下来,以备后患. 1 inline-block元素折行 BUG描述:现在我有三个DIV,要在一列等宽排列 ...
- 代码解读 | VINS 视觉前端
本文作者是计算机视觉life公众号成员蔡量力,由于格式问题部分内容显示可能有问题,更好的阅读体验,请查看原文链接:代码解读 | VINS 视觉前端 vins前端概述 在搞清楚VINS前端之前,首先要搞 ...
- 葡萄城首席架构师:前端开发与Web表格控件技术解读
讲师:Issam Elbaytam,葡萄城集团全球首席架构师(Chief Software Architect of GrapeCity Global).曾任 Data Dynamics.Inc 创始 ...
随机推荐
- [C#] BarcodeLib -- 一个精简而不失优雅的条形码生成库
BarcodeLib -- 一个精简而不失优雅的条形码生成库 引言 在百度进行“C# 条形码”等类似关键字搜索的时候,基本上是使用 ZXing 类库进行条形码的生成.今天我所介绍的是另一款类库 Bar ...
- JVM与对象初始化
一个对象从无到有的过程 A a = new A() 1.JVM遇到new指令就会去堆内存分配一块内存空间,内存的大小在编译期间就可以确定 2.接着调用A的构造函数,这里构造的时候会沿着继承树逆流而上, ...
- 腾讯云万象优图每个账户提供50G的图片存储(支持黄图检测)
文章由GIT博客迁移过来 程序下载地址(源码也在):点我下载 设计说明 10月20号晚上,准备写这么一个程序. 腾讯云万象优图每个账户提供50G的图片存储(支持黄图检测) 可以在截图之后,直接点击上传 ...
- Mac上面Mov转gif
尝试了很多方法,后来发现这个网站转换的结果最好, http://ezgif.com/video-to-gif/
- wiringPi安装
wiringPi安装 更新软件,输入以下指令: sudo apt-get update sudo apt-get upgrade 通过GIT获得wiringPi的源代码 git c ...
- 关于QT中的音频通信问题
今天给大家讲说一个新的东西,使用QT实现音频通信的功能,挺起来是不是很高大上啊,哈哈,实际上我们只是使用一些接口做一些简单的工作而已,并不是让你写一个传输协议和采集音频信息,好了,那我们就来说一说关于 ...
- 使用ConcurrentDictionary替代Hashtable对多线程的对象缓存处理
在之前一段时间里面,我的基类多数使用lock和Hashtable组合实现多线程内缓存的冲突处理,不过有时候使用这两个搭配并不尽如人意,偶尔还是出现了集合已经加入的异常,对代码做多方的处理后依然如故,最 ...
- js添加多个样式属性cssText
document.getElementById("box").style.cssText += ";color:red;font-size:20px"; 代码分 ...
- Promise实现多图预加载
Promise正如它的中文意思“承诺”一样,保存着未来会发生事件(一般为异步操作).Promise避免了“回调地狱”,写法更加接近同步操作.说到同步,我更加喜欢async.await,它们书写更贴近同 ...
- Dubbo源码分析系列---扩展点加载
扩展点配置: 约定: 在扩展类的jar包内,放置扩展点配置文件:META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔.(摘自dubbo文档) 示例: ...