corsswalk的研究和使用(一)

来源:互联网 发布:mac彻底删除战网 编辑:程序博客网 时间:2024/05/16 00:43

corsswalk作为一款优秀的开源web引擎,在当今碎片化严重的android中简直是广大开发者的福音,使用它代替webview来跑游戏速度可谓是杠杠的,具体的介绍可以参考文章:http://dev.yesky.com/24/39285024.shtml。

仔细阅读上面推荐的文章,发现它的好处之后才有动力继续研究它。然后我总结一下
Tables 正常版 简化版 Shared Mode embedded Mode Android webview(x86) √ √ √ √ Android webview(ARM) √ √ √ √ Cordova Android(x86) √ √ √ √ Cordova Android(ARM) √ √ √ √
  • 正常版就是官网上主要介绍的那些,下载地址https://crosswalk-project.org/documentation/downloads.html,一般有30几M,当嵌入混合应用的时候导致程序异常庞大。

  • 简化版,好像很少在官网上看到他的介绍,存在于https://github.com/crosswalk-project/crosswalk-website/wiki/Crosswalk-Project-Lite,一般是10M左右,wiki上也说了,由于不是主要研究的方向,所以会有一些bug,楼主使用简化版至今也发现了一些勉强可以接受的Bug.感觉也是没怎么更新的样子,下载地址https://download.01.org/crosswalk/releases/crosswalk-lite/android/canary/

  • 由于发现了crosswalk实在是太大了,官方也出来两种模式Shared Mode,embedded Mode。官网的介绍可以查看https://crosswalk-project.org/documentation/android/run_on_android.html,embedded Mode就是把整个二三十M东西导入到你要开发的程序里面,简单暴力,就是有点大。Shared Mode就是装一个crosswalk的apk包,目的就是来提供crosswalk runtime,而其他的程序不需要导入这个包而是直接引用它,这样就能多个程序共用一个runtime库。(该页面官网提供Shared Mode的示例apk下载,可以感受一下)

Embedded

In embedded mode packaging, each web app is bundled with the full Crosswalk runtime. Since the Crosswalk runtime needs an architecture-dependent native library, two Android apks need to be generated for embedded mode: one for targets with Intel architecture (x86) and another for ARM targets. The make_apk.py script used in this tutorial generates a package for each architecture by default, as explained above.

The advantage is that you can keep a tight dependency between Crosswalk and the application, so you can ensure that the correct Crosswalk version is used. (In shared mode, you would have to ensure that the user had the correct runtime version available.)

The disadvantage is that the generated apk is significantly larger, as it contains the whole Crosswalk runtime inside it.

Shared

In shared mode packaging, each web app is bundled with a thin layer of Java code which is architecture-independent. This produces a much smaller apk file. However, to run this shared mode application, a separate, architecture-dependent Crosswalk runtime also has to be installed on the target. Again, one runtime is required for each architecture (one for x86, one for ARM); but, unlike embedded mode, multiple applications can share this single runtime.

The advantage is that one Crosswalk runtime library can support multiple shared mode applications: valuable if you are using Crosswalk to deploy multiple applications on the same Crosswalk version, as it reduces the size of each application apk.

Another advantage is that you can upgrade the runtime for multiple applications by upgrading one shared Crosswalk runtime package. By contrast, in embedded mode, upgrading the runtime requires you to upgrade each application at the same time: so moving to a newer runtime for multiple applications means upgrading each of those applications separately.

The disadvantage is that you must distribute apks both for your web applications and for the Crosswalk runtime.


使用

介绍了这么多,接下来看看下载的crosswalk有什么东西。因为我使用的是简化版的arm。所以就以最新的简化版为例,打开crosswalk-webview-10.39.240.1-arm,发现大概12M的东西,在crosswalk-webview-10.39.240.1-arm\res\raw\libxwalkcore.so.armeabi_v7a这个文件大概占了8M多而且还是个压缩文件,楼主把他理解为runtime。然后在lib目录有个xwalk_core_library_java.jar,通过调用api里面的XWalkView(类似于webview)实现网页的加载。

