1. cordova介绍

1.1. cordova历史

Cordova是PhoneGap贡献给Apache后的开源项目,是从 PhoneGap中抽离出的核心代码,是驱动PhoneGap的核心引擎。有点类似Webkit和Google Chrome的关系。渊源就是:早在2011年10月,Adobe收购了Nitobi Software和它的PhoneGap产品,然后宣布这个移动Web开发框架将会继续开源,并把它提交到Apache Incubator,以便完全接受ASF的管治。当然,由于Adobe拥有了PhoneGap商标,所以开源组织的这个PhoneGap v2.0版产品就更名为Apache Cordova。

1.2. cordova功能

Apache Cordova是一个开源的移动开发框架,它支持使用标准的Web开发技术(HTML5、CSS3和JavaScript)开发跨平台的移动端应用。如果需要访问各平台本地化的功能,如摄像头、网络、传感器……,可以通过使用插件(plugin)来完成。

1.3. cordova架构

cordova架构示意图如下:

 

Web App层是开发人员编写代码的主要地方,应用程序以网页的形式呈现,在一个index.html的本地页面文件中引用所需要的各种Web资源,如CSS、JavaScript、图像、影音文件等。应用程序的配置保存在config.xml文件中。

WebView层用来呈现用户界面,即web页面的展现。例如,在android平台是通过WebView控件实现web页面的呈现。

Plugins主要用于在JavaScript代码中调用各平台native的功能。Cordova项目已经包含一些核心的plugin,如电池、摄像头、通讯录等。开发人员也可以开发自定义的plugin,来实现所需要的功能。

Cordova预先帮我们预先封装了各种mobile os上最常用的本地api调用,然后以统一的Javascript api形式提供给webapp开发者调用。(注:cordova还提供另外一种Hybird即混合开发模式,这个后面有时间再说。)对于webapp的开发者来说,无需关注系统底层调用实现细节,也就实现了所谓的“跨平台”。实际上,各平台涉及到本地能力的调用,以插件形式被封装了。(每个插件的实现实际上还是Native模式)。

笔者比较感兴趣的一点是JS和Native是如何实现互调的(各平台有差别,这里先研究Android的,重点是JS如何实现对于Native的调用),网上实际上有比较多的文章在解释这些,看下来感觉总不是太清晰,于是乎,你懂的,我直接对着github上Cordova-Android源码来了一番研究。

先把研究的结果共享出来:Cordova-Android是通过addJavascriptInterface(Android Webview的API)和JS Prompt这两种方式来实现JS对于Native API的调用。

具体介绍这两种方式前,我们先来看一个Cordova-Android框架中的一个关键类:CordovaActivity.java
该类继承了Android Activty类,实际上是Cordova-Android的Launcher Activity,也就是启动入口activity。我们通过一张图来描述下它干了哪些事:
CordovaActivity调用时序图
应用启动后,核心干了两件事:读取config.xml和loadUrl。这个loadUrl实际上就是加载webapp的启动页(默认是index.html)

addJavascriptInterface方式:
addJavascriptInterface方式时序图
看了上面的图,再看下其中的一个核心类的代码,就啥都明白啦。
SystemExposedJsApi.java
我们直接看代码,很短:

/*
       Licensed to the Apache Software Foundation (ASF) under one
       or more contributor license agreements.  See the NOTICE file
       distributed with this work for additional information
       regarding copyright ownership.  The ASF licenses this file
       to you under the Apache License, Version 2.0 (the
       "License"); you may not use this file except in compliance
       with the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing,
       software distributed under the License is distributed on an
       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
       KIND, either express or implied.  See the License for the
       specific language governing permissions and limitations
       under the License.
*/
package org.apache.cordova.engine;

import android.webkit.JavascriptInterface;

import org.apache.cordova.CordovaBridge;
import org.apache.cordova.ExposedJsApi;
import org.json.JSONException;

/**
 * Contains APIs that the JS can call. All functions in here should also have
 * an equivalent entry in CordovaChromeClient.java, and be added to
 * cordova-js/lib/android/plugin/android/promptbasednativeapi.js
 */
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);
    }
}

