使用Cordova来解决HTML5制作的WebView手机不兼容的问题

来源:互联网 发布:淘宝解绑不了支付宝 编辑:程序博客网 时间:2024/05/01 18:56

一:Android 4.0WebView分析

这里写图片描述

(1)WebView API

主要提供给我们应用程序的接口,为了兼容向下版本,Android在高版本中也是对一层的API进行支持,

(2)Android WebView Framework

Android Framework:Android WebView是个特殊控件实现的支持需要Framework的代码主要在./frameworks/base/core/java/android/webkit目录下,在Android 4.0实现主要是在WebViewCore.java,BrowserFrame.java等文件。

(3)Android JNI

Android JNI:需要有Native代码支持,因此需要有JNI层实现,Android WebView 4.0的JNI层实现WebView相关代码在./external/webkit/Source/WebKit/android/jni/目录下,这一层起到承上启下的作用,链接Framework层以及WebKit层的桥梁,比如相关的一些实现在WebviewCore.cpp,WebCoreFrameBridge.cpp等。

(4)WebKit

WebKit: WebKit内核,其核心主要是解析W3C标准以及渲染排版网页,他是一个跨平台的内核引擎,那么需要支持各个平台,需要我们的平台实现层,在Android 4.0系统这一部分相关代码主要在./external/webkit/Source/WebKit/android/WebCoreSupport/目录下,比如FrameLoaderClientAndroid.cpp,ChromeClientAndroid.cpp,这一层负责WebCore与系统平台的桥接,具体在不同平台会有不同的实现。

二:Android 4.1–4.3 WebView的结构

Android 4.1–4.3版本WebView内核实现还是基于WebKit,但在WebView的Framework层发生了变化,引入了工厂模式,目地是为了将内核与上层API接口分离开来,分离的意义不仅仅是抽象接口,更重要的是将来能替换内核部分的实现。 在4.1–4.3这一系列版本native结构基本与4.0版本相同,下图呈现新的变化:
这里写图片描述

三:Android 4.4 WebView的结构

在Android 4.4系统上 Google已经将系统默认的Webkit内核替换成自己的开源项目chromium,通过之前的版本分析,我们可以看到Android 对WebView的Framework 结构进行调整使其更抽象,更重要的目的还是集成自己的开源chromium。下面我们来看看WebView的结构发生了什么样的变化:
这里写图片描述
在Android 4.0上已经默认开启硬件加速,因此WebView的渲染默认是基于硬件渲染的,通过本人分析其在WebView被隐藏的那一帧是采用软件渲染,目的是减少硬件占用,让其他UI能及时的响应。
为了将chromium项目集成到Android 中,chromium项目抽象出Android webview这一层,之前的接口抽离这时候已经变得很明显,Android Webview基于chromium content API这一层,第三方浏览器厂商也可以采用这种方式,目前所了解的厂商有Opera使用这种方式。Android 4.4WebView的渲染核心目前也没有发生太大变化,还是基于WebView的Canvas,将Chromium composit 结构绘制到WebView Canvas上。接入chromium内核,WebView浏览性能大幅度提升,但是和chrome for Android还是有些不同,主要体现在一下几点:
1. chrome浏览器是多进程架构,Chromium for Android Webview 是单进程架构。
2. chrome浏览器 内存占用比 Android WebView大的多。
3. chrome支持更多的HTML5 feature。

四:Android 5.0 WebView

Lollipop版本中WebView的内核实现采用Chromium 37版本,这个版本带来更多的安全性和稳定性。这个版本解决Android 4.4版本网页当中请求访问打开本地文件选择器问题,引入新的回调接口,onShowFileChooser方法,需要此功能的可以在5.0上接上这个回调接口,并实现功能。另外这个版本提供安全许可给用户选择,当网页需要访问特殊资源时,会通知我们的应用程序,请求允许,回调接口为onPermissionRequest。之前我们也提到这个版本使得WebView默认支持WebAudio,WebGL,WebRTC等标准。
另外Google Android 还将webview做为一个能动态更新的app,能不更新Android版本情况下,更新WebView内核。Android 5.0 Webview默认提供减少内存占用支持,并且智能选择需要绘制的HTML document部门来提供性能。 当然开发者可以在自己应用程序需要时关闭这个选项(enableSlowWholeDocumentDraw)。

五:使用Cordova

(1)Cordova概述

什么是Cordova?
*一个移动开发的框架
*将HTML,CSS,JS封装为原生App(Hybrid)(可以让一个前端工程师拥有研发Android App的能力)
*来自Adobe的PhoneGap产品,是当下很多Web开发框架的底层源码

(2)下载和安装Cordova框架

下载Cordova框架之前必须要先下Node.js,(注:Node.js是一个Javascript运行环境(runtime)。实际上它是对Google V8引擎进行了封装。V8引 擎执行Javascript的速度非常快,性能非常好。Node.js对一些特殊用例进行了优化,提供了替代的API,使得V8在非浏览器环境下运行得更好。)
这里写图片描述
确认安装成功
这里写图片描述
在windows上安装Cordova
这里写图片描述
安装速度有点慢,还需要翻墙支持
下面的图表示安装成功
这里写图片描述