导入Project之后,接下来就是使用。
首先必须要继承XWalkActivity抽象类

public class MainActivity extends XWalkActivity {    private XWalkView xWalkView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        xWalkView = new XWalkView(this, this);        //类似于webview.setWebViewClient(new WebViewClient());        //XWalkView已经没有setWebChromeClient()方法,但是在XWalkResourceClient中多了个onProgressChanged回调方法。        xWalkView .setResourceClient(new XWalkResourceClient(xWalkView ));        //设置Ui回调        walkView.setUIClient(new XWalkUIClient(walkView));        setContentView(xWalkView);    }    //返回上个页面    private void back(){         if(xWalkView.getNavigationHistory().canGoBack())                xWalkView.getNavigationHistory().navigate(Direction.BACKWARD, 1);     }    //抽象方法,当crosswalk初始化完成时才会执行该方法,允许XWalkView在此之前初始化,但是不允许它在此之前加载网页。    //之前的版本load方法可以在crosswalk初始化之前调用,现在不行了    @Override    protected void onXWalkReady() {        // webview加载网页是loadUrl("http://csdn.net");        xWalkView.load("http://csdn.net", null);    }}

XWalkResourceClient类似WebViewClient,看看便知,上手极快 ,XWalkUIClient顾名思义,实现下打印个log就知道哪些情况会调用到了,


有没有发现一般情况下使用webview时是要调用getSettings()来设置使用js,读取本地设置等等功能,但是在XWalkView中这些都帮我们封装好了,所以导致了没有方法去获取XWalkSettings.但是如果想要设置XWalkView的资源缓存方式的话要怎么办,只能使用反射了。

    //设置加载缓存的方式,和WebView的设置方式其实差不多    public void setCacheMode(XWalkView xw){        try {            Method _getBridge = XWalkView.class.getDeclaredMethod("getBridge");            _getBridge.setAccessible(true);            XWalkViewBridge xWalkViewBridge = null;            xWalkViewBridge = (XWalkViewBridge)_getBridge.invoke(xw);            XWalkSettings xWalkSettings = xWalkViewBridge.getSettings();            if(NetWorkHelp.isWifiConnected(this)){                xWalkSettings.setCacheMode(WebSettings.LOAD_DEFAULT);            }else{                xWalkSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);            }        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (IllegalArgumentException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        }    }

程序需要以下权限

