本篇文章讲述的是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);
}
}
对于自定义插件类,额外补充以下两点:
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:
其中,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,不足之处,欢迎批评指正;
/***************************************2018.6.28补充 start ***************************************/
1,时隔一年半再回头看这篇博文,竟发现有的东西讲得不是很准确,已修正。请见谅。
2,以上自定义插件实现方式是根据Cordova官方文档标准流程。但仔细看了cordova源码之后,发现实际上有更加简单的实现方式:
以上流程中的第3、4步均可省略,不用在cordova_plugins.js中注册,也不用写TestDemo.js提供调用方法,直接如下即可调起:
Cordova.exec(successCallback,errorCallback,"ToastDemo","toast",[content]);
/***************************************2018.6.28补充 end ***************************************/