@JavascriptInterface暴露方法给JS,这里的exec接口方法实际上就实现了从JS到Native调用的“桥”。

至此,我们对于addJavscriptInterface这种方式的调用过程就搞清楚了。对于JS Prompt这种方式,原理上大同小异。实际上Cordova在SystemWebChromeClient.java这个类中重载了OnJsPrompt方法。实际的调用过程如下:webapp->prompt()->OnJsPrompt()->Native()。

分析下这个过程的反面,也就是从Native端->JS端,Cordova是如何处理的。

老习惯,我们先看一段代码:
exec.js

nativeToJsModes = {
        // Polls for messages using the JS->Native bridge.
        POLLING: 0,
        // For LOAD_URL to be viable, it would need to have a work-around for
        // the bug where the soft-keyboard gets dismissed when a message is sent.
        LOAD_URL: 1,
        // For the ONLINE_EVENT to be viable, it would need to intercept all event
        // listeners (both through addEventListener and window.ononline) as well
        // as set the navigator property itself.
        ONLINE_EVENT: 2
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

可以看到Cordova实现了3中模式:POLLING、LOAD_URL和ONLINE_EVENT。笔者这里重点分析了第一种,也就是POLLING模式,后两种有机会再做深入研究。下图大致描述了这个过程。

这里写图片描述

总体来说,过程如下:
1、JS端调用Native API后,如果当前调用消息未处理完成,每隔50ms取一次消息队列,直到本次调用的消息结束;
2、Native端的插件同样维护了一个消息队列;
3、JS端通过Native端暴露的retrieveMessages接口来实现消息的拉取;

另外,通过源代码我们可以大致分析下Cordova的JS和Native两端的消息格式大致协议:

1、* 号的消息表示当前Native端仍然有待处理消息,JS端会再拉取一次消息;
2、消息内容的第一个字符如果为S表示调用成功,F表示调用失败;
其他的有兴趣的可以对照代码再做分析。

android studio打开工程

工程建立并添加android平台后,可以在/platform/android/目录下找到cordove创建的android工程。

注意:android工程是临时的,cordova会覆盖该目录下的文件。工程开发主要工作是开发工程目录下的www目录、config.xml文件,以及自定义的plugin,而不是修改该android目录下的内容。

原生移动app框架inoic功能研究

本篇只侧重框架提供的功能和能力的研究,请关注后续实际部署使用体验。

一、inoic是什么?

inoic是一个可以使用Web技术以hybird方式开发移动app的前端开源框架

二、inoic框架特点

1.利用web技术开发移动app。

ionic提供了一套HTML、CSS、JS的类库。我们可以使用其提供的CSS组件和工具构建具有良好交互性的app。

2.关注性能

ionic框架以更少的DOM操作,零JQuery和硬件加速过度,在现代最新的移动设备上性能表现优越。

3.Angular

ionic基于Angular创建了一套最合开发丰富健壮的app的强大SDK。ionic与Angular完美融合,提供了适合专业化app开发的核心架构。

4.关注原生

ionic对当下流行的原生移动开发SDKs进行抽象,并利用ApacheCordova或者Phonegap编译,使开发人员只关注自己的代码,而不用针对IOS和Android开发多套原生app。可以实现开发一次,任意部署。

5.UI设计精美

UI干净、简单、实用。其提供了流行的移动组件、结构、交互规范、漂亮的皮肤。

6.功能强大的CLI

一个命令可以完成创建、构建、测试、部署ionic app到任意平台。

7.学习有趣

只需要学习HTML、CSS、JS、AngularJS。

8.提供专业原型工具

使用Creator可以通过简单的拖拽创建真正的ionicapp。其可以导出干净、立即可用的ionic代码,甚至是IOS和Android二进制文件。网站提供了在线体验,但是可能是国内网络的原因,登录后无法进行操作。

9.提供了启动、构建、测试和部署的专业化工具Lab,但是打开页面无法进行下载。

10.提供了一个应用市场,可以上传app和插件,但是市场页面没有东西,没有活力。

三、ionic依赖的底层技术

ionic仅仅是开发hibrid移动app的前端框架,其依赖一些底层的技术框架

1.其依赖apacheCordova或者Phonegap提供的原生SDK访问能力,并依赖其将ionicapp编译部署。

2.Sass,其核心css是使用Sass编写,可以利用Sass对Css功能的增强能力,以及灵活易于维护的能力,

同时保障了ionic框架的css扩展能力。

3.Angularjs,其通过angularjs对apacheCordova提供的原生SDK接口进行封装(称为ngAngular),同时其也依赖angularjs提供的动画、触控系统、ui交互功能,同时angularjs的核心架构也是基于angularjs的MVC模式构建的。

四、浏览器兼容性

ionic重点关注原生或者hibird移动app,而不是移动web站点。其更关注特定平台提供的WebView控件的兼容性。对于1.2.4版本的ionic支持IOS7+和Android4.1+的UIWebView。

五、开源协议

基于MIT协议,可以免费用于个人和商业项目。

六、技术支撑

ionic是一个叫Drifty公司的三个人员开发的,该公司还有CodiqaJetstrap两个移动产品。哦盖过了

七、ionic提供的CSS组件

框架提供了丰富多样的CSS组件包括Header、Content、Footer、Buttons、List、Cards、Forms、Toggle、CheckBox、RadioButton、Grid等

八、平台相关定制

1.平台相关类

ionic提供了平台设备类和平台OS版本类以方便我们修改或者扩展现有样式。ionic会在app启动的时候在body里添加相关的平台类。

平台设备相关类如下

2.使用CSS直接自定义平台相关样式

针对android自定义bar-header的文本样式。

.platform-android .bar-header {
  text-transform: uppercase;  
}

3.使angular直接自定义平台相关样式
ionic通过ionic.Platform暴露平台相关类,我们可以在控制器中获取平台类
.controller('AppCtrl', function($scope) {
  $scope.platform = ionic.Platform.platform();
})

我们也可以在html元素中使用平台类控制元素的样式,比如控制标签在android的时候显示一种样式,其他系统的时候显示另外一种样式。
<ion-tabs class="tabs-stable" ng-class="{'tabs-positive': platform == 'android', 'tabs-icon-top': platform != 'android'}">
  <!-- ion-tab directives go here -->
</ion-tabs>

根据平台加载不同模板

复制代码

.state('tab', {
  url: "/tab",
  abstract: true,
  controller: 'AppCtrl',
  templateUrl: function() {
    if (ionic.Platform.isAndroid()) {
        return  "templates/home-android.html";
    }
    return "templates/home.html";
  }
})

复制代码

4.使用merge文件夹加载不同的文件

复制代码

merges/
    ios/
        index.html
        css/
            platform.css
        js/
            app.js
    android/
        index.html
        css/
            platform.css
        js/
            app.js

复制代码

九、JS组件

ionic提供的css组件是通过基于angular实现的control实现用户交互功能的。可以简单看下list的用法

复制代码

<ion-list ng-controller="MyCtrl"
          show-delete="shouldShowDelete"
          show-reorder="shouldShowReorder"
          can-swipe="listCanSwipe">
  <ion-item ng-repeat="item in items"
            class="item-thumbnail-left">

    <img ng-src="{{item.img}}">
    <h2>{{item.title}}</h2>
    <p>{{item.description}}</p>
    <ion-option-button class="button-positive"
                       ng-click="share(item)">
      Share
    </ion-option-button>
    <ion-option-button class="button-assertive"
                       ng-click="edit(item)">
      Edit
    </ion-option-button>
    <ion-delete-button class="ion-minus-circled"
                       ng-click="items.splice($index, 1)">
    </ion-delete-button>
    <ion-reorder-button class="ion-navicon"
                        on-reorder="reorderItem(item, $fromIndex, $toIndex)">
    </ion-reorder-button>

  </ion-item>
</ion-list>

复制代码

app.controller('MyCtrl', function($scope) {
 $scope.shouldShowDelete = false;
 $scope.shouldShowReorder = false;
 $scope.listCanSwipe = true
});

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