浅谈Cordova框架的一些理解

前言

由于工做缘由,最近须要研究Cordova框架,看了其中的源码和实现方式,当场在看的时候立刻能理解,可是过后再回去看相关源码时候却发现以前理解的内容又忘记了,又不得不从新开始看,因此总以为须要记录下来,这样也代表以前也是学习过,俗话说「好记性不如烂笔头 」,想必也是体现了笔记的重要性。javascript

目录

  • 为什么要用Cordovacss

  • 什么是Cordovahtml

  • Cordova中UML类图前端

  • Cordova实现机制html5

  • 小结java

为什么要用Cordova

随着移动互联网的发展,如今基本是APP满天飞,不知在你们印象中,若是我去下载一个APP,那么基本都能看到有两种选择,一种是Android版本,一种是IOS版本。无论个人手机是哪一种操做系统,安装完一个APP以后,后续若是有新的版本发布的时候,我还必须去更新,才能享用新版本里的功能,好比我装了“京东”这个APP,前几天正好碰到“618”活动,那么以前一个月APP Store就提醒我要去更新最新的APP版本,以避免错过“618”活动中新的功能使用。相对来讲IOS系统更新APP比起Android系统用户体验会好一点,可是仍是稍显麻烦点。android

那么有没有一种方式,我只须要开发一个APP版本,就能去适配通用的操做系统呢,不只能够适配Android、IOS,还能够适配其余系统,好比Windows Phone、 Palm WebOS、Blackberry等等。有,Cordova就能提供这种能力,代码写一次,就能处处运行,跟咱们平常开发网站效果同样,基于写Web APP,根据输出平台要求不一样,就能提供不一样类型的安装包。Cordova其设计初衷是但愿用户群体可以经过跨平台开发的方法下降原生开发的成本,为此,开发人员须要安装原生开发环境,配置工程,使用HTML5CSS3JS和原生SDK生成应用。css3

什么是Cordova

官网定义以下:web

Apache Cordova是一个开源的移动开发框架。容许你用标准的web技术-HTML5,CSS3和JavaScript作跨平台开发。 应用在每一个平台的具体执行被封装了起来,并依靠符合标准的API绑定去访问每一个设备的功能,好比说:传感器、数据、网络状态等。apache

使用Apache Cordova的人群:

  • 移动应用开发者,想扩展一个应用的使用平台,而不经过每一个平台的语言和工具集从新实现。

  • web开发者,想包装部署本身的web App将其分发到各个应用商店门户。

  • 移动应用开发者,有兴趣混合原生应用组建和一个WebView(一个特别的浏览器窗口) 能够接触设备A级PI,或者你想开发一个原生和WebView组件之间的插件接口。

架构图

框架图

从图中,咱们能够看到它提供了Web APP、WebView、Cordova Plugins。

Web APP

这是存放应用程序代码的地方,体现是你的具体业务逻辑模块。应用的实现是经过web页面,默认的本地文件名称是是index.html,这个本地文件应用CSS,JavaScript,图片,媒体文件和其余运行须要的资源。应用执行在原生应用包装的WebView中,这个原生应用是你分发到app stores中的。

WebView

Cordova启用的WebView能够给应用提供完整用户访问界面。在一些平台中,他也能够做为一个组件给大的、混合应用,这些应用混合和Webview和原生的应用组件。

Cordova Plugins

插件是Cordova生态系统的重要组成部分。他提供了Cordova和原生组件相互通讯的接口并绑定到了标准的设备API上,这使你可以经过JavaScript调用原生代码。

Cordova中UML类图

其实Cordova经过命令来添加项目的,可是能够选择哪一个平台去编译,好比咱们添加Android平台,在Android默认mainActivity类,咱们能够看到它其实继承CordovaActivity类,一切初始化条件是从loadUrl方法开始。

package com.example.hello;

import android.os.Bundle;
import org.apache.cordova.*;

