华为快应用(2)-本地接入支付

我的快游戏基于cocos creator 2.0.7。

首先华为的支付流程是这样的:https://developer.huawei.com/consumer/cn/service/hms/catalog/fastgameRuntime.html?page=fastapp_fastgameRuntime_devguide_open_ability#%E6%8E%A5%E5%85%A5%E6%94%AF%E4%BB%98%E6%9C%8D%E5%8A%A1

华为快应用(2)-本地接入支付_第1张图片

首先我的游戏是单机游戏,没有服务器的支持。所以只能把签名算法写在本地,首先写好自己的订单信息,然后必须参与签名的字段先构造源串。在orderInfo参数中,在你的订单信息中必填的字段中选择参与签名的信息,提取出来,使用它们构造源串。例如字段url参与订单信息非必填,但是参与签名。只要你的订单信息中没有出现url,签名就可以不包含字段url。

第一步提取出的参数先构造源串。使用一个ksort算法,根据键值的ASCII码增序排序。我是在网上百度搜到的方法,拷过来单独写一个类,模块化。用到的时候调用就可以。

var SignScript ={

    ksort(inputArr, sort_flags) {
        //  discuss at: http://phpjs.org/functions/ksort/
        // original by: GeekFG (http://geekfg.blogspot.com)
        // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
        // improved by: Brett Zamir (http://brett-zamir.me)
        //        note: The examples are correct, this is a new way
        //        note: This function deviates from PHP in returning a copy of the array instead
        //        note: of acting by reference and returning true; this was necessary because
        //        note: IE does not allow deleting and re-adding of properties without caching
        //        note: of property position; you can set the ini of "phpjs.strictForIn" to true to
        //        note: get the PHP behavior, but use this only if you are in an environment
        //        note: such as Firefox extensions where for-in iteration order is fixed and true
        //        note: property deletion is supported. Note that we intend to implement the PHP
        //        note: behavior by default if IE ever does allow it; only gives shallow copy since
        //        note: is by reference in PHP anyways
        //        note: Since JS objects' keys are always strings, and (the
        //        note: default) SORT_REGULAR flag distinguishes by key type,
        //        note: if the content is a numeric string, we treat the
        //        note: "original type" as numeric.
        //  depends on: i18n_loc_get_default
        //  depends on: strnatcmp
        //   example 1: data = {d: 'lemon', a: 'orange', b: 'banana', c: 'apple'};
        //   example 1: data = ksort(data);
        //   example 1: $result = data
        //   returns 1: {a: 'orange', b: 'banana', c: 'apple', d: 'lemon'}
        //   example 2: ini_set('phpjs.strictForIn', true);
        //   example 2: data = {2: 'van', 3: 'Zonneveld', 1: 'Kevin'};
        //   example 2: ksort(data);
        //   example 2: $result = data
        //   returns 2: {1: 'Kevin', 2: 'van', 3: 'Zonneveld'}
       
        var tmp_arr = {},
          keys = [],
          sorter, i, k, that = this,
          strictForIn = false,
          populateArr = {};
       
        switch (sort_flags) {
        case 'SORT_STRING':
          // compare items as strings
          sorter = function (a, b) {
            return that.strnatcmp(a, b);
          };
          break;
        case 'SORT_LOCALE_STRING':
          // compare items as strings, original by the current locale (set with  i18n_loc_set_default() as of PHP6)
          var loc = this.i18n_loc_get_default();
          sorter = this.php_js.i18nLocales[loc].sorting;
          break;
        case 'SORT_NUMERIC':
          // compare items numerically
          sorter = function (a, b) {
            return ((a + 0) - (b + 0));
          };
          break;
          // case 'SORT_REGULAR': // compare items normally (don't change types)
        default:
          sorter = function (a, b) {
            var aFloat = parseFloat(a),
              bFloat = parseFloat(b),
              aNumeric = aFloat + '' === a,
              bNumeric = bFloat + '' === b;
            if (aNumeric && bNumeric) {
              return aFloat > bFloat ? 1 : aFloat < bFloat ? -1 : 0;
            } else if (aNumeric && !bNumeric) {
              return 1;
            } else if (!aNumeric && bNumeric) {
              return -1;
            }
            return a > b ? 1 : a < b ? -1 : 0;
          };
          break;
        }
       
        // Make a list of key names
        for (k in inputArr) {
          if (inputArr.hasOwnProperty(k)) {
            keys.push(k);
          }
        }
        keys.sort(sorter);
       
        // BEGIN REDUNDANT
        this.php_js = this.php_js || {};
        this.php_js.ini = this.php_js.ini || {};
        // END REDUNDANT
        strictForIn = this.php_js.ini['phpjs.strictForIn'] && this.php_js.ini['phpjs.strictForIn'].local_value && this.php_js
          .ini['phpjs.strictForIn'].local_value !== 'off';
        populateArr = strictForIn ? inputArr : populateArr;
       
        // Rebuild array with sorted key names
        for (i = 0; i < keys.length; i++) {
          k = keys[i];
          tmp_arr[k] = inputArr[k];
          if (strictForIn) {
            delete inputArr[k];
          }
        }
        for (i in tmp_arr) {
          if (tmp_arr.hasOwnProperty(i)) {
            populateArr[i] = tmp_arr[i];
          }
        }
       
        return strictForIn || populateArr;
    }
    
};

