Android集成Cordova

導(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.運行之后會生成一個空項目,目錄如下:


image.png

3.進入工程根目錄下,添加平臺
Android:cordova platform add android
iOS:cordova platform add ios
添加完成之后會發(fā)現(xiàn)在platforms文件夾下生成了一個Android項目:

image.png

本文章主要介紹Android平臺,如不需要iOS平臺則可以不添加iOS。

4.在編譯項目之前應(yīng)該先檢測編譯環(huán)境是否滿足,在cordova項目根目錄下運行如下命令:
cordova requirements
運行后若環(huán)境滿足則會打印如下信息:

image.png

若不滿足則會提示缺少SDK配置或者jdk配置。

5.直接編譯運行:
cordova build
注意:若使用cordova build則會編譯所有平臺,例如Android和iOS以及其他平臺會同時被編譯,若只想編譯其中一個平臺則運行cordova build android,加上平臺后綴即可,單獨編譯iOS則cordova build ios
編譯Android項目時用到gradle編譯命令,所以運行前請保證環(huán)境變量已經(jīng)配置完畢。
編譯后將生成一個apk,可直接傳到手機上運行:

image.png

運行截圖:
image.png

這樣第一個Android的Cordova項目就運行起來了。

6.用Android Studio打開該項目跟打開普通Android項目一樣的:


image.png

三、Cordova插件調(diào)用

cordova官網(wǎng)提供了很多原生插件以供開發(fā)者使用,具體插件命令和作用可以查看這兩篇文章:

1.在cordova工程根目錄或者Android目錄下運行一下命令
cordova plugin add cordova-plugin-camera
其中cordova plugin add 為添加插件操作,cordova-plugin-camera為插件名稱。
卸載插件命令為:
cordova plugin remove cordova-plugin-camera
等待控制臺打印

image.png

這樣一個相機插件就添加完成了,查看文件目錄可以發(fā)現(xiàn)添加該插件的同時都添加了哪些代碼文件:


image.png

image.png

image.png

image.png

image.png

2.在用cordova添加Android平臺時會在assets文件夾下創(chuàng)建www目錄來管理插件和js代碼:


image.png

首頁面的頁面編輯在index.html中:


index.html

邏輯編寫在js文件夾下的index.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文件引用的第一行


image.png

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é)果:


image.png

關(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查看版本信息:

image.png

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)如下:

image.png

需要在src下手動創(chuàng)建一個android空目錄,里面存放代碼和資源文件,如果沒有android目錄則將該插件添加到項目中時會報找不到資源的錯誤。
image.png

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代碼:
image.png

重寫三個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目錄下:


image.png

注意:是剪切,如果復(fù)制的話記得將toa包和其中的ToaPlugin.java文件刪掉,因為后面添加插件的時候cordova會自動將toa包和java文件復(fù)制進來。若項目中已經(jīng)有了則會在添加插件的時候報錯”已存在“。
5.編輯plugin.xml文件,該文件是各個平臺對插件的各項配置,包括插件名稱、id、調(diào)用方法名、代碼文件及資源文件配置等。
初始只有插件名稱和js配置:


image.png

在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
彈出的提示依次回車:

image.png

完成后會在插件目錄下生成一個package.json文件:
image.png

image.png

里面的內(nèi)容是插件的名稱、版本、描述、作者等信息,我們可以暫時不去管它,以后需要編輯的話重新在npm init彈出的提示中填入即可。

7.這樣一個插件就編寫完成了,復(fù)制插件路徑,在as控制臺或者終端通過以下命令將該插件添加到項目中去:
cordova plugin add /Users/mac/Desktop/toast-plugin
添加成功會打印如下信息:

image.png

可以看到插件文件已經(jīng)被自動添加進來了:
image.png

另外插件會被注冊到項目中:
image.png

image.png

8.編寫index.html添加一個按鈕

<div class="line"><button id="show_toa">彈出Toast</button></div>
image.png

編寫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);}
      };
image.png

9.運行截圖:


image.png

五、管理自定義插件中使用到的各種資源文件

以上只是創(chuàng)建了一個簡單的自定義插件,沒有使用其他資源文件,那么如要在自定義插件使用資源文件如圖片,style,string,lib庫等資源則需要將該插件寫成lib庫的形式導(dǎo)入工程中。下面使用加載圖片資源的Activity作為插件來創(chuàng)建一個插件lib。
1.建立一個新項目或者在原項目上新建一個lib module,起名叫photolib
2.在res-drawbale中插入一張圖片,創(chuàng)建Activity,編寫布局代碼,界面如下:


image.png

3.按照上面創(chuàng)建自定義插件的流程在桌面創(chuàng)建一個photo-plugin插件
4.將該lib庫整體復(fù)制到插件src-android目錄下:


image.png

5.在app項目中編寫一個用于啟動PhotoActivity的插件:
image.png

6.將插件文件同樣復(fù)制到桌面創(chuàng)建的photo-plugin插件-src-android中:
image.png

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庫的形式添加了進來:

image.png

同時項目自動依賴了該插件庫:
image.png

10.編輯index.html再添加一個按鈕,其余不變:

  <div class="line"><button id="jump_photo">跳轉(zhuǎn)到圖片界面</button></div>
image.png

index.js中:

      //跳轉(zhuǎn)到圖片界面
     document.getElementById("jump_photo")
             .onclick = function(){
             cordova.exec(onSuccess,onFailed,"PhotoPlugin","jumpPhoto");
             function onSuccess() {}
             function onFailed(message) {alert('Failed : ' + message);}
             };
image.png

運行測試即可。

10.若引用的資源文件不多也可以不使用lib庫,可直接將圖片文件復(fù)制到PhotoPlugin.java同級目錄下:

image.png

plugin.xml中添加
<source-file src="src/android/photo.jpeg" target-dir="app/src/main/res/drawable" />
image.png

這里需留意一下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文件時的邏輯并不一樣:

image.png

可以看到處理.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>
  1. 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 詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,296評論 2 376

推薦閱讀更多精彩內(nèi)容