前言:
Cordova作为一个成熟的混合开发框架,具备有完整的开发文档和社区论坛来供我们学习、爬坑使用~~~ 同时Cordova还提供了像Battery Status,Camera,Device,Dialogs,File,Media等诸多插件来支持Cordova对platform的原生调用, 除了这些提供的plugin之外,项目使用到的其他原生功能就需要我们自己来实现插件支持.
本篇主要介绍在Cordova android platform上进行开发一个支付插件来供web调用,有不清楚Cordova 平台创建的小伙伴可以先移步我前面写的Cordova android平台开发一(应用创建),下面开始我们今天的正题~~~
一 创建Cordova插件
1.plugman环境安装
这里使用plugman命令生成插件包,所以要先使用npm全局安装plugman:
npm install -g plugman
//如果permission denied (try: sudo npm install -g plugman)
2.创建cordova plugin
- 随便在目录下新建一个文件夹(CustomPlugin),然后cmd cd到该文件夹下
- plugman create --name <pluginName> --plugin_id <pluginID> --plugin_version <version> [--path <directory>] [--variableNAME=VALUE]
参数:
pluginName: 插件名字
pluginID: 插件id, egg : coolPlugin
oversion: 版本, egg : 0.0.1
directory:一个绝对或相对路径的目录,该目录将创建插件项目
variable NAME=VALUE: 额外的描述,如作者信息和相关描述
egg : plugman create --name ZITOPay --plugin_id com.example.plugin --plugin_version 1.0.0
- 添加android平台的插件类
cd ZITOPay
plugman platform add --platform_name android
最终生成的插件包的目录结构如下:
- 修改plugin.xml 把id 改成cordova-plugin-zitopay, 把target-dir的 /ZITOPay去掉
<?xml version='1.0' encoding='utf-8'?>
//<plugin id="com.example.plugin" //修改id为cordova-plugin-zitopay
<plugin id="cordova-plugin-zitopay"
version="1.0.0"
xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<name>ZITOPay</name>
<js-module name="ZITOPay" src="www/ZITOPay.js">
<clobbers target="ZITOPay" /> //用于生成js调用时的引用名,可修改
</js-module>
<platform name="android">
<config-file parent="/*" target="res/xml/config.xml">
<feature name="ZITOPay">
<param name="android-package" value="com.example.plugin.ZITOPay" />
</feature>
</config-file>
<config-file parent="/*" target="AndroidManifest.xml"></config-file>
//<source-file src="src/android/ZITOPay.java" target-dir="src/com/example/plugin/ZITOPay" /> //去掉 /ZITOPay
<source-file src="src/android/ZITOPay.java" target-dir="src/com/example/plugin" />
</platform>
</plugin>
对于plugin.xml文件的配置有不懂得可以参考:http://www.jianshu.com/p/050ed1bd4973
-
生成package.json文件,命令 : npm init
name 最好和plugin.xml中的id一样: cordova-plugin-zitopay, 然后一直Enter;
最后license,写成Apache-2.0就可以了.
//插件的js和java文件可以等用到时修改~
二 在Cordova项目中添加插件
- cmd cd到项目的根目录
- 添加插件
执行插件安装命令 cordova plugin add F:\workroom\Cordova\CustomPlugin\ZITOPay
执行完之后你就发现插件已经安装上去了
如果你想卸载插件的话,执行cordova plugin remove 你的plugin_id
egg:cordova plugin remove cordova-plugin-zitopay
三 用android studio打开添加插件的Cordova项目
1. 修改ZITOPay.java
/**
* This class echoes a string called from JavaScript.
*/
public class ZITOPay extends CordovaPlugin {
private Activity activity;
String toastMsg;
private static final int SDK_PAY_FLAG = 1;
private static final int SDK_AUTH_FLAG = 2;
private CallbackContext callbackContext;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressWarnings("unused")
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
ToastUtil.showToast(toastMsg, activity);
break;
default:
break;
}
}
};
ZitoCallBack zitoCallback = new ZitoCallBack() {
@Override
public void done(ZitoResult result) {
//判断结果
final ZitoPayResult zitoPayResult = (ZitoPayResult) result;
Message msg = mHandler.obtainMessage();
//单纯的显示支付结果
msg.what = 1;
String res = zitoPayResult.result;
if (res.equals(ZitoPayResult.RESULT_SUCCESS)) {
toastMsg = "支付成功";
callbackContext.success(res);
} else if (res.equals(ZitoPayResult.RESULT_CANCEL)) {
toastMsg = "支付取消" + zitoPayResult.detailInfo;
callbackContext.error(res + zitoPayResult.detailInfo);
} else if (res.equals(ZitoPayResult.RESULT_FAIL)) {
toastMsg = "支付失败" + zitoPayResult.detailInfo;
callbackContext.error(res + zitoPayResult.detailInfo);
} else if (res.equals(ZitoPayResult.START_WEB_SCUESS)) {
toastMsg = "支付webview初始化成功" + zitoPayResult.detailInfo;
callbackContext.error(res + zitoPayResult.detailInfo);
}
mHandler.sendMessage(msg);
}
};
@Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
Log.e("initialize", "============================");
activity = cordova.getActivity();
}
@Override
public void onStart() {
super.onStart();
Log.e("onStart", "ZITOPay....onStart方法调用了");
//设置ZTIO上注册获得的融拓提供的Id和融拓提供的Secret和支付应用的AppId
ZitoCloud.setAppIdAndSecret("RZF206855", "e3c7cc4540463c64b22cb619f52abd9e", "RZF206852");
//是测试模式
ZitoCloud.setTest(true);
//初始化微信
String initInfo = ZitoPay.initWechatPay(activity, "wx2a490909492ec841");
if (initInfo != null) {
ToastUtil.showToast("微信初始化失败:" + initInfo, activity);
}
}
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
this.callbackContext = callbackContext;
//参数赋值
ZitoPayUpLoadParmas parma = new ZitoPayUpLoadParmas();
//随机生成订单号
parma.orderidinf = "S222_" + TimeUtils.getNowTime();
//parma.totalPrice="0.01";
parma.currey = "cny";
//parma.ordertitle="食品";
// parma.goodsname ="零食";
// parma.goodsdetail ="乐事薯片";
parma.bgRetUrl = "http://www.baidu.com";
parma.returnUrl = "http://www.baidu.com";
parma.retUrl = "http://www.baidu.com";
parma.totalPrice = args.getString(0);
parma.ordertitle = args.getString(1);
parma.goodsname = args.getString(2);
parma.goodsdetail = args.getString(3);
if (action.equals("ALiPay")) {
Map<String, String> optional = new HashMap<String, String>();
//扩展参数可以传任意数量
optional.put("Key", "Value");
parma.optional = optional;
parma.analysis = null;
ZitoPay.getInstance(activity).sendZITOReq(ZiToPayFields.AliPay, parma, zitoCallback);
return true;
} else if (action.equals("WXPay")) {
if (ZitoPay.isWXAppInstalledAndSupported() && ZitoPay.isWXPaySupported()) {
ZitoPay.getInstance(activity).sendZITOReq(ZiToPayFields.WXPay, parma, zitoCallback);
} else {
ToastUtil.showToast("您尚未安装微信或者安装的微信版本不支持", activity);
}
return true;
}
return false;
}
}
- execute方法是js调用Cordova插件时被调用的方法,是我们写的插件的入口。
这个方法有三个参数action、args、callbackContext。
action活动,主要用来区分调用的是哪个方法,如果你的插件有多个方法,可以用这个区分。比如我有ALiPay和WXPay这个方法:
if (action.equals("ALiPay")) {
Map<String, String> optional = new HashMap<String, String>();
//扩展参数可以传任意数量
optional.put("Key", "Value");
parma.optional = optional;
parma.analysis = null;
ZitoPay.getInstance(activity).sendZITOReq(ZiToPayFields.AliPay, parma, zitoCallback);
return true;
} else if (action.equals("WXPay")) {
if (ZitoPay.isWXAppInstalledAndSupported() && ZitoPay.isWXPaySupported()) {
ZitoPay.getInstance(activity).sendZITOReq(ZiToPayFields.WXPay, parma, zitoCallback);
} else {
ToastUtil.showToast("您尚未安装微信或者安装的微信版本不支持", activity);
}
return true;
}
args传入的参数,我的插件传入了一个参数:
parma.totalPrice = args.getString(0);
如果有多个参数,依次取出即可。
- initialize是在调用插件前作的准备工作,在调用execute之前被调用。如上面的代码,我仅仅是获取了activity并保持下来。
- onStart是在活动显示的时候调用,在这里进行微信的初始化和注册操作。
- ZitoCallBack类是支付的结果返回,将支付结果返回给js
2.添加依赖和工具包,编译
-
根据支付平台的开发文档添加工具包
-
添加依赖库
- 在AndroidManifest.xml文件添加支付activity和权限
<?xml version='1.0' encoding='utf-8'?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hello"
android:hardwareAccelerated="true"
android:versionCode="10000"
android:versionName="1.0.0">
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:hardwareAccelerated="true"
android:icon="@mipmap/icon"
android:label="@string/app_name"
android:supportsRtl="true">
<activity
android:name="MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
android:label="@string/activity_name"
android:launchMode="singleTop"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
android:windowSoftInputMode="adjustResize">
<intent-filter android:label="@string/launcher_name">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--支付宝-->
<activity
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind"></activity>
<activity
android:name="com.alipay.sdk.auth.AuthActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind"></activity>
<!--微信-->
<activity
android:name="com.SDK.activity.ZitoWechatPaymentActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity-alias
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:targetActivity="com.SDK.activity.ZitoWechatPaymentActivity" />
</application>
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="26" />
<!--支付用到的权限-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />
</manifest>
到这里项目应该可以编译通过了....
3. 修改ZITOPay.js
cordova.define("cordova-plugin-zitopay.ZITOPay", function(require, exports, module) {
var exec = require('cordova/exec');
var zitopay = function(){};
zitopay.prototype.AliPay = function(arg,success,error) {
exec(success, error, "ZITOPay", "ALiPay", [arg]);
};
zitopay.prototype.WeiXinPay = function(arg,success,error) {
exec(success, error, "ZITOPay", "WXPay", [arg]);
};
var pay = new zitopay();
module.exports = pay;
});
- zitopay.prototype.ALiPay:js中调用时使用的方法名是ALiPay,参数是arg,success,error。
- exec(success, error, "ZITOPay", "ALiPay", [arg]);中的参数解释:
success:成功回调方法,对应java代码中的private CallbackContext callbackContext; callbackContext.success(res);方法。
error:失败回调方法,对应java代码中的private CallbackContext callbackContext; callbackContext.error(res + zitoPayResult.detailInfo);方法。
- "ZITOPay":插件名。
- "ALiPay",[arg]:这两个参数一起说,还记得这个吗?
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
this.callbackContext = callbackContext;
...
if (action.equals("ALiPay")) {
... //支付宝支付逻辑
return true;
} else if (action.equals("WXPay")) {
... //微信支付逻辑
return true;
}
return false;
}
"ALiPay"对应action,[arg]对应args。
四 插件的使用
- 简单写一个调用,打开assets\www\index.html,添加两个按钮:
<input type="button" id="btnpay" name="btn" value="ALiPAY"/> <br/>
<input type="button" id="btnshow" name="btn1" value="WeiXinPay"/> <br/>
- 打开assets\www\js\index.js,添加两个按钮的事件处理:
var app = {
// Application Constructor
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
//在initialize中加载事件
document.getElementById("btnpay").addEventListener("click",alipay)
document.getElementById("btnshow").addEventListener("click",weixin)
},
// deviceready Event Handler
//
// Bind any cordova events here. Common events are:
// 'pause', 'resume', etc.
onDeviceReady: function() {
this.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
}
};
app.initialize();
//定义方法
function weixin(){
ZITOPay.WeiXinPay("weixinpay~",showMessage,showMessage);
}
function alipay(){
ZITOPay.AliPay("alipay~",showMessage,showMessage);
}
function showMessage(msg){
alert(msg);
}
运行项目,测试成功~~~
番外说明:
- 有小伙伴说要配置config.xml
打开res\xml文件夹下的config.xml文件,需要在widget节点下添加配置ZITOPay插件的feature标签:
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.example.hello" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<feature name="Whitelist">
<param name="android-package" value="org.apache.cordova.whitelist.WhitelistPlugin" />
<param name="onload" value="true" />
</feature>
//feature不适用于通过cmd添加插件的方式,
//适用于通过SDK特定平台进行开发可通过编辑config.xml feature标签的内容添加API
<feature name="ZITOPay">
//value为插件类在项目中的位置,即全类名
<param name="android-package" value="com.example.plugin.ZITOPay" />
</feature>
<name>HelloWorld</name>
...
如果你通过CLI添加了插件(Plugin),则你可以在平台目录下的config.xml中找到如下类似的配置节:
<widgetid="com.oserp.hwec" version="0.0.1"xmlns="http://www.w3.org/ns/widgets"xmlns:cdv="http://cordova.apache.org/ns/1.0">
<preference name="loglevel" value="DEBUG" />
<feature name="App">
<param name="android-package"value="org.apache.cordova.App" />
</feature>
<feature name="Device">
<param name="android-package"value="org.apache.cordova.device.Device" />
</feature>
<feature name="NetworkStatus">
<param name="android-package"value="org.apache.cordova.networkinformation.NetworkManager" />
</feature>
结构很明了。如果是IOS平台的,则name就是ios-package了。
关于config.xml文件的详细介绍参考官方文档:http://cordova.axuer.com/docs/zh-cn/latest/config_ref/index.html
本章小结
Cordova(PhoneGap) 技术使用了CordovaPlugin 插件化(模块化)技术,使用不同插件对不同HTML5页面进行分别处理。与此同时,系统也可以利用插件调用系统已有的地图、通信录、浏览器等多个API,与 HTML5 页面进行信息交换,真正实现HTML5与Android、iOS系统的无缝对接。
好吧,附上源码,欢迎指教~~
https://github.com/watermelonRind/cordova_android_plugin/tree/master