Cordova android平台开发二(自定义支付插件)

镇楼.jpg

前言:

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
创建插件.png

最终生成的插件包的目录结构如下:


目录结构.png
  • 修改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文件可以等用到时修改~


    生成package.json.png

二 在Cordova项目中添加插件

  • cmd cd到项目的根目录
  • 添加插件
执行插件安装命令 cordova plugin add F:\workroom\Cordova\CustomPlugin\ZITOPay
执行完之后你就发现插件已经安装上去了
如果你想卸载插件的话,执行cordova plugin remove  你的plugin_id
egg:cordova plugin remove  cordova-plugin-zitopay
添加插件.png

三 用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.添加依赖和工具包,编译

  • 根据支付平台的开发文档添加工具包


    添加工具包.png
  • 添加依赖库


    添加依赖库.png
  • 在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/>
index.html.png
  • 打开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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容