Android Html5开发(二)-Cordova


Android Html5开发()-Cordova


本文介绍Android Html的开发框架Cordova

目录

.Cordova简介

.Cordova开发环境搭建

.添加Cordova插件

.添加自定义插件

.JavaScript调用Android代码的过程

.Android Html5混合开发的性能

.Cordova简介

介绍Cordova前需要先介绍下PhoneGap.

PhoneGap是一个用基于HTMLCSSJavaScript的,创建移动跨平台移动应用程序

的快速开发平台。它使开发者能够利用iPhoneAndroidPalmSymbian,WP7,

WP8,BadaBlackberry智能手机的核心功能——包括地理定位,加速器,联系人,声

音和振动等,此外PhoneGap拥有丰富的插件,可以调用。

业界很多主流的移动开发框架均源于PhoneGap。较著名的有WorklightappMobi

WeX5等;其中WeX5为国内打造,完全Apache开源,在融合Phonegap的基础上,

做了深度优化,具备接近Native app的性能,同时开发便捷性也较好。

PhoneGapCordova的关系:

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

也就是说PhoneGapAdobe的商业产品,CordovaApache的开源项目,我们在使用时应当使用Cordova.

.安装Cordova

Cordova 官网

http://cordova.apache.org/

安装Cordova开发环境

http://cordova.apache.org/#getstarted

在安装Cordova前需要先安装Node.js NPM

安装命令

npm install -g cordova

创建你的第一个应用

http://cordova.apache.org/docs/en/6.x/guide/cli/index.html

1. cordova create hello com.example.hello HelloWorld

2. cd hello

3. cordova platform add android --save

添加Android platfrom之后可以用Eclipse 导入hello/platforms/android下的工程

一个是CordovaLib ,一个是MainActivity.

CordovaLib Cordova框架的源码.

如图:
















 

CordovaLib 提供了JavaScriptAndroid之间相互调用的框架.

在第一个Cordova HelloWorld程序中,MainActivity代码如下




 

 

 

 

 

 

 

 

 

 

加载的launchUrl,assets/www/index.html.

Cordova 是基于插件开发的,Android提供给JavaScript调用的API应该已插件的形式提供.Cordova 本身已经拥有丰富的插件.下面介绍如果添加Cordova 插件

.添加Cordova插件

这里以添加contacts插件为例

执行:cordova plugin add cordova-plugin-contacts
就可以添加cordova-plugin-contacts插件
Android部分
添加之后会在MainActiviy 里面增加如下代码:









 

这部分就是通讯录插件Android端所有的代码.其中ContactManager继承了

CordovaPlugin,并重写了下面方法.

publicboolean execute(String action, CordovaArgs args, CallbackContext callbackContext)

/res/xml/config.xml文件中增加了

<featurename="Contacts">

<paramname="android-package"value="org.apache.cordova.contacts.ContactManager"/>

</feature>

用于注册 Contacts插件

feature name="Contacts"是定义js通过下面方法调用Android接口时传入的

The plugin's JavaScript interface uses the cordova.exec method as follows:

exec(<successFunction>,<failFunction>,<service>,<action>,[<args>]);

service

<paramname="android-package"value="org.apache.cordova.contacts.ContactManager"/>

ContactManager类的全名

JavaScript部分:

/assets/www/plugins目录下增加了一个cordova-plugin-contacts文件夹存放Contacts插件所有的js代码











 

/assets/www/cordova_plugins.js 里面注册该模块







 

其中

"clobbers": [

"navigator.contacts"

]

声明了

contacts.js 里面定义的contacts对象可以通过navigator.contacts来访问.

使用示例:

/assets/www/js/index.js onDeviceReady 方法里面加入如下代码,调用

查找所有联系人的方法.

function onSuccess(contacts) {

for (var i = 0; i < contacts.length; i++) {

console.log(contacts[i].displayName);

}

};

function onError(contactError) {

alert('onError!');

};

// find all contacts

