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