開發一個Cordova插件 ionic系列一

概述

介紹如何自己開發一個Cordova插件(android平臺)。我們用ionic開發時,如果需要使用Android系統原生功能,Cordova插件是一個很好的選擇。如果沒有現成的cordova 插件,我們就需要自己開發一個。下面簡單介紹一下如何開發。
cordova插件分為2大部分,js端和平臺端(Android、ios等代碼);js端定義了統一的接口,供ionic等web開發框架調用(用JavaScript方式)。平臺端是具體功能針對不同平臺的實現。(對應Android來說,就是實現具體功能的Java類,jar包等)。
詳細的介紹大家參加cordova官網介紹:cordova plugin

大致步驟:

這里介紹一下本文的主要步驟:

  1. 開發一個簡單的cordova plugin 。例子就采用官網的示例:EchoPlugin。
  2. 新建一個ionic 項目。使用流行的tabs方式(當然這是無關緊要的)。
  3. 將EchoPlugin安裝到ionic項目。
  4. 在ionic項目中,利用JavaScript調用插件提供的echo接口。
  5. 運行項目,查看結果。

1. 創建插件

創建插件前,先簡單介紹一下這個EchoPlugin,Android本地端提供了一個EchoPlugin.echo(String message, CallbackContext cbc)方法。這個方法的作用就是把message返回前臺。org.apache.cordova.CallbackContext是cordova框架提供的。JS端定義了window.echo()接口,只要以web js方式調用這個接口,后臺就能執行執行的功能(EchoPlugin.echo)。

1.1 創建項目EchoPlugin 框架

在硬盤里找個地方(比如d:\app),創建項目EchoPlugin,官網上也沒提供Maven模板。自己手工建吧。先建項目根目錄:EchoPlugin,然后在根目錄里面建plugin.xml,www目錄(js端啦),src\android(平臺端啦)。參考一下圖片:

cordova_plugin_archetype.png

1.2 編寫js端代碼(EchoPlugin.js):

window.echo = function(str, callback) {
    cordova.exec(callback, function(err) {
        callback('Nothing to echo.');
    }, "EchoPlugin", "echo", [str]);
};

js端通過cordova.exec()方法,實現前臺js代碼對后臺Java的調用。你可以先把項目跑成功再來看下面的廢話。
根據Cordva官網介紹:Cordova.exec有五個參數,其作用分別如下:
第一個:success回調,當Android平臺端函數執行成功后被調用。
第二個:error回調,當Android平臺端函數執行不成功后被調用。
第三個:Java類名,用于指定Android平臺被調用方法所在的Java類的類名。
第四個:Java方法名,用于指定Android平臺被調用方法的method name。
第五個:字符串數組,作為參數args傳遞給Android Java method.
window.echo = function(str,callback) {...} 有兩個參數,str、callback。他里面就調用了cordava.exec(...) .這里很明顯,str傳遞給cordava.exec作為了第五個參數。callcack傳遞給cordava.exec成為了第一個參數。這都不是必須的,自己可以靈活掌握。

1.3 編輯Java端代碼(EchoPlugin.java):

package org.apache.cordova.plugin;

import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
* This class echoes a string called from JavaScript.
*/
public class EchoPlugin extends CordovaPlugin {

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if (action.equals("echo")) {
            String message = args.getString(0);
            this.echo(message, callbackContext);
            return true;
        }
        return false;
    }

    private void echo(String message, CallbackContext callbackContext) {
        if (message != null && message.length() > 0) {
            callbackContext.success(message);
        } else {
            callbackContext.error("Expected one non-empty string argument.");
        }
    }
}

自定義插件需要繼承CordovaPlugin 并且Override其execute方法。此外我們這個插件還需要實現echo()方法,這是js接口中指定的后臺方法。使用插件的時候并不關心這些。