var options = new ContactFindOptions();

options.filter = "";

options.multiple = true;

var filter = ["displayName", "addresses"];

navigator.contacts.find(filter, onSuccess, onError, options);

参考:

http://cordova.apache.org/docs/en/latest/cordova-plugin-contacts/index.html

 

.添加自定义插件

这里以添加一个EchoPlugin插件为例

Android:

1.编写 EchoPlugin继承 CordovaPlugin并重写execute方法

publicclass EchoPlugin extends CordovaPlugin {

 

privatestaticfinal String TAG = EchoPlugin.class.getSimpleName();


@Override

publicvoid initialize(CordovaInterface cordova, CordovaWebView webView) {

super.initialize(cordova, webView);

// your init code here

Log.e(TAG, "initialize ");

}

 

@Override

publicboolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {

Log.e(TAG, "action == " + action);

Log.e(TAG, "args == " + args);

Log.e(TAG, "callbackContext == " + callbackContext);

if ("echo".equals(action)) {

callbackContext.success(args + " from android ");

returntrue;

}

returnfalse; // Returning false results in a "MethodNotFound" error.

}


}

2./res/xml/config.xml文件中增加:

<featurename="Echo">

<paramname="android-package"value="com.example.echo.EchoPlugin"/>

</feature>

注册EchoPlugin插件,这样就完成了Android端的插件开发

JavaScript:

如果只想调用EchoPlugin提供的方法,执行下面代码即可

cordova.exec(function(msg) {

console.log(msg);

}, function(err) {

console.log("Nothing to echo.'" + err);

}, "Echo", "echo", []);

service名为Echo,action echo

但实际使用中我们应该在js端也实现模块化.

1./assets/www/plugins 目录下新建

com-example-echo 目录,并新建一个echo.js 文件

里面的代码如下:

//定义一个id com-example-echo.echo的模块

//模块注册,加载 参照 http://rensanning.iteye.com/blog/2047324

cordova.define("com-example-echo.echo", function(require, exports, module) {

//加载cordova/exec模块

var exec = require('cordova/exec');

//定义一个Echo 对象

var Echo = {

//Echo对象定义一个echo方法

echo: function(msg) {

console.log("ech0");

exec(function(msg) {

console.log(msg);

}, function(err) {

console.log("Nothing to echo.'" + err);

}, "Echo", "echo", [msg]);

}

};

//模块的输出为Echo对象

module.exports = Echo;

});

这段代码的含义是定义一个id为”com-example-echo.echo”的模块,模块的输出时一个Echo的对象.

然后在/assets/www/cordova_plugins.js 里面 注册该模块

{

"file": "plugins/com-example-echo/echo.js",

"id": "com-example-echo.echo",

"pluginId": "com-example-echo",

"clobbers": [

"navigator.Echo"

]

}

这样就可以通过 navigator.Echo来调用该方法.

调用示例如下:

/assets/www/js/index.jsonDeviceReady方法里面加入

navigator.Echo.echo('hello word');

即可.

参考

http://cordova.apache.org/docs/en/latest/guide/platforms/android/plugin.html

.JavaScript调用Android API的内部执行过程

这里就以调用 navigator.Echo.echo('hello word')方法为例,首先对代码进行一下剖析

1)调用navigator.Echo.echo('hello word')方法,实际执行的是下面代码

cordova.exec(function(msg) {

console.log(msg);

}, function(err) {

console.log("Nothing to echo.'" + err);

}, "Echo", "echo", []);

查看cordova.js 源码,可以看到

modulemapper.clobbers('cordova/exec', 'cordova.exec');

modulemapper.clobbers('cordova/exec', 'Cordova.exec');

cordova.exec的定义如下

define("cordova/exec", function(require, exports, module) {

/

module.exports = androidExec;

});

也就是说cordova.exec指向的是 androidExec 方法,

androidExec的定义如下:

function androidExec(success, fail, service, action, args)

参数说明:

success:成功回调

fail:失败回调

