精华内容
下载资源
问答
  • Android 浏览器内核浅谈

    千次阅读 2017-08-19 16:47:34
    目前,移动设备浏览器上常用的内核有Webkit,Blink,Trident,Gecko等,其中iPhone和iPad等苹果iOS平台主要是WebKit,Android 4.4之前的android系统浏览器内核是WebKit,Android4.4系统浏览器切换到了Chromium(内核...

     目前,移动设备浏览器上常用的内核有Webkit,Blink,Trident,Gecko等,其中iPhone和iPad等苹果iOS平台主要是WebKit,Android 4.4之前的android系统浏览器内核是WebKit,Android4.4系统浏览器切换到了Chromium(内核是Webkit的分支Blink),Windows Phone 8系统浏览器内核是Trident。

     1.WebKit项目 

    (1)项目简介:WebKit项目是苹果公司在2005年发起的一个新的开源项目,是Safari浏览器的内核,是目前的主流浏览器渲染引擎。WebKit项目具有结构清晰、易于维护等优点,WebKit简单灵活和便于引入新移植的特性,使其迅速称为主流的渲染引擎。

     (2)WebKit架构   

    WebCore部分:包含了目前被各个浏览器所使用的WebKit共享部分,是加载和渲染网页的基础部分,具体包括HTML解释器、CSS解释器等。  

    JavaScriptCore引擎:是WebKit中的默认JavaScript引擎。在Google的Chromium项目中,它被替换为V8引擎。

    WebKit Ports部分:是WebKit红的非共享部分,属于WebKit被移植的模块。由于不同浏览器使得平台差异、依赖的第三方库和需求不同,从而导致多种WebKit版本。

    WebKit嵌入式接口:指在WebCore和javascript引擎之上的一层绑定和嵌入式编程接口,可以被各种浏览器调用。 

     2.Chromuim项目 

    (1)项目简介

      Chromuim项目是Google公司以苹果开源项目WebKit作为内核,创建的一个新的项目,该项目的目标是创建一个快速的、支持众多操作系统的浏览器。在Chromium项目基础上,Google发布了自己的浏览器产品Chrome。与使用WebKit作为内核的Safari浏览器不同,Chromium本身就是一个浏览器,而不是Chrome浏览器的内核,再未从WebKit项目分离之前,Chrome浏览器使用的是WebKit内核。2013年4月,Google宣布从Webkit复制出来并独立运作Blink项目,该项目也就是目前Android4.4及以上系统浏览器采用的内核。

     (2)Blink内核     

    Blink项目从WebKit分离出来后,其本身也是源于WebKit项目,只是Google将除Chromium浏览器需要之外的其他移植的代码都删除了,并且在Blink项目中加入了很多新的技术,部分技术如下: 实现跨进程的iframe。iframe允许网页中嵌入其他页面,为了解决潜在的安全问题,为iframe创建一个单独的沙箱进程。 重新整理和修改WebKit关于网络方面的架构和接口。

    将DOM树引入JavaScript引擎中。
    针对各种技术的性能优化,包括图形、JavaScript引擎、内存使用、编译的二进制文件大小等。

    (3)基于Blink引擎的Chromium浏览器结构 

      下图描述了Chromium的架构和主要模块,可知Blink只是其中的一个模块,和它并列的还有众多的Chromium模块,包括GPU/CommandBuffer(硬件加速架构)、V8 JavaScript引擎、沙箱模型、CC(Chromium合成器)、IPC、UI等。"Content模块"和"Content API(接口)"

      "Content模块"和"Content API"将下面的渲染机制、安全机制和插件机制等隐藏起来,提供一个接口层,是Chromium对渲染网页功能的抽象,被内部的Chromium浏览器、Content Shell调用,是用来渲染网页内容的模块。"Chromium浏览和"Content Shell"

     "Chromium浏览和"Content Shell"是构建在Content API之上的两个"浏览器",Chromium具有浏览器的完成功能。

    "Content Shell"是使用Content API包装的一层简单的"壳",用户可以使用Content模块来渲染和显示网页内容。Android WebView模块

      Android WebView模块是希望利用Chromiuim的实现来替换原来的Android系统默认的WebView. 

     3.浏览器内核 

    (1)内核介绍     

    在浏览器中,有一个最重要的模块,它主要的作用是将页面转变成可视化的图像结果,这就是浏览器内核,也被称为渲染引擎。所谓渲染,就是根据描述或者定义构建数学模型,通过模型生成图像的过程。浏览器的渲染引擎就是能够将HTML/CSS/JavaScript文本及其相应的资源文件转换成图像结果的模块。 

     (2)内核特征    

    一个渲染引擎主要包括HTML解释器、CSS解释器、布局和JavaScript引擎、绘图等。 HTML解释器:解释HTML文本的解释器,主要作用是将HTML文本解释成DOM(文档对象模型)树,DOM是一种文档的表示方法.

    CSS解释器:级联样式表的解释器,主要作用是为DOM中各个元素对象计算出样式信息,从而为计算最后网页的布局提供基础设施。
    布局:在DOM创建之后,WebKit需要将其中的元素对象同样式信息结合起来,计算他们的大小位置等布局信息,形成一个能够表示这所有信息的内部表示模型。
    JavaScript引擎:使用JavaScript代码可以修改网页的内容,也能修改CSS的信息,JS引擎能够解释JS代码并通过DOM接口和CSSOM接口来修改网页内容和样式信息,从而改变渲染的结果。
    绘图:使用图形库将布局计算后的各个网页的节点绘制成图形结果。
     
    展开全文
  • 使用浏览器访问这个地址,就可以查看当前浏览器内核信息。 包含内核的类型,内核的版本,以及主机操作系统的类型和版本。 可以查看PC端浏览器以及Android端浏览器的版本信息。 Chrome浏览器 IE浏览器 Edge...

    工具网址:https://ie.icoa.cn/

    使用浏览器访问这个地址,就可以查看当前浏览器内核信息。

    包含内核的类型,内核的版本,以及主机操作系统的类型和版本。

    可以查看PC端浏览器以及Android端浏览器的版本信息。

    Chrome浏览器

    IE浏览器

    Edge浏览器

    Android浏览器

    展开全文
  • 手机浏览器种类:UC浏览器,QQ浏览器,欧朋浏览器,百度...就像国内的手机操作系统都是基于Android修改的全球仅有四大浏览器内核目前全球仅有四个独立的浏览器内核,分别为微软IE的Trident、网景最初研发后卖给Mozil...

    手机浏览器种类:

    UC浏览器,QQ浏览器,欧朋浏览器,百度手机浏览器,360安全浏览器,谷歌浏览器,搜狗手机浏览器,猎豹浏览器,其他杂牌浏览器

    国内的UC和QQ,百度等手机浏览器都是根据Webkit修改过来的内核,国内尚无自主研发的内核,就像国内的手机操作系统都是基于Android修改的

    全球仅有四大浏览器内核

    目前全球仅有四个独立的浏览器内核,分别为微软IE的Trident、网景最初研发后卖给Mozilla基金会并演化成火狐的Gecko、KDE的开源内核Webkit以及Opera(欧朋)的Presto。其中,Presto是历史最悠久的内核。

    * 目前微软的Trident在移动终端上主要为WP7系统内置浏览器

    * Opera的Presto内核在所有联网设备上都使用,移动终端上主要为 Opera Mobile、OperaMini、欧朋浏览器以及欧朋HD Beta版

    * Webkit内核的适用范围则较为广泛,Android原生浏览器、苹果的Safari、谷歌的Chrome(Android4.0使用)都是基于Webkit开源内核开发的。

    ####实际情况出发:

    ######对于Android手机而言:

    使用率最高的就是Webkit内核,我们看到很多手机浏览器厂商都宣称有着自主内核,比如手机UC就号称采用了U3内核、而华为也经常标榜自己的天天浏览器采用了T9内核,事实上,他们都是基于开源内核Webkit进行二次开发的,并不是完全的自主内核。

    ######对于iPhone而言:

    由于系统封闭,不允许除系统自带浏览器内核以外的浏览器内核进入,因此各家浏览器的开发均为在Safari内核的基础上进行二次开发,优化功能和自制UI。比如海豚、遨游等浏览器就是直接采用系统自带浏览器的内核,这点从这几款浏览器的HTML5评分与系统自带浏览器评分结果完全一致就可以看出。

    四大浏览器内核优缺点

    1、 Trident([ˈtraɪdn:t]):因为在早期IE占有大量的市场份额,所以以前有很多网页是根据这个Trident的标准来编写的,但是实际上这个内核对真正的网页标准支持不是很好,同时存在许多安全Bug。

    2、 Gecko( [ˈgekoʊ]):优点就是功能强大、丰富,可以支持很多复杂网页效果和浏览器扩展接口,缺点是消耗很多的资源,比如内存。

    3、 Webkit:优点就是Webkit拥有清晰的源码结构、极快的渲染速度,缺点是对网页代码的兼容性较低,会使一些编写不标准的网页无法正确显示。

    4、 Presto:Presto内核被称为公认的浏览网页速度最快的内核,同时也是处理JS脚本最兼容的内核,能在Windows、Mac及Linux操作系统下完美运行。

    展开全文
  • Android 集成Chrome 浏览器内核 Crosswalk

    千次阅读 2020-02-21 15:19:28
    但实际上,由于 Android 的碎片化问题(大量存在不同的 Android 系统版本,并且各个厂商对内置应用进行定制化,有可能用的不是最新的浏览器内核)。这就导致 WebView 在真实环境中对 API 的支持根本无迹可寻,越发...

    Crosswalk 内核的兴起与消亡

    Android 4.4 版本之前,使用的是基于 androidWebKit 的 WebView

    但实际上,由于 Android 的碎片化问题(大量存在不同的 Android 系统版本,并且各个厂商对内置应用进行定制化,有可能用的不是最新的浏览器内核)。这就导致 WebView 在真实环境中对 API 的支持根本无迹可寻,越发混乱。

    Android 碎片化问题集中表现在下面几个方面:

    • 设备繁多,硬件配置参差不弃,设备性能各异,差距很大
    • 品牌众多,厂商标准不一致,定制化系统体验不同
    • 版本各异,国内外系统环境差异巨大
    • 分辨率不统一,各种类型尺寸众多

    随着混合开发的兴起,前端对 API 的支持程度和网页的表现效果都有了更严格的要求,原生WebView 由于碎片化严重,API支持程度未知,容易引发很多意料之外的BUG。

    这时候,就诞生了一些第三方浏览器内核

    从 Android 5.0 开始,Google 把 Chromium blink内核 webview 作为 apk 单独从系统抽离出去,可以在应用市场(Google Play)上面接收安装更新。应用可以直接使用该webview内核,Google也可以及时发布更新,不用再通过更新系统才能更新浏览器内核,也避免部分了 Android 系统碎片化问题。

    因此 Intel 的 Crosswalk 就停止维护了。然而由于国内被墙,并没有接入谷歌服务,因此 腾讯X5 内核 还流传至今,并且被广泛的应用

    集成原因

    现在代的手机上,原生的 webkit 内嵌的谷歌内核版本并不是很统一,这就导致了有些手机支持的API到另一个手机,又不支持了。为了达到体验一致,也方便测试,我建议在国内,尽量使用腾讯X5进行替换,X5的API和原生的基本一致,仅需要改动较小的部分。

    那么corsswalk,一个包40M,是不是就毫无用处了呢?答案是否定的,crosswalk现在多用于集成到
    智能设备中。智能设备的网络不一定好用,更别说安装QQ微信了,而且即使安装了,也不一定支持腾讯X5,因为现在还是有部分手机无法兼容X5转而降级为原生浏览器内核的。

    集成方式

    添加依赖

    可以在项目根路径下的 build.gradle 中添加,针对所有module

    buildscript {
    	repositorities {
    		……
    	}
    }
    allprojects {
        repositories {
        	……
            maven { url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'}
        }
    }
    

    两个位置的 repositories 的区别

    1. buildscript 里是 gradle 脚本执行所需依赖,分别是对应的 maven 库和插件
    2. allprojects 里是项目本身需要的依赖

    也可以仅在对应 module 的 build.gradle 中添加 respositories,然后再添加对应依赖

    android {
    }
    repositories {
    	maven { url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'}
    }
    dependencies {
        implementation 'org.xwalk:xwalk_core_library:23.53.589.4'
    }
    

    注意:添加依赖后不可能一次就同步成功,需要多同步好几次

    申请权限

    在 AndroidManifest.xml 中添加如下权限声明

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    

    开启硬件加速

    从Android3.0(API Level 11)开始,Android 2D渲染管道k开始支持硬件加速(默认是关闭的)。

    可以在 AndroidManifest.xml 中,为 Application 添加属性,开启全局硬件加速

    <Application
    	……
    	android:hardwareAccelerated="true" >
    	……
    </Application>	
    

    硬件加速执行的所有的绘图操作,都是使用GPU在 View 对象的画布上来进行的。因为启用硬件加速会增加资源的需求,因此这样的应用会占用更多的内存。

    为了让应用能申请使用更多的内存,还需要添加一个 largeHeap 属性。机器的内存限制,在/system/build.prop文件中配置的,例如

    dalvik.vm.heapsize=128m  
    dalvik.vm.heapgrowthlimit=64m  
    

    heapgrowthlimit 是一个普通应用的内存限制,用ActivityManager.getLargeMemoryClass() 获得的值就是这个。而 heapsize 是在 manifest 中设置了 largeHeap=true 之后,可以使用最大内存值。

    习惯性的为应用多申请一点内存,可以使用如下代码

    <Application
    	……
    	android:hardwareAccelerated="true"
    	android:largeHeap="true" >
    	……
    </Application>	
    

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <org.xwalk.core.XWalkView
            android:id="@+id/webview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    测试代码

    XWResourceClient.java

    public class XWResourceClient extends XWalkResourceClient {
        private static final String TAG = "XWalkResourceClient";
    
        public XWResourceClient(XWalkView view) {
            super(view);
        }
    
        @Override
        public void onLoadStarted(XWalkView view, String url) {
            Log.i(TAG, "onLoadStarted " + url);
            super.onLoadStarted(view, url);
        }
    
        @Override
        public void onLoadFinished(XWalkView view, String url) {
            Log.i(TAG, "onLoadFinished " + url);
            super.onLoadFinished(view, url);
        }
    
        @Override
        public void onProgressChanged(XWalkView view, int progressInPercent) {
            Log.i(TAG, "onProgressChanged " + progressInPercent);
            super.onProgressChanged(view, progressInPercent);
        }
    
        @Override
        public boolean shouldOverrideUrlLoading(XWalkView view, String url) {
            Log.i(TAG, "shouldOverrideUrlLoading " + url);
            return super.shouldOverrideUrlLoading(view, url);
        }
    
        @Override
        public WebResourceResponse shouldInterceptLoadRequest(XWalkView view, String url) {
            Log.i(TAG, "shouldInterceptLoadRequest " + url);
            return super.shouldInterceptLoadRequest(view, url);
        }
    
        @Override
        public XWalkWebResourceResponse shouldInterceptLoadRequest(XWalkView view, XWalkWebResourceRequest request) {
            Log.i(TAG, "shouldInterceptLoadRequest " + request.isForMainFrame() + ", " + request.getUrl() + ", " + new JSONObject(request.getRequestHeaders()).toString());
            return super.shouldInterceptLoadRequest(view, request);
        }
    
        @Override
        public void onReceivedSslError(XWalkView view, ValueCallback<Boolean> callback, SslError error) {
            Log.i(TAG, "onReceivedSslError " + error.toString());
            super.onReceivedSslError(view, callback, error);
        }
    
        @Override
        public void onReceivedLoadError(XWalkView view, int errorCode, String description, String failingUrl) {
            Log.i(TAG, "onReceivedLoadError " + errorCode + ", " + description + ", " + failingUrl);
            super.onReceivedLoadError(view, errorCode, description, failingUrl);
        }
    
        @Override
        public void onDocumentLoadedInFrame(XWalkView view, long frameId) {
            Log.i(TAG, "onDocumentLoadedInFrame " + frameId);
            super.onDocumentLoadedInFrame(view, frameId);
        }
    
        @Override
        public void onReceivedClientCertRequest(XWalkView view, ClientCertRequest handler) {
            Log.i(TAG, "onReceivedClientCertRequest " + handler.getHost() + ", " + handler.getPort() + ", " + Arrays.toString(handler.getKeyTypes()));
            super.onReceivedClientCertRequest(view, handler);
        }
    
        @Override
        public void onReceivedHttpAuthRequest(XWalkView view, XWalkHttpAuthHandler handler, String host, String realm) {
            Log.i(TAG, "onReceivedHttpAuthRequest " + host + ", " + realm);
            super.onReceivedHttpAuthRequest(view, handler, host, realm);
        }
    
        @Override
        public void onReceivedResponseHeaders(XWalkView view, XWalkWebResourceRequest request, XWalkWebResourceResponse response) {
            Log.i(TAG, "onReceivedResponseHeaders " + request.isForMainFrame() + ", " + request.getUrl() + ", " + new JSONObject(request.getRequestHeaders()).toString());
            super.onReceivedResponseHeaders(view, request, response);
        }
    
        @Override
        public XWalkWebResourceResponse createXWalkWebResourceResponse(String mimeType, String encoding, InputStream data) {
            Log.i(TAG, "createXWalkWebResourceResponse " + mimeType + ", " + encoding);
            return super.createXWalkWebResourceResponse(mimeType, encoding, data);
        }
    
        @Override
        public XWalkWebResourceResponse createXWalkWebResourceResponse(String mimeType, String encoding, InputStream data, int statusCode, String reasonPhrase, Map<String, String> responseHeaders) {
            Log.i(TAG, "createXWalkWebResourceResponse " + mimeType + ", " + encoding + ", " + statusCode + ", " + reasonPhrase + ", " + new JSONObject(responseHeaders));
            return super.createXWalkWebResourceResponse(mimeType, encoding, data, statusCode, reasonPhrase, responseHeaders);
        }
    
        @Override
        public void doUpdateVisitedHistory(XWalkView view, String url, boolean isReload) {
            Log.i(TAG, "doUpdateVisitedHistory " + url + ", " + isReload);
            super.doUpdateVisitedHistory(view, url, isReload);
        }
    
        @Override
        protected Object getBridge() {
            Object obj = super.getBridge();
            if(obj != null) {
                Log.i(TAG, "getBridge " + obj.getClass().getSimpleName());
            } else {
                Log.i(TAG, "getBridge()");
            }
            return obj;
        }
    }
    

    XWUIClient.java

    public class XWUIClient extends XWalkUIClient {
    
        private static final String TAG = "XWalkUIClient";
    
        public XWUIClient(XWalkView view) {
            super(view);
        }
    
        @Override
        public void onPageLoadStarted(XWalkView view, String url) {
            Log.i(TAG, "onPageLoadStarted " + url);
            super.onPageLoadStarted(view, url);
        }
    
        @Override
        public void onPageLoadStopped(XWalkView view, String url, LoadStatus status) {
            Log.i(TAG, "onPageLoadStopped " + url + ", " + status.toString());
            super.onPageLoadStopped(view, url, status);
        }
    
        @Override
        public boolean onJsAlert(XWalkView view, String url, String message, XWalkJavascriptResult result) {
            Log.i(TAG, "onJsAlert " + url + ", " + message);
            return super.onJsAlert(view, url, message, result);
        }
    
        @Override
        public boolean onJsConfirm(XWalkView view, String url, String message, XWalkJavascriptResult result) {
            Log.i(TAG, "onJsConfirm " + url + ", " + message);
            return super.onJsConfirm(view, url, message, result);
        }
    
        @Override
        public boolean onJsPrompt(XWalkView view, String url, String message, String defaultValue, XWalkJavascriptResult result) {
            Log.i(TAG, "onJsPrompt " + url + ", " + message);
            return super.onJsPrompt(view, url, message, defaultValue, result);
        }
    
        @Override
        public boolean onConsoleMessage(XWalkView view, String message, int lineNumber, String sourceId, ConsoleMessageType messageType) {
            Log.i(TAG, "onConsoleMessage " + message + ", " + lineNumber + ", " + sourceId + ", " + messageType.toString());
            return super.onConsoleMessage(view, message, lineNumber, sourceId, messageType);
        }
    
        @Override
        public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback) {
            Log.i(TAG, "onShowCustomView " + requestedOrientation);
            super.onShowCustomView(view, requestedOrientation, callback);
        }
    
        @Override
        public void onShowCustomView(View view, CustomViewCallback callback) {
            Log.i(TAG, "onShowCustomView");
            super.onShowCustomView(view, callback);
        }
    
        @Override
        public boolean onCreateWindowRequested(XWalkView view, InitiateBy initiator, ValueCallback<XWalkView> callback) {
            Log.i(TAG, "onCreateWindowRequested");
            return super.onCreateWindowRequested(view, initiator, callback);
        }
    
        @Override
        public boolean onJavascriptModalDialog(XWalkView view, JavascriptMessageType type, String url, String message, String defaultValue, XWalkJavascriptResult result) {
            Log.i(TAG, "onJavascriptModalDialog " + type.toString() + ", " + url + ", " + message + ", " + defaultValue);
            return super.onJavascriptModalDialog(view, type, url, message, defaultValue, result);
        }
    
        @Override
        public void onFullscreenToggled(XWalkView view, boolean enterFullscreen) {
            Log.i(TAG, "onFullscreenToggled " + enterFullscreen);
            super.onFullscreenToggled(view, enterFullscreen);
        }
    
        @Override
        public void onHideCustomView() {
            Log.i(TAG, "onHideCustomView");
            super.onHideCustomView();
        }
    
        @Override
        public void onIconAvailable(XWalkView view, String url, Message startDownload) {
            Log.i(TAG, "onIconAvailable " + url + ", " + startDownload.toString());
            super.onIconAvailable(view, url, startDownload);
        }
    
        @Override
        public void onJavascriptCloseWindow(XWalkView view) {
            Log.i(TAG, "onJavascriptCloseWindow");
            super.onJavascriptCloseWindow(view);
        }
    
        @Override
        public void onReceivedIcon(XWalkView view, String url, Bitmap icon) {
            Log.i(TAG, "onReceivedIcon " + url);
            super.onReceivedIcon(view, url, icon);
        }
    
        @Override
        public void onReceivedTitle(XWalkView view, String title) {
            Log.i(TAG, "onReceivedTitle " + title);
            super.onReceivedTitle(view, title);
        }
    
        @Override
        public void onRequestFocus(XWalkView view) {
            Log.i(TAG, "onRequestFocus");
            super.onRequestFocus(view);
        }
    
        @Override
        public void onScaleChanged(XWalkView view, float oldScale, float newScale) {
            Log.i(TAG, "onScaleChanged " + oldScale + ", " + newScale);
            super.onScaleChanged(view, oldScale, newScale);
        }
    
        @Override
        public void onUnhandledKeyEvent(XWalkView view, KeyEvent event) {
            Log.i(TAG, "onUnhandledKeyEvent " + event.getAction() + ", " + event.getKeyCode());
            super.onUnhandledKeyEvent(view, event);
        }
    
        @Override
        public void openFileChooser(XWalkView view, ValueCallback<Uri> uploadFile, String acceptType, String capture) {
            Log.i(TAG, "openFileChooser " + acceptType + ", " + capture);
            super.openFileChooser(view, uploadFile, acceptType, capture);
        }
    
        @Override
        public boolean shouldOverrideKeyEvent(XWalkView view, KeyEvent event) {
            Log.i(TAG, "shouldOverrideKeyEvent " + event.getAction() + ", " + event.getKeyCode());
            return super.shouldOverrideKeyEvent(view, event);
        }
    
        @Override
        protected Object getBridge() {
            Object obj = super.getBridge();
            if(obj != null) {
                Log.i(TAG, "getBridge " + obj.getClass().getSimpleName());
            } else {
                Log.i(TAG, "getBridge()");
            }
            return obj;
        }
    }
    

    MainActivity.java

    public class MainActivity extends XWalkActivity {
    
        private XWalkView webView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            webView = findViewById(R.id.webview);
            // Crosswalk's APIs are not ready yet
        }
    
        @Override
        protected void onXWalkReady() {
            initSettings();
            webView.setUIClient(new XWUIClient(webView));
            webView.setResourceClient(new XWResourceClient(webView));
            webView.addJavascriptInterface(new AppShell(this), AppShell.TAG);
            webView.loadUrl("http://www.baidu.com");
        }
    
        @Override
        public void onPointerCaptureChanged(boolean hasCapture) {
        }
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            if(isXWalkReady()) webView.onNewIntent(intent);
        }
        @Override
        protected void onPause() {
            super.onPause();
            if(isXWalkReady()) {
                webView.pauseTimers();
                webView.onHide();
            }
        }
        @Override
        protected void onResume() {
            super.onResume();
            if(isXWalkReady()) {
                webView.resumeTimers();
                webView.onShow();
            }
        }
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if(isXWalkReady()) {
                webView.onDestroy();
            }
        }
    
        @Override
        public void onBackPressed() {
            if(isXWalkReady()) {
                XWalkNavigationHistory history = webView.getNavigationHistory();
                if (history.canGoBack()) {
                    history.navigate(XWalkNavigationHistory.Direction.BACKWARD, 1);
                } else {
                    super.onBackPressed();
                }
            } else {
                super.onBackPressed();
            }
        }
    
        /**
         * 没有允许定位的设置
         */
        public void initSettings() {
            XWalkSettings webSettings = webView.getSettings();
    
            //启用JavaScript
            webSettings.setJavaScriptEnabled(true);
            //允许js弹窗alert等,window.open方法打开新的网页,默认不允许
            webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
    
            //localStorage和sessionStorage
            webSettings.setDomStorageEnabled(true);
            //Web SQL Databases
            webSettings.setDatabaseEnabled(true);
            //是否可访问Content Provider的资源,默认值 true
            webSettings.setAllowContentAccess(true);
    
            /*
            是否允许访问文件系统,默认值 true
            file:///androMSG_asset和file:///androMSG_res始终可以访问,不受其影响
             */
            webSettings.setAllowFileAccess(true);
            //是否允许通过file url加载的Javascript读取本地文件,默认值 false
            webSettings.setAllowFileAccessFromFileURLs(true);
            //是否允许通过file url加载的Javascript读取全部资源(包括文件,http,https),默认值 false
            webSettings.setAllowUniversalAccessFromFileURLs(true);
    
            //设置是否支持缩放
            webSettings.setSupportZoom(false);
            //设置内置的缩放控件
            webSettings.setBuiltInZoomControls(false);
    
            /*
             当该属性被设置为false时,加载页面的宽度总是适应WebView控件宽度;
             当被设置为true,当前页面包含viewport属性标签,在标签中指定宽度值生效,如果页面不包含viewport标签,无法提供一个宽度值,这个时候该方法将被使用。
             */
            webSettings.setUseWideViewPort(false);
            //缩放至屏幕大小
            webSettings.setLoadWithOverviewMode(true);
            //支持多窗口
            webSettings.setSupportMultipleWindows(true);
    
            /*
            缓存模式
            LOAD_CACHE_ONLY         不使用网络,只读取本地缓存
            LOAD_DEFAULT            根据cache-control决定是否从网络上获取数据
            LOAD_NO_CACHE           不使用缓存,只从网络获取数据
            LOAD_CACHE_ELSE_NETWORK 只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据
             */
            webSettings.setCacheMode(XWalkSettings.LOAD_DEFAULT);
            //设置是否加载图片
            webSettings.setLoadsImagesAutomatically(true);
    
            //允许远程调试
            XWalkPreferences.setValue("enable-javascript", true);
            XWalkPreferences.setValue(XWalkPreferences.REMOTE_DEBUGGING, true);
        }
    }
    

    生命周期

    在这里插入图片描述XWalk 内核加载的生命周期

    1. 预加载 xwalk 内核
    2. 将共享的XWalk内核与当前Activity绑定
    public static void reserveReflectObject(Object object) {
    	String tag = (String)sReservedActivities.getLast();
        Log.d("XWalkLib", "Reserve object " + object.getClass() + " to " + tag);
        ((LinkedList)sReservedActions.get(tag)).add(new XWalkCoreWrapper.ReservedAction(object));
    }
    
    1. 在Activity中初始化XWalk内核

    2. 解压、激活、将内核附着在Activity上

    3. 下载模式禁用
      下载模式和共享模式差不多,只是共享模式是把APK下载下来当成一个应用安装到手机上,而下载模式干脆把APK下载到自己的私有目录下,把所有的so文件、资源解压出来保存到自己的内部私有目录下只供自己使用。

    4. 通过反射,api版本是否等于lib版本(mApiVersion == minLibVersion)

    private boolean checkCoreVersion() {
      Log.d("XWalkLib", "[Environment] SDK:" + VERSION.SDK_INT);
         Log.d("XWalkLib", "[App Version] build:23.53.589.4, api:" + this.mApiVersion + ", min_api:" + this.mMinApiVersion);
    
         try {
             Class<?> clazz = this.getBridgeClass("XWalkCoreVersion");
             String buildVersion = "";
    
             try {
                 buildVersion = (String)(new ReflectField(clazz, "XWALK_BUILD_VERSION")).get();
             } catch (RuntimeException var5) {
             }
    
             int libVersion = (Integer)(new ReflectField(clazz, "API_VERSION")).get();
             int minLibVersion = (Integer)(new ReflectField(clazz, "MIN_API_VERSION")).get();
             Log.d("XWalkLib", "[Lib Version] build:" + buildVersion + ", api:" + libVersion + ", min_api:" + minLibVersion);
             if (XWalkEnvironment.isDownloadMode() && XWalkEnvironment.isDownloadModeUpdate() && !buildVersion.isEmpty() && !buildVersion.equals("23.53.589.4")) {
                 this.mCoreStatus = 8;
                 return false;
             }
    
             if (this.mMinApiVersion > libVersion) {
                 this.mCoreStatus = 3;
                 return false;
             }
    
             if (this.mApiVersion < minLibVersion) {
                 this.mCoreStatus = 4;
                 return false;
             }
         } catch (RuntimeException var6) {
             Log.d("XWalkLib", "XWalk core not found");
             this.mCoreStatus = 2;
             return false;
         }
    
         Log.d("XWalkLib", "XWalk core version matched");
         return true;
     }
    
    1. 打印出,当前库是基于ARM架构编译的。当前设备是arm64-v8a,使用嵌入模式运行
    2. 搭建环境、初始化内核、初始化视图,激活任务执行完毕,开始在 SurfaceView 上进行绘制。
      在这里插入图片描述
    函数 用途
    getBridge XWalkUIClient 和 XWalkResourceClient 获取反射的对象
    shouldInterceptLoadRequest 拦截请求,在这里可以使用缓存
    onPageLoadStarted、onPageLoadStopped 页面加载开始、结束,可以用来做自定义定时器
    onLoadStarted、onLoadStopped 页面中的元素加载开始和结束
    onReceivedResponseHeaders 处理接收的头部
    shouldOverrideUrlLoading 用来处理意图
    doUpdateVisitedHistory 更新访问历史记录
    onReceivedTitle 收到标题

    遇到的问题

    1. Crosswalk‘s APIs are not ready yet

    在这里插入图片描述
    首先, org.xwalk.core.XWalkView 控件,只能在 XWalkActivity 里,也就是当前 Activity 必须继承自 XWalkActivity。
    在这里插入图片描述
    对 XWalkView 的设置,只能 onXWalkReady 里。
    在这里插入图片描述
    在 Activity 的生命周期函数中调用 XWalkView 的方法需要先判断是否初始化完毕。
    在这里插入图片描述

    2. Mismatch of CPU Architecture

    在这里插入图片描述
    so分32位和64位!

    理论上官方应该提供2种包含不同so的aar包。一种是32位的另一种是64位,32位的aar中只包含x86和armeabi-v7a两种so文件,同理64位的包中只包含x86_64和arm64-v8a两种so文件。

    由于arm64-v8a平台能兼容32位的so文件、x86_64也能兼容32位的x86 so文件,在不考虑性能(暂时未知性能问题)的情况下就可以直接集成32位的aar包,可以大大减少安装包的大小。

    腾讯X5的话,是仅支持32位的。我猜测 crosswalk 应该也是这个问题,因此仅集成32位即可。

    因此可以在 module 的 build.gradle 中添加如下内容

    android {
    	defaultConfig {
    	    ndk {
    	        abiFilters  'armeabi', 'armeabi-v7a'
    	    }
    	}
    }
    

    然后,再跟腾讯 X5 的做法一样,在 src/mian/jniLibs/armeabi-v7a 目录下,创建一个空的 so

    在这里插入图片描述

    3. 文件选择的问题

    在 HTML5 中共有 4 种选择文件的方式,代码如下

    <label>下面是选择文件</label>
    <input type="file"  name="filename" />
    
    <label>下面是通过摄像头获取文件</label>
    <input capture="camera" id="cameraFile" name="imgFile" type="file">
    
    <label>下面是打开摄像头拍照</label>
    <input accept="image/*" capture="camera" id="imgFile" name="imgFile" type="file">
    
    <label>下面是打开摄像头录像</label>
    <input accept="video/*" capture="camera" id="videoFile" name="imgFile" type="file">
    

    在 CrossWalk 中对应的函数是 XWalkUIClient.java 中的 openFileChooser。如果主动不触发回调函数,即为未选择,那么内部会一直处于等待的过程中,即使下一次点击选择文件,也不会有响应。

    public void openFileChooser(XWalkView view, ValueCallback<Uri> uploadFile, String acceptType, String capture) {
    	……
    }
    

    获取文件(文件、拍照、相册、录像)

    序号 acceptType capture 含义
    1 false 获取文件
    2 true 打开摄像头获取文件
    3 image/* true 打开摄像头拍照
    4 video/* true 打开摄像头录像

    实现大致逻辑(再细的代码就不贴了,讲个思路)

    @Override
    public void openFileChooser(XWalkView view, ValueCallback<Uri> uploadFile, String acceptType, String capture) {
        Log.i(TAG, "openFileChooser " + acceptType + ", " + capture);
        super.openFileChooser(view, uploadFile, acceptType, capture);
    
        if ("true".equals(capture)) {
            //判断是拍视频,还是拍照
            boolean isVideo = "video/*".equals(acceptType);
            String path;
            DataCallback1<Uri> callback = uri -> {
                LogUtil.i(TAG, "uri: " + (uri == null ? null : uri.toString()));
                uploadFile.onReceiveValue(uri);
            };
            if (isVideo) {
                //拍视频
                path = genMoviesPath(activity);
                LogUtil.i(TAG, path);
                if(path == null) return;
                FileUtil.mkParentDirs(path);
                LogUtil.d(TAG, "videoCapture: " + path);
                IntentUtil.videoCapture(activity, path, callback);
            } else {
                //拍照片
                path = genPicturePath(activity);
                LogUtil.i(TAG, path);
                if(path == null) return;
                FileUtil.mkParentDirs(path);
                LogUtil.d(TAG, "videoCapture: " + path);
                IntentUtil.imageCaptureToUri(activity, path, callback);
            }
        } else {
            if(TextUtils.isEmpty(acceptType)) acceptType = "*/*";
            IntentUtil.selectFile(activity, acceptType, (uri, path, mimeType) -> uploadFile.onReceiveValue(uri));
        }
    }
    

    4. 注解 @JavascriptInterface

    注意一个细节,原生 webkit 乃至腾讯X5,用的都是 android.webkit.JavascriptInterface ,然而 crosswalk 不同,它用的是 org.xwalk.core.JavascriptInterface。如果注解用错了,抱歉 Uncaught TypeError: <JavaScriptInterfaceName.Method> is not a function

    5. 截图

    普通的 View 控件,直接用下面函数即可截图。但 Crosswalk 用下面方法,只能得到一张白纸

    public static Bitmap getView(View view) {
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap cache = view.getDrawingCache();
        Bitmap bitmap = BitmapUtil.clone(cache);
        view.setDrawingCacheEnabled(false);
        view.destroyDrawingCache();
        return bitmap;
    }
    

    网上有人说是 “硬件加速” 的问题,如下两种方法关闭硬件加速

    • 在 AndroidManifest.xml 的 application 或 activity 里添加 android:hardwareAccelerated="false"
    • 在代码中设置 webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

    经过测试发现行不通,最后发现 XWalkView 自带异步的截图方法,源码如下

    public void captureBitmapAsync(XWalkGetBitmapCallback callback) {
        try {
            this.captureBitmapAsyncXWalkGetBitmapCallbackInternalMethod.invoke(new Object[]{callback.getBridge()});
        } catch (UnsupportedOperationException var3) {
            if (this.coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            }
            XWalkCoreWrapper.handleRuntimeError(var3);
        }
    }
    

    6. 拦截请求

    public class XWResourceClient {
         @Override
         public XWalkWebResourceResponse shouldInterceptLoadRequest(XWalkView view, XWalkWebResourceRequest request) {
             String url = request.getUrl().toString(); 
             if(!TextUtils.isEmpty(url)&&url.endsWith(".png")) {
                 Log.i(TAG, String.format("拦截网址:%s", url));
                 return createXWalkWebResourceResponse("text/html","UTF-8",null);//不向过滤的地址发出请求
             }
             return super.shouldInterceptLoadRequest(view, request);
         }
    }
    

    7. CrossWalk 支持 websocket

    注意,if (typeof WebSocket != 'undefined') 并不能判断 websocket 是否被支持。因为 Android 中,即使浏览器不支持 WebSocket ,但是它还是存在这个属性。

    正确的验证方法如下

    function isSupportWebsocket() {
        if (!!window.WebSocket && window.WebSocket.prototype.send) {
    		return true;
        } else {
       		return false;
        }
    }
    

    部分方法不支持

    1. Object #<HTMLElement> has no method 'remove'
    展开全文
  • 图1- 1浏览器内核fork关系 上图清晰的展示了目前浏览器内核的fork关系,现如今浏览器内核呈现四分天下,分别是Google公司主导的Blink内核,Apple公司主导的WebKit内核,微软公司主导的EdgeHtml内核以及老牌的...
  • cordova Android集成crosswalk浏览器内核

    千次阅读 2019-01-18 12:01:34
    由于ios对浏览器内核性能较好,不需要使用第三方内核,这里针对Android打包 1.安装crosswalk插件 cordova plugin add cordova-plugin-crosswalk-webview 2.关闭crosswalk多核打包 在项目根目录下的config.xml配置...
  • 查看android内置(webview)浏览器和系统浏览器内核信息
  • 浏览器内核

    2019-03-17 16:26:44
    Apple的Safari, Google的Chrome, Nokia S60平台的默认浏览器,Apple手机的默认浏览器,Android手机的默认浏览器均采用的Webkit作为器浏览器内核。Webkit的采用程度由 此可见一斑,理所当然的成为了当今主流的三大...
  • Android集成腾讯X5浏览器内核库一、相关配置1. 相关地址2.引入SDK3. AndroidManifest配置二、Application中初始化内核三、代码实现1. 自定义带ProgressBar的WebView2. activity_main.xml3. MainActivity 一、相关...
  • 1、为什么要集成腾讯 X5 浏览器内核 肯定是事出有因,简单来说,JS代码写的不标准,与部分机型内嵌套的浏览器内核产生矛盾,出现底层(os)bug导致,不得不费事搞一个其它内核进行加载网页,具体原因。 2、官方网站...
  • 魅族Note 5手机通过手机设置内无法查看版本,可在浏览器内输入该链接,即可查看浏览器内核版本 3、chromedriver对应版本 chromedriver下载地址:http://chromedriver.storage.googleapis.com/ind
  • 浏览器内核:1.Webkit内核;2.Chrominum内核;3.Blink内核。 第三方可靠的WebView组件的两套解决方案:Crosswalk与TBS(X5内核)服务。  WebView加载H5也有两种模式,一种是加载服务器的H5页面,一种是加载本地的H5...
  • 常见浏览器内核

    2021-02-09 18:11:49
    IE -->trident Chrome–>blink(之前:webkit) Opera–>...Android 4.4之前的android系统浏览器内核是WebKit,Android4.4系统浏览器切换到了Chromium浏览器(内核是Webkit的分支Blink) ...
  • 浏览器内核、webview内核

    千次阅读 2019-09-24 23:23:20
    不同的手机,出于各种目的,会对自己的浏览器内核进行修改, 而不是用Android原生的浏览器, 所以在web的现实上也会有差异的。应该通过写更加标准通用的js方法来增加兼容性。 2:国内现状多数手机浏览器都基于...
  • 常见浏览器内核总结

    2020-06-01 23:18:08
    常见浏览器内核 浏览器 内核 备注 IE Trident IE、百度浏览器、猎豹安全、360浏览器 firefox Gecko 火狐浏览器内核 Safari Webkit Apple Safari (Win/Mac/iPhone/iPad)、Symbian手机浏览器、Android ...
  • Android接入腾讯X5浏览器内核

    千次阅读 2020-03-27 14:35:29
    该方案由SDK、手机QQ浏览器X5内核和X5云端服务组成,解决移动端webview使用过程中出现的一切问题,优化用户的浏览体验。同时,腾讯还将持续提供后续的更新和优化,为开发者提供最新最优秀的功能和服务。 其中,SDK是...
  • 浏览器内核解析

    2017-11-01 11:07:30
    Apple的Safari, Google的Chrome, Nokia S60平台的默认浏览器,Apple手机的默认浏览器,Android手机的默认浏览器均采用的Webkit作为器浏览器内核。Webkit的采用程度由 此可见一斑,理所当然的成为了当今主流的三大...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,463
精华内容 585
关键字:

android浏览器内核