本篇文章講述的是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]);