(3)安装ANT

输入网址:http://ant.apache.org/
在视图左边找到Download–Binary Distributions
这里写图片描述
选择对应的Zip文件进行下载
这里写图片描述
将解压的zip文件的bin目录添加到环境变量中
这里写图片描述

(4)Cordova的部分指令

在E盘创建一个”Cordova”文件夹
进入到E盘
这里写图片描述
进入之前创建的”Cordova”目录
这里写图片描述
创建自己的第一个项目
这里写图片描述
其中
hello 表示项目所在的文件夹
com.aqiu.sample 表示项目的包名
HelloWorld 表示入口类
进入到之前创建的hello文件夹
这里写图片描述
在hello项目文件夹中,为其搭建Android平台的环境
这里写图片描述
此时的platform–android中已经自动构建了可以在AS运行的代码块,使用AS打开即可
这里写图片描述

(5)项目文件中的文件目录

这里写图片描述

hooks:
存放的是我们自定义的扩展功能
这里写图片描述
platforms:是doc引入的运行平台,我们运行的是Android环境
www:表示的是HTML5的配置文件
注:这个地方将自己的HTML+CSS文件替换掉默认的文件,这样就可以显示自己写的HTML布局了
这里写图片描述
config.xml:配置文件,里面有起始页HelloWorld和项目名称”index.html”基础信息
这里写图片描述

六.Android Studio的集成Cordova项目

1.build构建成功的代码块

这里写图片描述

2.使用Cordova需要注意的问题

(1)在MainActiity中,没有WebView的布局,该布局在依赖库CordovaLib中通过代码构建
(2)在Activity的onCreate方法中,loadUrl(launchUrl)调用之后,CordovaLib中的WebView对象appView才有值,因此使用appView时,必须写在loadUrl的后面
(3)在Cordova中,appView是不能直接调用addJavascriptInterface()方法的,按照要求,在调用该方法之前,
需要加上一行代码:
WebView Wv = (WebView) appView.getEngine().getView();
(4)AS资源文件中,均加上了www文件夹,所以在使用路径下的图片时,在资源路径下要添加/www/路径
这里写图片描述

七:Cordova事件分发之返回键的使用

(1)在Cordova的CordovaWebViewImpl中,关于返回键的事件分发代码

着重要强调的是
engine.canGoBack():其作用是拦截Android原生的BackButton按钮,js无上一级时返回false,存在上一级返回true
engine.goBack:其作用的是使Android返回键在js页面跳转中有效,
也就是说,如果不需要进行js页面跳转,那么直接注释掉canGoBack()和goBack()方法即可

@Overridepublic Boolean onDispatchKeyEvent(KeyEvent event) {    int keyCode = event.getKeyCode();    boolean isBackButton = keyCode == KeyEvent.KEYCODE_BACK;    if (event.getAction() == KeyEvent.ACTION_DOWN) {        if (isBackButton && mCustomView != null) {//点击了返回键,并且js的历史栈中还有数据,那么页面时返回上一级            System.out.println("执行第一步!");            return true;//返回true表示拦截,即原生Android的返回不能调用本地的方法,而是调用js的代码        } else if (boundKeyCodes.contains(keyCode)) {            return true;        } else if (isBackButton) {            return engine.canGoBack();//作用是拦截Android原生的BackButton按钮        }    } else if (event.getAction() == KeyEvent.ACTION_UP) {        if (isBackButton && mCustomView != null) {            hideCustomView();            return true;        } else if (boundKeyCodes.contains(keyCode)) {            String eventName = null;            switch (keyCode) {                case KeyEvent.KEYCODE_VOLUME_DOWN:                    eventName = "volumedownbutton";                    break;                case KeyEvent.KEYCODE_VOLUME_UP:                    eventName = "volumeupbutton";                    break;                case KeyEvent.KEYCODE_SEARCH:                    eventName = "searchbutton";                    break;                case KeyEvent.KEYCODE_MENU:                    eventName = "menubutton";                    break;                case KeyEvent.KEYCODE_BACK:                    eventName = "backbutton";                    break;            }            if (eventName != null) {                sendJavascriptEvent(eventName);                return true;            }        } else if (isBackButton) {            return engine.goBack();        }    }    return null;}

(2)在跳转下一个js页面时,清空之前栈内容

本地Java代码:

@JavascriptInterfacepublic void clearHistory() {    wV.postDelayed(new Runnable() {        @Override        public void run() {            wV.clearHistory();        }    }, 1000);}

JavaScript跳转页面,并且调用方法

/** * 退出登录 * @returns */function logout(){   user = {};    window.js2java.clearHistory();    window.location.href="#login";}

当我们跳转到”login”界面时,”login”界面之前的页面历史清空

2 0