public class MainActivity extends CordovaActivity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // enable Cordova apps to be started in the background
        Bundle extras = getIntent().getExtras();
        if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
            moveTaskToBack(true);
        }

        // Set by <content src="index.html" /> in config.xml
        loadUrl(launchUrl);
    }
}

进而获得如下UML类图

UML图

简单分析下,CordovaActivity内依赖一个WebView类,一个Preferences类,一个CordovaInterface接口,并同时初始化一些配置信息。WebView具体实现是由CordovaWebViewImpl类,CordovaInterface接口具体实现是由CordovaInterfaceImpl类实现。

CordovaWebViewImpl是核心类,里面会把一些插件能力初始化,用一个PluginManager进行管理,包含一个引擎类—CordovaWebViewEngine,这个引擎是经过反射的方式建立,自身初始化的时候把NativeToJsMessageQueue关联起来,里面包含着以Js字符串为主的双向链表,把每次从前端经过JS代码存储起来,而后经过绑定的桥接方式Pop出到相应的Native代码中去。

最终实现由SystemWebViewEngine类来对Android系统中WebView控件进行二次包装,这个类的初始化是在CordovaWebViewImpl类反射建立,相关插件和消息传递也是经过SystemWebViewEngine进行绑定。

Cordova实现机制

当Cordova框架启动时候,CordovaActivity类中的onCreate方法调用loadUrl方法便可启动,最终在SystemWebViewEngine类的init方法中,会调用webView的addJavascriptInterface方法,看到这个方法是否是很熟悉,咱们常规让webView支持开启JavaScript调用接口也是使用此特性。

private static void exposeJsInterface(WebView webView, CordovaBridge bridge) {
        if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) {
            LOG.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old.");
            // Bug being that Java Strings do not get converted to JS strings automatically.
            // This isn't hard to work-around on the JS side, but it's easier to just
            // use the prompt bridge instead.
            return;
        }
        SystemExposedJsApi exposedJsApi = new SystemExposedJsApi(bridge);
        webView.addJavascriptInterface(exposedJsApi, "_cordovaNative");
    }

那么SystemExposedJsApi类new出来的对象就等同抛出“_cordovaNative”对象给JS端调用,进去看下SystemExposedJsApi类包含哪些内容,

class SystemExposedJsApi implements ExposedJsApi {
    private final CordovaBridge bridge;

    SystemExposedJsApi(CordovaBridge bridge) {
        this.bridge = bridge;
    }

    @JavascriptInterface
    public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
        return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);
    }

    @JavascriptInterface
    public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
        bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);
    }

    @JavascriptInterface
    public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
        return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);
    }
}

其中最关键是exec方法,其中bridgeSecret表明选择哪一个桥接方式,service通常对应着你本地Java文件类名,action表明java文件中方法名,callbackId表明回调函数的Id,也就是句柄,arguments表明传递的参数。看出其中设计思想了没,service每每是本地能力集的类名,好比web端想调用相机,通常起个Camera类表明这个相机服务类,而后在这个类中定义方法,也就是action参数,这个action名称可扩展,由于方法名称可各类各样,适合自定义功能扩展。

SystemExposedJsApi对象初始化

在建立SystemExposedJsApi时须要CordovaBridge类,CordovaBridge类初始化须要CordovaWebView的PluginManager对象和NativeToJsMessageQueue对象。由于全部的JS端与Android native代码交互都是经过SystemExposedJsApi对象的exec方法。在exec方法中执行PluginManager的exec方法,PluginManager去查找具体的Plugin并实例化而后再执行Plugin的execute方法,并根据同步标识判断是同步返回给JS消息仍是异步。由NativeToJsMessageQueue统一管理返回给JS的消息。

什么时候加载Plugin,如何加载

Cordova中很重要的部分是插件,Cordova在启动每一个Activity的时候都会将配置文件中的全部plugin加载到PluginManager,在第一次loadUrl方法时,就会去初始化PluginManager并加载plugin,PluginManager在加载plugin的时候并非立刻实例化plugin对象,而是只是将plugin的Class名字保存到一个hashmap中,用service名字做为key值。当JS端经过JavascriptInterface接口的SystemExposedJsApi对象请求Android时,PluginManager会从hashmap中查找到plugin,若是该plugin还未实例化,利用java反射机制实例化该plugin,并执行plugin的execute方法。