module.exports = SignScript;

构造源串

//生成源串 str

var SignScript = require("SignScript");

let boo = SignScript.ksort(signInfo); //使用ksort算法根据键值排序

let str = "";

//遍历所有键值 拼接

for(let i in boo){

      str += i + "=" + boo[i] + "&";

}

str = str.substring(0,str.length-1); 

 

得到的str就是拼接好的源串,格式为a=XXX&b=XX&c=XXX,接下来进行第二步,将得到的源串使用sha256withRSA算法签名。

根据公钥加密私钥解密,私钥签名公钥验签的原则,使用私钥给源串加签名。这里我们用到jsrsasign这个东西,提供给了我们签名算法。如果需要加密则使用jsencrypt.js实现。我们这里只需要签名,所以只用jsrsasign,这里可以下载到jsrsasign,提供了例子:https://kjur.github.io/jsrsasign/,签名用到的就是KJUR.crypto.Signature类,API参考:https://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html。本地代码导入jsrsasign类,将jsrsasign.js直接放在自己的目录下,在用到签名的地方导入。我直接就用的var jsrsasign  = require("jsrsasign");

实例化signature :

let signature=new jsrsasign.KJUR.crypto.Signature({alg:"SHA256withRSA","prov": "cryptojs/jsrsa","prvkeypem": keyPem});

kevPem是你的私钥,华为快应用申请的支付服务后可以看到,kevPem前后要分别加上-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY----,不然会报错。

接下来传入需要签名的字符串,也就是上边我们得到的源串:

signature.updateString(str);

签名:let keys = signature.sign();

在得到我们的签名后,还要对其进行base64编码,直接调用jsrsasign 的hex2b64方法,返回的字符串就是我们最终得到的签名值。let sign = jsrsasign.hex2b64(keys);

sign值就是我们得到的签名值。到这里签名就结束了。

将sign值赋给orderInfo的sign字段,调用华为支付方法hbs.hwPay()方法。在回调中做相应的操作就可以了。

回调传回的参数中,会返回你传过去的requestId值,requestId通过ret.result.requestId值获得。它这个回调包了两层,回调传回的ret是个obj,遍历ret只有一个,key为result,value还是一个obj,要再遍历ret.result才是到数据层。可以在回调中遍历查看键值。

得到了requestId值,再做出相应的操作,比如下发道具什么的,支付就算是完成了。

你可能感兴趣的:(华为快应用(2)-本地接入支付)