tomorrow.cyz@gmail.com

什么是CrossWalk

CrossWalk是基于Chromium内核的一款HTML应用运行环境,用户可以在上面搭建HTML应用。跨平台开发环境Cordova现在就将CrossWalk当做自己的运行环境。 使用CrossWalk,可以直接开发Web App,在Android上,也可以将他当做一个Embed HTML Runtime,替代系统WebView。

为什么使用CrossWalk

很多公司使用系统的WebView桥接来实现Native和H5的混合开发模式,开发的时候碰到了一些痛点

  1. Android各个版本的WebView差异太大,4.4以下甚至使用传统的WebKit而不是Chromium内核,前端需要适配各种机器,各种兼容性的问题让人抓狂。
  2. 对内核有定制需求根本不可能。App开发只能靠大量的javascript注入实现一些简单的功能,有很多非常需要的需求没法落地。
  3. 超级App对自主内核有强烈的需求,如微信

一般的App公司,要基于Chromium做出一个自主的内核来,难度很大。特别是Android5.0版本在Framework层对Render做了线程化,对显示的架构影响比较大。而Android WebView 的机制,网页绘制又是通过在Framework的Render里面置入DisplayList(相当于一些列的OpenGL command)来实现的。Chromium M39后的的内核,硬件加速这块很难在5.0以前的 版本上跑起来。而5.0以下的版本,硬件加速是否开启,对网页绘制性能的影响很大。所以,要通过自己直接移植Chromium内核和Android WebView的方式来解决自主内核的问题, 要投入很大的人力。

另外,android版本兼容,对自主内核来说,也是一个蛮大的挑战。相比之下,CrossWalk因为其广泛的测试和应用,兼容性势必要好很多。

如何使用XWalk Embed

XWalkView有一个例子很好地展示了XWalk Embed的使用。

Crosswalk的API和Android WebView并没有一一对应的关系,官方也明确声明,出于兼容性和性能的考虑,并不完全兼容WebView的API。但是,大部分Android WebView的接口,在XWalk都能找到。比如,XWalkView类对应于WebView类,XWalkSettings对应于WebSettings,XWalkNavigationHistory对应于WebBackHistory,XWalkCookieManager对应于CookieManager。CookieSyncManager本身在Android API21已经Deprecated,所以没有对应的XWalk类。

对应于WebView的Callback WebViewClient和WebChromeClient,XWalk提供了XWalkResourceClient和XWalkUIClient类。大部分接口都可以对应得上。需要注意的是,XWalkResourceClient里面,onLoadFinished对应的是整个页面级别的Finish,而不是单个Resource的Finish,而onLoadStarted则对应的是单个resource的Finish。对应于单个页面的start的接口是XWalkUIClient::onPageLoadStarted。

XWalk没有对应的onGeolocationPermissionsShowPrompt接口。

官方文档有的地方没有更新(包括源代码的注释也没有更新),说如果不继承XWalkActivity的话,需要自己调用XWalkInitializer来初始化。已经确认,并不需要。XWalk并不需要一个初始化的接口,从源代码实现上可以看到XWalkView初始化的时候,如果内核没有初始化,会进行初始化(比如load library)。正因为如此,第一个XWalkView的调用会略慢一点,但并不明显。

XWalkView和WebView的使用的主要差异有两点:

  1. XWalkView需要显示地调用destroy等操作,在这个Class Overview的例子里面可以看到。
  2. XWalkView的初始化需要一个Activity的参数,这限制了XWalkView在一些Null Acitivity的使用场合,比如Service。WebView则没有这方面的限制。

自己编译crosswalk内核

自己编译Crosswalk,给了我们定制化内核的能力,比如裁剪一些功能以减少size,比如实现password save等定制化需求。

另外,自己编译Crosswalk,碰到问题可以从内核上调试及解决,不怕坑。

编译Crosswalk 给出了很detail的步骤。

使用XWalkView的一些注意事项

  1. 缺省情况下,XWalkView的backend是SurfaceView,这决定了XWalkView缺省情况下不能使用动画,同一个Window不能有两个XWalkView。 这个问题在App利用Fragment进行页面切换的时候非常容易暴露出来,比如,一个App在某一个操作的时候,通过隐藏一个Fragment,显示另外一个Fragment来加快不同页面的切换速度(相比之下,Activity的切换成本显然要高),如果两个Fragment里面都有XWalkView,第二个Fragment就会显示不出来。

    官方对这个问题的解决方案是开发者可以通过设置backend为TextureView,来代替SurfaceView。代价是一定的性能损失和内存的增加。

    XWalkPreferences.setValue(XWalkPreferences.ANIMATABLE_XWALK_VIEW, true);

    xwalk-2457有对这个问题的bug描述

    TextureView和SurfaceView都会使用硬件加速,但是SurfaceView可以在没有硬件加速的情况下工作,TextureView则不能。

    也可以参考ANIMATABLE_XWALK_VIEWchromium的讨论

  2. XWalkView需要显示地调用destroy等操作 如何使用XWalk Embed里面已经有描述,需要特别注意

  3. Android6.0以上版本,同一个app,XWalkView和Android WebView不能共存 在Android系统里面,每个App全局只有一个Assets目录,而Chromium内核初始化icu的时候(lazy-init,要调用icu的地方初始化icu),会将icudtl.dat目录拷贝到Asset目录下,而XWalk虽然将icudtl.dat放到了res/raw下面,但是代码里面(icu_util.cc)监察到Asset有icudtl.dat,会优先使用Assets/icudtl.dat,用到了是android webview匹配的icudtl.dat。

这个问题要考虑到其他第三方包对android webview的使用,比如自己的app可能没有调用任何android.webkit的函数,但是引入了第三方包exampleSDK,该第三方包调用了CookieManager或者CookieSyncManager,就会带来共存问题。直接导致你的app在有些输入框界面crash(因为icu resource missing)。

官方给的workaround是在android webview之前初始化XWalkView,是一个很差的解决方案。因为第三方SDK大部分在Application初始化的时候就调用,而XWalkView的初始化要一个Activity参数,导致需要将第三方SDK的初始化放到第一个Activity的onCreate里面运行,然后实例化一个可能没有用的XWalkView。

更好的解决方案是自己编译内核,在icu_util.cc里面,将检查读取Assets/icudtl.dat的代码注释掉,实际上,XWalk的ResourceExtractor.java里面已经有说明XWalk不再从assets目录下读取icudtl.dat文件,这部分代码注释掉是合理的。

相应的bug可以参考xwalk-7004

对ICU没有概念的看下Chromium ICU库定制裁剪

tomorrow.cyz@gmail.com

dlmu2001.github.io


dlmu2001

stay foolish, stay hungry!