1.4 編寫manifest文件: plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
    id="cordova-plugin-echo" version="0.1.1">
    <name>Echo</name>
    <description>Cordova Echo Plugin</description>
    <author>July</author>
    <license>Apache 2.0</license>
    <keywords>cordova,Echo</keywords>
    <js-module src="www/EchoPlugin.js" name="echoPlugin">
        <clobbers target="echoplugin" />
    </js-module>
    <platform name="android">
        <config-file target="res/xml/config.xml" parent="/*">
            <feature name="EchoPlugin">
                <param name="android-package" value="org.apache.cordova.plugin.EchoPlugin" />
            </feature>
        </config-file>

        <!-- Required  一些系統要求的權限,如訪問網絡等-->
        <!-- <config-file target="AndroidManifest.xml" parent="/manifest">
            <uses-permission android:name="android.permission.INTERNET" />
        </config-file> -->

        <source-file src="src/android/EchoPlugin.java" target-dir="src/org/apache/cordova/plugin" />
    </platform>
</plugin>

這個文件的ID是插件的名字,估計發布到cordova服務器后可以通過ID就能安裝插件;js-module元素描述了JavaScript接口信息;主要就是指出js文件位置啦;platform元素指定了各平臺(這里只有android)代碼的位置。config-file指定編譯后目標平臺配置文件config.xml的位置,cordova要把feature元素中的內容復制到config.xml中。source-file指定Java源碼位置這里有2個位置,src源文件位置,target是ionic項目build android,編譯為目標平臺(android)項目后代碼的位置。同樣這段廢話可以等項目跑成功后再看。
我們的插件開發完啦,libs目錄是空的,因為這個Java類太簡單啦,如果有需要可以將Jar包放在libs目錄里。
下面我們新建一個ionic項目來使用這個插件。當然cordova項目,phonegap項目都能用這個插件。我的ionic系列是不會提供環境搭建教程的。第一次搭建環境推薦找梯子。

2. 創建ionic 項目。找一個比較合適的目錄,cmd切換到該目錄,執行下面的命令。

 ionic start testEcho tabs
 cd testEcho
ionic platform add android
cordova plugin add D:\app\EchoPlugin

3. 安裝剛才開發的插件。

嗯剛才的最后一行代碼就是安裝自己開發的Echo cordova插件。

4. 在ionic項目中使用插件。

找到www\js\app.js,添加如下代碼:

window.echo("echoMe",function(echoValue){
      console.log("Echo Plugin called");
      console.log(echoValue);
      alert(echoValue == "echoMe");
    });

添加位置:

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);

    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }

    // 調用Echo插件

    window.echo("echoMe",function(echoValue){
      console.log("Echo Plugin called");
      console.log(echoValue);
      alert(echoValue == "echoMe");
    });
  });
})
...

5. 查看效果。cmd切換到ionic項目根目錄,就是www目錄的父目錄。

ionic build android
ionic emulate android

效果圖:

cordova_plugin_result1.png

控制臺:

cordova_result.png

6. 其他補充

這個例子很簡單,但包含了開發一個插件的基本要素。但是Java 插件只是返回了一個信息,沒有和Android原生程序交互。下面補充一下如何調用Android項目原生activity;比如某個項目的DemoActivity.java.

首先 把DemoActivity.java; 他的layout文件main.xml;他用到的jar包,so文件都辨識出來。一開始漏掉也沒關系編譯通不過會提示你缺少那些類,根據提示再補充。然后通過plugin.xml配置這些文件信息,指定文件編譯后在Android項目中的位置就行了。

6.1 activity及 layout;這些文件都是原生Android項目文件,建議在Android項目中完成開發并且運行成功。然后直接復制文件到相應的目錄。參加1.1項目框架。

DemoActivity.java
package com.test.demo;
import android.app.Activity;
/**
* 這里要用ionic項目編譯后的R文件,包名需要自己去查詢*
* %projecthomefolder%\platforms\android\build\generated\source\r\armv7\debug\ *
*/
import com.ionicframework.xxxx.R;
import ...

public class DemoActivity extends Activity {

     /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
   }

/** other method */
@Override
...

}

main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:fillViewport="true" >

    <LinearLayout
        android:id="@+id/Play"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
...
</ScrollView>

6.2 插件后臺Java類,需集成CordovaPlugin

public class DemoPlugin extends CordovaPlugin {
  private CallbackContext context;
  /** Constructor */
  public DemoPlugin() {

  }

  @Override
  public boolean execute(String action,JSONArray args,CallbackContext callbackContext) throws JSONException {
    this.context = callbackContext;
    if("openDemoActivity".equals(action)) {
      //使用Intent啟動DemoActivity
      Intent intent = new Intent(this.cordova.getActivity(),com.test.demo.DemoActivity.class);
      if(this.cordova != null) {
        this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0);
        return true;
      }
      return false;
    }
    return false;

  }

 @Override
 public void onActivityResult(int requestCode,int resultCode,Intent intent) {
   super.onActivityResult(requestCode,resultCode,intent);
    //decide what to do by resultCode
    if(resultCode == Activity.RESULT_OK) {
      context.success("ok");
    }
  }
}

6.3 plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="cordova-plugin-hcnet" version="0.1.1">
<name>HcnetPlugin</name>
<description>Cordova HcNet Plugin</description>
<author>July</author>
<license>Apache 2.0</license>
<keywords>cordova,Hcnet</keywords>
<js-module src="www/DemoPlugin.js" name="DemoPlugin">
<clobbers target="DemoPlugin" />
</js-module>
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
<feature name="DemoPlugin">
<param name="android-package" value="org.apache.cordova.plugin.DemoPlugin" />
</feature>
</config-file>

    <!-- Required  一些系統要求的權限,如訪問網絡等-->
    <config-file target="AndroidManifest.xml" parent="/manifest">
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
        <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    </config-file>

    <config-file target="AndroidManifest.xml" parent="/manifest/application">
        <activity android:name="com.test.demo.DemoActivity"
            android:label="@string/app_name">
        </activity>
    </config-file>

    <source-file src="src/android/DemoPlugin.java" target-dir="src/org/apache/cordova/plugin" />
    <source-file src="src/android/DemoActivity.java" target-dir="src/com/test/demo" />
    <source-file src="src/android/xxx.java" target-dir="src/com/test/demo" />
   
    <!-- 其他包里面的Java文件,target-dir寫上src/包的路徑 -->
    <source-file src="src/android/Other.java" target-dir="src/com/xxx/xxx" />
    <!-- lib目錄里面的jar文件,target-dir寫上libs -->
    <source-file src="src/android/libs/SomeSDK.jar" target-dir="libs" />
    
    <!-- 布局文件,target-dir寫上libs -->
    <source-file src="src/android/res/layout/main.xml" target-dir="res/layout" />

    <source-file src="src/android/libs/armeabi/libAudioEngine.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libCpuFeatures.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libgnustl_shared.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libHCAlarm.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libHCCore.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libHCCoreDevCfg.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libHCDisplay.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libHCGeneralCfgMgr.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libHCIndustry.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libhcnetsdk.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libHCPlayBack.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libHCPreview.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libHCVoiceTalk.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libjnidispatch.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libopensslwrap.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libPlayCtrl.so" target-dir="libs/armeabi" />
    <source-file src="src/android/libs/armeabi/libSystemTransform.so" target-dir="libs/armeabi" />

</platform>

</plugin>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,424評論 25 708
  • ionic是一個運行在webview上的應用,但是很多功能js搞不定,免不了本地代碼的支持。ionic在nativ...
    李澤1988閱讀 3,056評論 0 3
  • 偶爾會聽到身邊有朋友說,自己的愛人很“假”,口是心非。我很好奇,為什么對方的反應會他們以為愛人很“假”呢?直接有一...
    昭君故事薈閱讀 301評論 0 0
  • 2017.4.1感賞日記 感賞女兒今天感冒好多了 感賞小鳥相處的融洽一些了 感賞自己利用晚上看完了省下的半本書 感...
    悄然h閱讀 217評論 0 0