導(dǎo)語
Apache Cordova是一個開源的移動開發(fā)框架。允許你用標準的web技術(shù)-HTML5,CSS3和JavaScript做跨平臺開發(fā)。 應(yīng)用在每個平臺的具體執(zhí)行被封裝了起來,并依靠符合標準的API綁定去訪問每個設(shè)備的功能,比如說:傳感器、數(shù)據(jù)、網(wǎng)絡(luò)狀態(tài)等。
使用Apache Cordova的人群:
移動應(yīng)用開發(fā)者,想擴展一個應(yīng)用的使用平臺,而不通過每個平臺的語言和工具集重新實現(xiàn)。
web開發(fā)者,想包裝部署自己的web App將其分發(fā)到各個應(yīng)用商店門戶。
移動應(yīng)用開發(fā)者,有興趣混合原生應(yīng)用組建和一個WebView(一個特別的瀏覽器窗口) 可以接觸設(shè)備A級PI,或者你想開發(fā)一個原生和WebView組件之間的插件接口。
一、安裝Cordova環(huán)境
1.下載安裝Node.js node.js下載地址,這樣就可以使用npm命令。
2.在終端中使用以下命令安裝cordova。
sudo npm install -g cordova
其中g(shù)表示全局安裝。
3.安裝完成后運行一下命令查看cordova版本,若出現(xiàn)版本號則說明安裝成功,我目前的版本號是8.0.0。
cordova -v
二、創(chuàng)建第一個Cordova工程,添加Android平臺并運行
1.在創(chuàng)建第一個cordova工程。選擇一個目錄例如桌面cd desktop
,運行以下命令創(chuàng)建一個cordova工程。
cordova create HelloCordova com.xxx
其中HelloCordova是項目名稱,com.xxx是包名。
2.運行之后會生成一個空項目,目錄如下:
3.進入工程根目錄下,添加平臺
Android:cordova platform add android
iOS:cordova platform add ios
添加完成之后會發(fā)現(xiàn)在platforms文件夾下生成了一個Android項目:
本文章主要介紹Android平臺,如不需要iOS平臺則可以不添加iOS。
4.在編譯項目之前應(yīng)該先檢測編譯環(huán)境是否滿足,在cordova項目根目錄下運行如下命令:
cordova requirements
運行后若環(huán)境滿足則會打印如下信息:
若不滿足則會提示缺少SDK配置或者jdk配置。
5.直接編譯運行:
cordova build
注意:若使用cordova build
則會編譯所有平臺,例如Android和iOS以及其他平臺會同時被編譯,若只想編譯其中一個平臺則運行cordova build android
,加上平臺后綴即可,單獨編譯iOS則cordova build ios
編譯Android項目時用到gradle編譯命令,所以運行前請保證環(huán)境變量已經(jīng)配置完畢。
編譯后將生成一個apk,可直接傳到手機上運行:
運行截圖:
這樣第一個Android的Cordova項目就運行起來了。
6.用Android Studio打開該項目跟打開普通Android項目一樣的:
三、Cordova插件調(diào)用
cordova官網(wǎng)提供了很多原生插件以供開發(fā)者使用,具體插件命令和作用可以查看這兩篇文章:
- https://cordova.apache.org/plugins/
-
cordova插件大全
下面使用相機插件為例演示調(diào)用官方插件完成拍照及選擇圖片:
1.在cordova工程根目錄或者Android目錄下運行一下命令
cordova plugin add cordova-plugin-camera
其中cordova plugin add 為添加插件操作,cordova-plugin-camera為插件名稱。
卸載插件命令為:
cordova plugin remove cordova-plugin-camera
等待控制臺打印
這樣一個相機插件就添加完成了,查看文件目錄可以發(fā)現(xiàn)添加該插件的同時都添加了哪些代碼文件:
2.在用cordova添加Android平臺時會在assets文件夾下創(chuàng)建www目錄來管理插件和js代碼:
首頁面的頁面編輯在index.html中:
邏輯編寫在js文件夾下的index.js文件中:
3.我們可以分別編輯這兩個文件,首先在index.html中編寫兩個按鈕
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
<!--<link rel="stylesheet" type="text/css" href="css/index.css">-->
<title>Hello World</title>
</head>
<body>
<div class="app">
<div class="line"><button id="take_picture">拍照</button></div>
<div class="line"><img id="picture" style="height: 200px;"></img></div>
<div class="line"><button id="open_photo">相冊選擇圖片</button></div>
<div class="line"><img id="photo" style="height: 200px;"></img></div>
</div>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>
注意cordova.js不能省略,且需放在其他js文件引用的第一行
4.編寫index.js
首先簡化代碼:
var app = {
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
onDeviceReady: function() {
},
};
app.initialize();
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
這一行是在初始化js文件的時候初始化cordova,不做改動。
初始化完成后會自動調(diào)用onDeviceReady: function() {},我們的點擊事件就在這里面寫:
var app = {
// Application Constructor
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
onDeviceReady: function() {
//調(diào)用原生拍照
document.getElementById("take_picture")
.onclick = function(){
navigator.camera.getPicture(onSuccess, onFail, {quality: 50,destinationType: Camera.DestinationType.DATA_URL});
function onSuccess(imageData) {
document.getElementById('picture')
.src = "data:image/jpeg;base64," + imageData;
}
function onFail(message) {
alert('Failed because: ' + message);
}
};
//調(diào)用原生選擇圖片
document.getElementById("open_photo")
.onclick = function(){
navigator.camera.getPicture(onSuccess, onFail, {quality: 50,destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY
});
function onSuccess(imageData) {
document.getElementById('photo')
.src = "data:image/jpeg;base64," + imageData;
};
function onFail(message) {
alert('Failed because: ' + message);
};
};
},
};
app.initialize();
需要說明的是:調(diào)用原生方法時需要傳入一個調(diào)用成功onSuccess()和一個調(diào)用失敗的方法onFail(),
Android返回結(jié)果時就會通過這兩個方法,這里返回的是base64格式圖片。
5.兩個文件編寫完成,運行查看結(jié)果:
關(guān)于相機動態(tài)權(quán)限問題該插件已經(jīng)自動處理好了,cordova擁有一套完整的權(quán)限處理機制,主要通過PermissionHelper類來完成處理,在之后的自定義插件中如用到動態(tài)權(quán)限則可以參照相機插件的源碼完成,具體可以查看該插件源碼,這里就先不貼了。
四、創(chuàng)建自定義插件及調(diào)用
很多時候官方的插件并不能滿足我們的開發(fā)需求,此時需要自定義插件以供開發(fā)調(diào)用,下面以創(chuàng)建一個能彈Toast的插件為例進行講解。
1.插件的創(chuàng)建我們依賴一個plugman插件,該插件可以為我們自動創(chuàng)建一個cordova插件所需要的文件。
首先打開終端,運行以下命令安裝plugman:
npm install -g plugman
安裝完成后可通過plugman -v
查看版本信息:
2.隨便選擇一個目錄在該目錄下打開終端創(chuàng)建自定義插件:
命令:plugman create --name [插件名] --plugin_id [插件ID] --plugin_version [插件版本號]
例子:plugman create --name toast-plugin --plugin_id toast-plugin --plugin_version 1.0.0
創(chuàng)建完成后可以看到該插件目錄文件結(jié)構(gòu)如下:
需要在src下手動創(chuàng)建一個android空目錄,里面存放代碼和資源文件,如果沒有android目錄則將該插件添加到項目中時會報找不到資源的錯誤。
3.根據(jù)功能先編寫java文件,該java文件要繼承cordova的CordovaPlugin.java,如我們要創(chuàng)建的插件功能為彈出一條Toast,為了結(jié)構(gòu)規(guī)范以及編寫方便,我們在Android studio中的app-src-java-org-apache下創(chuàng)建一個toa包,在包中創(chuàng)建ToaPlugin.java文件繼承自CordovaPlugin.java,并編寫Toast代碼:
重寫三個execute方法,這三個方法的功能是一樣的,按照個人喜好重寫其中一個即可,這里我們使用第三個方法
- 參數(shù)action:js調(diào)用原生的方法名
- 參數(shù)CordovaArgs:js傳過來的參數(shù),cordova做了封裝
- 參數(shù)CallbackContext:該對象很重要,要靠它實現(xiàn)js與原生的回調(diào)及數(shù)據(jù)交互
- 另外需要返回一個boolean值來告訴cordova是否調(diào)用成功,若不寫則會直接調(diào)用失敗。
- 上下文可以使用cordova.getActivity()或者cordova.getContext();
4.編寫完成后將該插件文件剪切到plugman創(chuàng)建的插件文件夾toast-plugin中的src-android目錄下:
注意:是剪切,如果復(fù)制的話記得將toa包和其中的ToaPlugin.java文件刪掉,因為后面添加插件的時候cordova會自動將toa包和java文件復(fù)制進來。若項目中已經(jīng)有了則會在添加插件的時候報錯”已存在“。
5.編輯plugin.xml文件,該文件是各個平臺對插件的各項配置,包括插件名稱、id、調(diào)用方法名、代碼文件及資源文件配置等。
初始只有插件名稱和js配置:
在plugin節(jié)點下添加我們的插件配置,完整代碼:
<?xml version='1.0' encoding='utf-8'?>
<plugin id="toast-plugin" version="1.0.0" xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<name>toast-plugin</name>
<js-module name="toast-plugin" src="www/toast-plugin.js">
<clobbers target="cordova.plugins.toast-plugin" />
</js-module>
<!--添加Android平臺 -->
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
<!-- JS調(diào)用時的前綴名字 -->
<feature name="ToaPlugin">
<!-- 插件類名全路徑 -->
<param name="android-package" value="org.apache.cordova.toa.ToaPlugin"/>
</feature>
</config-file>
<!-- 意思從Android目錄下找到ToaPlugin.java文件,拷貝到工程項目中的toa包下,包名要與上面的插件類名全路徑對應(yīng)上 -->
<source-file src="src/android/ToaPlugin.java" target-dir="src/org/apache/cordova/toa" />
</platform>
</plugin>
注意:
- 之所以要在toa包下編寫ToaPlugin.java文件是為了包名匹配,若在別的包下編寫則需要在復(fù)制java文件的時候記得把包名手動改成
package org.apache.cordova.toa;
- toast-plugin.js文件暫時不用編寫
- 這個xml文件不僅僅可以添加Android插件配置,同時也可以在plugin節(jié)點下繼續(xù)添加iOS插件配置。
6.在插件目錄下通過npm注冊該插件:
npm init
彈出的提示依次回車:
完成后會在插件目錄下生成一個package.json文件:
里面的內(nèi)容是插件的名稱、版本、描述、作者等信息,我們可以暫時不去管它,以后需要編輯的話重新在
npm init
彈出的提示中填入即可。
7.這樣一個插件就編寫完成了,復(fù)制插件路徑,在as控制臺或者終端通過以下命令將該插件添加到項目中去:
cordova plugin add /Users/mac/Desktop/toast-plugin
添加成功會打印如下信息:
可以看到插件文件已經(jīng)被自動添加進來了:
另外插件會被注冊到項目中:
8.編寫index.html添加一個按鈕
<div class="line"><button id="show_toa">彈出Toast</button></div>
編寫index.js代碼調(diào)用ToaPlugin插件:
//調(diào)用原生選擇圖片
document.getElementById("show_toa")
.onclick = function(){
cordova.exec(onSuccess,onFailed,"ToaPlugin","showToa",["這是從js傳過來的消息"]);
function onSuccess(deviceInfo) {}
function onFailed(message) {alert('Failed : ' + message);}
};
9.運行截圖:
五、管理自定義插件中使用到的各種資源文件
以上只是創(chuàng)建了一個簡單的自定義插件,沒有使用其他資源文件,那么如要在自定義插件使用資源文件如圖片,style,string,lib庫等資源則需要將該插件寫成lib庫的形式導(dǎo)入工程中。下面使用加載圖片資源的Activity作為插件來創(chuàng)建一個插件lib。
1.建立一個新項目或者在原項目上新建一個lib module,起名叫photolib
2.在res-drawbale中插入一張圖片,創(chuàng)建Activity,編寫布局代碼,界面如下:
3.按照上面創(chuàng)建自定義插件的流程在桌面創(chuàng)建一個photo-plugin插件
4.將該lib庫整體復(fù)制到插件src-android目錄下:
5.在app項目中編寫一個用于啟動PhotoActivity的插件:
6.將插件文件同樣復(fù)制到桌面創(chuàng)建的photo-plugin插件-src-android中:
7.編輯plugin.xml文件:
<?xml version='1.0' encoding='utf-8'?>
<plugin id="photo-plugin" version="1.0.0"
xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<name>photo-plugin</name>
<js-module name="photo-plugin" src="www/photo-plugin.js">
<clobbers target="cordova.plugins.photo-plugin" />
</js-module>
<!--添加Android平臺 -->
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
<!-- JS調(diào)用時的前綴名字 -->
<feature name="ToaPlugin">
<!-- 插件類名全路徑 -->
<param name="android-package" value="org.apache.cordova.photo.PhotoPlugin"/>
</feature>
</config-file>
<!-- 意思從Android目錄下找到ToaPlugin.java文件,拷貝到工程項目中的toa包下,包名要與上面的插件類名全路徑對應(yīng)上 -->
<source-file src="src/android/PhotoPlugin.java" target-dir="src/org/apache/cordova/photo" />
<framework src="src/android/photolib" custom="true"/>
</platform>
</plugin>
請注意<framework src="src/android/photolib" custom="true"/>
這一句,
framework標簽代表引用內(nèi)部或外部庫資源,如要使用gson.jar包則這樣寫:
<framework src="src/android/gson.jar" custom="true"
關(guān)于plugin.xml文件中各個標簽節(jié)點的含義可以參考cordova Plugin.xml 詳解
8.編輯完成,在插件目錄下打開終端運行 npm init
,生成對應(yīng)package.json文件。
9.復(fù)制插件路徑,將插件添加到項目中,在as項目中運行命令:
cordova plugin add /Users/guibo/Desktop/photo-plugin
會發(fā)現(xiàn)photo-plugin插件以lib庫的形式添加了進來:
同時項目自動依賴了該插件庫:
10.編輯index.html再添加一個按鈕,其余不變:
<div class="line"><button id="jump_photo">跳轉(zhuǎn)到圖片界面</button></div>
index.js中:
//跳轉(zhuǎn)到圖片界面
document.getElementById("jump_photo")
.onclick = function(){
cordova.exec(onSuccess,onFailed,"PhotoPlugin","jumpPhoto");
function onSuccess() {}
function onFailed(message) {alert('Failed : ' + message);}
};
運行測試即可。
10.若引用的資源文件不多也可以不使用lib庫,可直接將圖片文件復(fù)制到PhotoPlugin.java同級目錄下:
plugin.xml中添加
<source-file src="src/android/photo.jpeg" target-dir="app/src/main/res/drawable" />
這里需留意一下target-dir="app/src/main/res/drawable
這個目錄,表示將圖片復(fù)制到app項目中的drawable中,若資源文件不是圖片而是.xml文件,則指定的目錄可以省略app/src/main
,例如:
<!-- drawable -->
<source-file
src="src/android/Library/res/drawable/back_button_selector.xml" target-
dir="res/drawable" />
<!-- drawable-hdpi -->
<source-file src="src/android/Library/res/drawable-hdpi/icon_back_press.png" target-dir="app/src/main/res/drawable-hdpi" />
原因是添加插件時由cordova中的js代碼控制文件拷貝,查看該源碼可以發(fā)現(xiàn)在cordova在處理圖片、.xml文件和.java文件時的邏輯并不一樣:
可以看到處理.xml和.java文件時會給目錄前自動加上app/src/main,但并沒有處理圖片路徑,所以我們在plugin.xml中的目標路徑要寫全路徑:
target-dir="app/src/main/res/drawable
路徑不正確會導(dǎo)致添加插件時指定的圖片資源無法復(fù)制到項目中去。
六、補充操作
1.想要在AndroidManifest.xml文件中添加權(quán)限或者四大組件,platform標簽下添加:
<config-file parent="/manifest" target="AndroidManifest.xml">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
</config-file>
<config-file parent="/manifest/application" target="AndroidManifest.xml">
<activity
android:name="org.apache.cordova.qrscanner.CaptureActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" >
</activity>
</config-file>
-
string.xml:
<config-file parent="/resources" target="res/values/strings.xml"> <string name="cancel_label">"取消"</string> <string name="scan">請掃描</string> <string name="OK">確定</string> <string name="complete">完成</string> </config-file>
3.lib庫:
<source-file src="src/android/Library/libs/core-3.3.0.jar" target-
dir="app/src/main/libs" framework="true"/>
七、常見問題
1.經(jīng)過實測,res/values文件夾下除了string.xml能添加資源以外,該文件夾下其他資源均添加不進去,如attr.xml、ids.xml、color、style、diments等。因此在使用的資源文件很多的情況下建議將插件寫成lib庫的形式添加,也方便管理。
八、感謝提供參考的寶貴文章:
Android使用Cordova進行混合開發(fā)
Android+Cordova混合開發(fā)以及Cordova自定義插件
cordova 插件之資源文件處理
cordova Plugin.xml 詳解