Cordova的数据返回

Cordova中经过exec()函数请求android插件,数据的返回可同步也能够异步于exec()函数的请求。在开发android插件的时候能够重写public boolean isSynch(String action)方法来决定是同步仍是异步。Cordova在android端使用了一个队列(NativeToJsMessageQueue)来专门管理返回给JS的数据。

1,同步
Cordova在执行完exec()后,android会立刻返回数据,但不必定就是该次请求的数据,多是前面某次请求的数据;由于当exec()请求的插件是容许同步返回数据的状况下,Cordova也是从NativeToJsMessageQueue队列头pop头数据并返回。而后再根据callbackID反向查找某个JS请求,并将数据返回给该请求的success函数。
2,异步
Cordova在执行完exec()后并不会同步获得一个返回数据。Cordova在执行exec()的同时启动了一个XMLHttpRequest对象方式或者prompt()函数方式的循环函数来不停的去获取NativeToJsMessageQueue队列中的数据,并根据callbackID反向查找到相对应的JS请求,并将该数据交给success函数。

webView.sendJavascript 发送到js队列,onNativeToJsMessageAvailable 负责执行js.

Native 调用 JS 执行方式有三种实现 LoadUrlBridgeMode、 OnlineEventsBridgeMode、PrivateApiBridgeMode

一、webView.sendJavascript 发送js方法到JS队列

二、onJsPrompt 方法拦截,获取调用方式

  • 若是是gap_bridge_mode,则执行 appView.exposedJsApi.setNativeToJsBridgeMode(Integer.parseInt(message));
  • 若是是gap_poll, 则执行 appView.exposedJsApi.retrieveJsMessages("1".equals(message));

三、调用setBridgeMode 方法调用onNativeToJsMessageAvailable 执行javascript调用

小结

总的来讲,使用Cordova框架开发优缺点很明显。

优势:

  • 跨平台,开发简单,学习成本低
  • 框架多,插件多,可自定义插件
  • 发展最先,社区资源丰富,

缺点:

  • WebView性能低下时,用户体验差,反应慢
  • 毕竟是老外的框架,中文文档资源少
  • 调试不方便,既不像原生那么好调试,也不像纯web那种调试

最后想说一句,不管是选择原生模式开发仍是Hybrid混合模式,必定是要基于具体业务场景去选择,而不是盲目和绝对化以为哪一种模式好就不作分析想固然的去选择,仍是有选择的结合,要知道应用之美在于药到病除。

阅读扩展

源于对掌握的Android开发基础点进行整理,罗列下已经总结的文章,从中能够看到技术积累的过程。
1,Android系统简介
2,ProGuard代码混淆
3,讲讲Handler+Looper+MessageQueue关系
4,Android图片加载库理解
5,谈谈Android运行时权限理解
6,EventBus初理解
7,Android 常见工具类
8,对于Fragment的一些理解
9,Android 四大组件之 " Activity "
10,Android 四大组件之" Service "
11,Android 四大组件之“ BroadcastReceiver "
12,Android 四大组件之" ContentProvider "
13,讲讲 Android 事件拦截机制
14,Android 动画的理解
15,Android 生命周期和启动模式
16,Android IPC 机制
17,View 的事件体系
18,View 的工做原理
19,理解 Window 和 WindowManager
20,Activity 启动过程分析
21,Service 启动过程分析
22,Android 性能优化
23,Android 消息机制
24,Android Bitmap相关
25,Android 线程和线程池
26,Android 中的 Drawable 和动画
27,RecylerView 中的装饰者模式
28,Android 触摸事件机制
29,Android 事件机制应用
30,Cordova 框架的一些理解
31,有关 Android 插件化思考
32,开发人员必备技能——单元测试

相关文章
相关标签/搜索