service:插件对应的 service,对应EchoPlugin中的Echo,用于从插件列表中找到EchoPlugin这个插件

action:执行的哪个方法,对应EchoPlugin中的echo;

args:参数,是一个JSONArray;

从该方法可以看出JS调用Android Native接口都是通过回调异步调用的.

androidExec执行时调用的是

var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);

nativeApiProvider.get()指向的是下面方法

define("cordova/android/promptbasednativeapi", function(require, exports, module) {

/**

* Implements the API of ExposedJsApi.java, but uses prompt() to communicate.

* This is used pre-JellyBean, where addJavascriptInterface() is disabled.

*/


module.exports = {

exec: function(bridgeSecret, service, action, callbackId, argsJson) {

return prompt(argsJson, 'gap:' + JSON.stringify([bridgeSecret, service, action, callbackId]));

},

setNativeToJsBridgeMode: function(bridgeSecret, value) {

prompt(value, 'gap_bridge_mode:' + bridgeSecret);

},

retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {

return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);

}

};

});

最终调用的是:

prompt(argsJson, 'gap:' + JSON.stringify([bridgeSecret, service, action, callbackId]));

promptWindow 对象的一个方法,用于显示可提示用户输入的对话框。

参照:http://www.w3school.com.cn/jsref/dom_obj_window.asp

Android端调用该方法会回调WebViewWebChromeClient

publicboolean onJsPrompt(WebView view, String origin, String message, String defaultValue, final JsPromptResult result);

方法.

查看CordovaLib源码,可以看到在SystemWebChromeClient里面对该方法进行了重写

publicboolean onJsPrompt(WebView view, String origin, String message, String defaultValue, final JsPromptResult result) {

// Unlike the @JavascriptInterface bridge, this method is always called on the UI thread.

Log.d(TAG, "onJsPrompt " + origin + " message == " + message);

String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue);

if (handledRet != null) {

result.confirm(handledRet);

} else {

dialogsHelper.showPrompt(message, defaultValue, new CordovaDialogsHelper.Result() {

@Override

publicvoid gotResult(booleansuccess, String value) {

if (success) {

result.confirm(value);

} else {

result.cancel();

}

}

});

}

returntrue;

}

执行调用的关键代码是

String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue);

promptOnJsPrompt中关键代码是

String r = jsExec(bridgeSecret, service, action, callbackId, message);

jsExec中关键代码是

pluginManager.exec(service, action, callbackId, arguments);

exec

//根据service 获取对应插件

CordovaPlugin plugin = getPlugin(service);

//执行对应插件的execute 方法

booleanwasValidAction = plugin.execute(action, rawArgs, callbackContext);


这也就是为什么编写插件时需要继承 CordovaPlugin,并重写 execute方法.


@Override

publicboolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {

Log.e(TAG, "action == " + action);

Log.e(TAG, "args == " + args);

Log.e(TAG, "callbackContext == " + callbackContext);

if ("echo".equals(action)) {

callbackContext.success(args + " from android ");

// if fail

callbackContext.error("err ");

returntrue;

}

returnfalse; // Returning false results in a "MethodNotFound" error.

}


execute 方法执行完后,通过 callbackContext.success()或者callbackContext.error()将结果回调给JS.

查看源码,可以知道, callbackContext最终是通过loadUrl的方式,将结果回调给JS.

String js = queue.popAndEncodeAsJs();

if (js != null) {

engine.loadUrl("javascript:" + js, false);

}

 

 

.Android Html5混合开发的性能

 

这里只截取运行一个Android Hello word程序和Android +HTML5混合开发时,程序运行后的线程截图

 

1.Android Hello word,程序运行后会有18个线程


 



 



 



 

 

 

 

 

 

 

2.不使用cordova,直接使用webiew,程序允许后会有31个线程

 

 



 



 



 



 



 



 

3.使用cordova框架,程序允许后会有36个线程

 



 



 



 



 



 



 



 



 



 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM