天天看點

Cordova插件開發(1)-Android插件開發詳解

本篇文章講述的是Android Cordova插件實踐過程,具體實作包括以下五個方面:

1,實作原生自定義插件類;

2,配置Cordova插件;

3,注冊Cordova插件;

4,定義Cordova插件調用方式;

5,調用Cordova插件;

本篇文章以安卓Toast插件實作過程為例。進入正題。

一,準備工作

需準備一個已添加Android平台的Cordova工程,插件實作基于此。這裡就不寫怎樣建立Cordova工程以及添加Andoird平台了,這些都是最基本的。

二,具體實作

實踐過程包含以下五個部分:實作自定義插件類、配置Cordova插件、注冊Cordova插件、定義Cordova插件調用方式和調用Cordova插件。下面分别講述:

1,實作自定義插件類ToastDemo.java

在 工程名/platforms/android/src目錄下建立一個包,然後在該包下建立自定義插件類,并繼承于CordovaPlugin(自定義插件都需要繼承這個類),重寫execute方法,在execute方法中實作自己想要的功能邏輯即可。以此demo為例,我是在 工程名/platforms/android/src目錄下建的fxp.cordova.plugins包,然後建立ToastDemo.java類,是以此demo中插件類路徑為:工程名/platforms/android/src/fxp/cordova/plugins/ToastDemo.java。不多解釋,直接貼代碼,代碼中有注釋:

package fxp.cordova.plugins;

import android.widget.Toast;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONException;

import java.util.Random;

/**
 * Created by fxp on 2017/4/14.
 */

public class ToastDemo extends CordovaPlugin {

    /**
     * @param action          The action to execute.
     * @param args            The exec() arguments, wrapped with some Cordova helpers.
     * @param callbackContext The callback context used when calling back into JavaScript.
     * @return
     * @throws JSONException
     */
    @Override
    public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {

        if ("toast".equals(action)) {
            String str = args.getString(0);
            Toast.makeText(cordova.getActivity(), str, Toast.LENGTH_LONG).show();
            return true;
        } else if ("toastWithCallback".equals(action)) {
            String str = args.getString(0);
            Toast.makeText(cordova.getActivity(), str, Toast.LENGTH_LONG).show();
            //為展現成功/失敗兩種回調,這裡使用Random生成随機數,随機數為true時回調成功function,為false時回調失敗function,
            Random random = new Random();
            if (random.nextBoolean()) {
                callbackContext.success("execute_callack_success");
            } else {
                callbackContext.error("execute_callack_error");
            }
            return true;
        }
        return super.execute(action, args, callbackContext);
    }

}
           

對于自定義插件類,額外補充以下兩點:

  • 關于args值取用方式

a)  如果js傳入的如果是對象數組,即[{“key”:”value”,”key”:”value”}],則如下取用:

JSONArray jsonarr = new JSONArray(args.getString(0)); 

JSONObject json = jsonarr.getJSONObject(0);

String str = json.get("key");

b)  如果js傳入的如果是普通數組,即["a",10,true,…],則如下取用:

args.getString(0) 

args.getInt(1) 

args.getBoolean(2)

  • 關于線程

a)以上execute方法不是運作在WebView接口主線程,而是運作在WebCore線程;

b)如果想要運作在Activity的UI線程,以上execute方法可以參照下面寫法:

@Override
    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
        if ("toast".equals(action)) {
            final String str = args.getString(0);
            cordova.getActivity().runOnUiThread(new Runnable() {
                public void run() {
                    //TODO

                    callbackContext.success(); // Thread-safe.                }
            });
            return true;
        }
        return super.execute(action, args, callbackContext);
    }
           

c)如果既不想運作在UI線程,又不想阻塞WebCore線程,以上execute方法可以參照下面寫法:

@Override
    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
        if ("toast".equals(action)) {
            final String str = args.getString(0);
            cordova.getThreadPool().execute(new Runnable() {
                public void run() {
                    //TODO
                    
                    callbackContext.success(); // Thread-safe.
                }
            });
            return true;
        }
        return false;
    }
           

2,在config.xml中配置Cordova插件

打開 工程名/platforms/android/res/xml/config.xml檔案,在widget節點下添加如下feature:

<!--ToastDemo插件-->
    <feature name="ToastDemo">
        <param name="android-package" value="fxp.cordova.plugins.ToastDemo" />
    </feature>
           

其中,feature的name值比較重要,可随意取,但後續都得統一;param的name值可以随意填寫,value值為插件實作類的路徑,即【包名】.【類名】。

3,在cordova_plugins.js中注冊Cordova插件

打開 工程名/platforms/android/assets/www/cordova_plugins.js檔案,在module.exports數組中添加自定義插件資訊。此demo中是在module.exports數組中添加以下元素:

{
        "file": "plugins/fxp-cordova-plugins/www/ToastDemo.js",//js檔案路徑
        "id": "fxp-cordova-plugins.ToastDemo",//插件moduleid。對應cordova.define的第一個參數
        "clobbers": [
            "fxp"//js中調用時使用的對象名
        ]
    }
           

一個plugin可以有多個module,類似于Android Studio中project和module的概念,這裡的id是插件目前module的id,命名規則為【插件id】.【feature的name值】。插件id應使用"pluginId"為key值。此示例中,"pluginId":"fxp-cordova-plugins"。

4,定義Cordova插件調用方式

在 工程名/platforms/android/assets/www/plugins路徑下建立自己的檔案夾,并在自己的檔案夾下建立www目錄,然後在此www目錄下建立定義插件使用方式的js檔案(可以把所有定義插件使用方式的js檔案都放在這個www檔案夾下)。以此demo為例,我所建立的TestDemo.js檔案路徑為:工程名/platforms/android/assets/www/plugins/fxp-cordova-plugins/www/TestDemo.js。插件通常有兩種使用形式:有回調方法和無回調方法。TestDemo.js檔案内容如下:

/**
* cordova.define 的第一個參數就是cordova_plugins.js裡面定義的id
* exec方法參數說明:
* 參數1:成功回調function
* 參數2:失敗回調function
* 參數3:feature name,與config.xml中注冊的一緻
* 參數4:調用java類時的action
* 參數5:要傳遞的參數,json數組格式
* 下面提供三種實作方式,三種實作方式均可行
*/
cordova.define("fxp-cordova-plugins.ToastDemo",
    function(require, exports, module) {

        /*
         * 實作方式一
        */
        var exec = require("cordova/exec");
        module.exports = {
            toast: function(content){
                exec(null,null,"ToastDemo","toast",[content]);
            },
            toastWithCallback: function (content, successCallback, errorCallback) {
                cordova.exec(successCallback, errorCallback, "ToastDemo", "toastWithCallback", [content]);
            }
        }

        /*
         * 實作方式二
        */
/*        var exec = require('cordova/exec');
        var FXP = function(){};
        FXP.prototype.toast=function(content) {
            exec(null, null, "ToastDemo", "toast", [content]);
        };
        FXP.prototype.toastWithCallback=function(content,success, error) {
            exec(success, error, "ToastDemo", "toastWithCallback", [content]);
        };
        var fxp = new FXP();
        module.exports = fxp;*/

        /*
         * 實作方式三
        */
/*        var exec = require('cordova/exec');
        exports.toast = function(content) {
            exec(null, null, "ToastDemo", "toast", [content]);
        };
        exports.toastWithCallback=function(content, successCallback, errorCallback){
            exec(successCallback,errorCallback,"ToastDemo","toastWithCallback",[content]);
        };*/
});
           

5,調用Cordova插件

完成以上4步後一切均已就緒,可以直接調用了。調用方式為:

[clobbers].[action]
           

以此demo為例:

fxp.toast("toast");

        fxp.toastWithCallback("toastWithCallback",function(success){
            alert(success);
        },function(error){
            alert(error);
        });
           

至此,games over!

三,寫在後面

1,本文實作的是簡單的toast插件,意在講述插件的實踐過程;

2,是以demo實踐都是在 工程名/platforms/android目錄下,是以調試時不要執行cordova build 或  cordova run 指令(執行此指令後,工程名/platforms/android/assets/www将被替換導緻前面所加代碼丢失);

3,後面有空會再寫一篇博文講述自定義插件安裝方式;

4,不足之處,歡迎批評指正;

1,時隔一年半再回頭看這篇博文,竟發現有的東西講得不是很準确,已修正。請見諒。

2,以上自定義插件實作方式是根據Cordova官方文檔标準流程。但仔細看了cordova源碼之後,發現實際上有更加簡單的實作方式:

以上流程中的第3、4步均可省略,不用在cordova_plugins.js中注冊,也不用寫TestDemo.js提供調用方法,直接如下即可調起:

Cordova.exec(successCallback,errorCallback,"ToastDemo","toast",[content]);