    <uses-permission android:name="android.permission.INTERNET"/>    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

实现原理

研究一下XWalkActivity 的实现原理,为什么要在Avtivity继承。

public abstract class XWalkActivity extends Activity {    private XWalkActivityDelegate mActivityDelegate;    /**     * Run on the UI thread to notify the Crosswalk runtime is ready.     */    protected abstract void onXWalkReady();    /**     * Return true if the Crosswalk runtime is ready, false otherwise.     */    public boolean isXWalkReady() {        return mActivityDelegate.isXWalkReady();    }    /**     * Return true if running in shared mode, false otherwise.     */    public boolean isSharedMode() {        return mActivityDelegate.isSharedMode();    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Runnable cancelCommand = new Runnable() {            @Override            public void run() {                finish();            }        };        Runnable completeCommand = new Runnable() {            @Override            public void run() {                onXWalkReady();            }        };        mActivityDelegate = new XWalkActivityDelegate(this, cancelCommand, completeCommand);    }    @Override    protected void onResume() {        super.onResume();        mActivityDelegate.onResume();    }}

XWalkActivity默认运行embedded mode ,当运行的app当中没有runtime的时候,或者包含的rumtime不符合cpu架构的时候,它将会切换为shared mode,就会查找手机上的安装好的runtime,当rumtime没有或者不匹配的时候,就会弹出个dialog提示用户去下载安装runtime,默认是到缺省的应用市场下载,我们可以在 Android manifest插入meta-data修改下载地址 android:name=”xwalk_apk_url” android:value=”http://host/XWalkRuntimeLib.apk”

在改抽象类中主要实例化XWalkActivityDelegate以及调用mActivityDelegate.onResume()。参数中的cancelCommand顾名思义就是接受到取消命令的时候调用的,一般第一次打开会解压Crosswalk runtime,可能是用于此。completeCommand 是runtime加载完成回调的方法,在此处调用load方法。

shared mode下没有runtime,提示用户下载

那XWalkActivityDelegate是怎么实现的

public class XWalkActivityDelegate            implements DecompressListener, ActivateListener, XWalkUpdateListener {    ......    public XWalkActivityDelegate(Activity activity,            Runnable cancelCommand, Runnable completeCommand) {        mActivity = activity;        mCancelCommand = cancelCommand;        mCompleteCommand = completeCommand;        //解压runtime的dialog管理类        mDialogManager = new XWalkDialogManager(mActivity);        //设置runtime更新的管理类,适用于Shared Mode下搜索不到合适runtime的时候        mXWalkUpdater = new XWalkUpdater(this, mActivity, mDialogManager);        //初始化        XWalkLibraryLoader.prepareToInit(mActivity);    }    //activity的onresume状态下调用的方法    public void onResume() {        if (mIsInitializing || mIsXWalkReady) return;        mIsInitializing = true;        if (XWalkLibraryLoader.isLibraryReady()) {            //激活runtime            XWalkLibraryLoader.startActivate(this, mActivity);        } else {            //解压runtime            XWalkLibraryLoader.startDecompress(this, mActivity);        }    }}

上面就是启动XWalkView的两个主要方法,大概的意思明白,具体的实现就不说了,我已经看不懂了,感兴趣的话可以自己去github上看。

    /**     * Prepare to start initializing before all other procedures.     *     * <p>This method must be invoked on the UI thread.     */    public static void prepareToInit(Activity activity) {        XWalkCoreWrapper.handlePreInit(activity.getClass().getName());    }    /**     * Return true if the Crosswalk runtime has already been initialized successfully either in     * embedded mode or shared mode, false otherwise.     */    public static boolean isLibraryReady() {        return XWalkCoreWrapper.getInstance() != null;    }/**     * Start activating the Crosswalk runtime in background. The activation is not cancelable.     *     * <p>This method must be invoked on the UI thread.     *     * @param listener The {@link ActivateListener} to use     */    public static void startActivate(ActivateListener listener, Activity activity) {        new ActivateTask(listener, activity).execute();    }/**     * Start decompressing the Crosswalk runtime in background     *     * <p>This method must be invoked on the UI thread.     *     * @param listener The {@link DecompressListener} to use     * @param context The context of the package that holds the compressed Crosswalk runtime     */    public static void startDecompress(DecompressListener listener, Context context) {        new DecompressTask(listener, context).execute();    }

上面可以看出既然XWalkActivity是这么实现了,那完全可以不继承它来单独实现

public class MainActivity extends Activity  {    private XWalkView walkView;    private final static float ANIMATION_FACTOR = 0.6f;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mActivityDelegate  = new XWalkActivityDelegate(this, cancelCommand, completeCommand);        LinearLayout linearLayout = new LinearLayout(this);        walkView = new XWalkView(this, this);        linearLayout.addView(walkView, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));        setContentView(linearLayout);        WebView view = new WebView(this);        view.setWebViewClient(new WebViewClient());        view.setWebChromeClient(new WebChromeClient());    }     @Override    protected void onResume() {        super.onResume();        mActivityDelegate.onResume();    }    Runnable cancelCommand = new Runnable() {         @Override         public void run() {             finish();         }     };     Runnable completeCommand = new Runnable() {         @Override         public void run() {             onXWalkReady();         }        private void onXWalkReady() {            // TODO Auto-generated method stub            walkView.load("http://csdn.net", null);        }     };

个人理解,不喜勿喷,哈哈

4 1