移动APP 微信支付完整过程(wxPay 方案一)

摘要:
前两天,我们开始为手机APP进行微信支付,在这个过程中遇到了一些问题。例如,在付款过程中,返回值总是-1{status:false}。这些问题已经解决。

前两天开始做移动端APP的微信支付,过程中遇到了一些问题,比如支付的过程中返回值总是:-1 {status:false},这些问题已经得到了解决。前人栽树,后人尽管乘凉,那么分享一下整个支付过程(wxPay 方案一):

1、申请微信开发平台的账号、创建移动应用、申请开发者资质认证(整个过程APICLOUD官方网站已经给出了相当明确的操作步骤,与实际操作没有差异,按照文档一步一步来,是没有问题的),附带链接地址:http://docs.apicloud.com/Others/Open-SDK-Integration-Guide/weChat

2、配置移动应用中 config.xml 文件

<feature name="wxPay">
    <param name="urlScheme" value="***"/>
    <param name="apiKey" value="***"/>
    <param name="apiSecret" value="***"/>
  </feature>

复制代码


配置获取方式说明以及截图:从微信开发平台获取,登录微信开发平台 —>管理中心—>移动应用—>查看(urlScheme的值和apiKey相同)(微信开发平台链接:https://open.weixin.qq.com/

移动APP 微信支付完整过程(wxPay 方案一)第1张

3、getOrderId(),将获取预支付订单号,建议将获取预支付订单号放置服务器端执行。(服务端代码如下:)

$dataArr = array(
    'appid' => $appId,
    'mch_id' => $mchId,
    'nonce_str' => getNonceStr(),
    'body' => $body,
    'attach' => $attach,
    'out_trade_no' => getNonceStr(),
    'total_fee' => $totalFee,
    'spbill_create_ip' => $cIp,
    'notify_url' => $url,
    'trade_type' => 'APP'
);


//转XML格式
function createXML($rootNode, $arr)
{
    //创建一个文档,文档时xml的,版本号为1.0,编码格式utf-8
    $xmlObj = new DOMDocument('1.0', 'UTF-8');
    //创建根节点
    $Node = $xmlObj->createElement($rootNode);
    //把创建好的节点加到文档中
    $root = $xmlObj->appendChild($Node);
    //开始把数组中的数据加入文档
    foreach ($arr as $key => $value) {
        //如果是$value是一个数组
        if (is_array($value)) {
            //先创建一个节点
            $childNode = $xmlObj->createElement($key);
            //将节点添加到$root中
            $root->appendChild($childNode);
            //循环添加数据
            foreach ($value as $key2 => $val2) {
                //创建节点的同时添加数据
                $childNode2 = $xmlObj->createElement($key2, $val2);
                //将节点添加到$childNode
                $childNode->appendChild($childNode2);
            }
        } else {
            //创建一个节点,根据键和值
            $childNode = $xmlObj->createElement($key, $value);
            //把节点加到根节点
            $root->appendChild($childNode);
        }
    }
    //把创建好的xml保存到本地
    $xmlObj->save('xml/log.xml');
    $str = $xmlObj->saveXML();
//        echo $str;
    //返回xml字符串
    return $str;
}


//封装签名算法
function MakeSign($arr)
{
    //签名步骤一:按字典序排序参数
    ksort($arr);
    $string = ToUrlParams($arr);
    //签名步骤二:在string后加入KEY
    $string = $string . "&key=" . $key;
    //签名步骤三:MD5加密
    $string = md5($string);
    //签名步骤四:所有字符转为大写
    $result = strtoupper($string);
    return $result;
}

/**
* 格式化参数格式化成url参数
*/
function ToUrlParams($arr)
{
    $buff = "";
    foreach ($arr as $k => $v) {
        if ($k != "sign" && $v != "" && !is_array($v)) {
            $buff .= $k . "=" . $v . "&";
        }
    }

    $buff = trim($buff, "&");
    return $buff;
}


//随机字符串(不长于32位)
function getNonceStr($length = 32)
{
    $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    $str = "";
    for ($i = 0; $i < $length; $i++) {
        $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
    }
    return $str;
}


function curl($url, $post_data)
{


    $headerArray = array(
        'Accept:application/json, text/javascript, */*',
        'Content-Type:application/x-www-form-urlencoded',
        'Referer:https://mp.weixin.qq.com/'
    );

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    // 对认证证书来源的检查,0表示阻止对证书的合法性的检查。
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    // 从证书中检查SSL加密算法是否存在
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//关闭直接输出
    curl_setopt($ch, CURLOPT_POST, 1);//使用post提交数据
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);//设置 post提交的数据
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.69 Safari/537.36');//设置用户代理
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray);//设置头信息


    $loginData = curl_exec($ch);//这里会返回token,需要处理一下。


    return $loginData;

    $token = array_pop($token);
    curl_close($ch);


}

/**
* 解析xml文档,转化为对象
* @param  String $xmlStr xml文档
* @return Object         返回Obj对象
*/
function xmlToObject($xmlStr)
{
    if (!is_string($xmlStr) || empty($xmlStr)) {
        return false;
    }
    // 由于解析xml的时候,即使被解析的变量为空,依然不会报错,会返回一个空的对象,所以,我们这里做了处理,当被解析的变量不是字符串,或者该变量为空,直接返回false
    libxml_disable_entity_loader(true);
    $postObj = json_decode(json_encode(simplexml_load_string($xmlStr, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    //将xml数据转换成对象返回
    return $postObj;
}




//=====================执行=======================
$sign = MakeSign($dataArr);//签名生成
$dataArr['sign'] = $sign;

$xmlStr = createXML('xml', $dataArr);//统一下单xml数据生成
$reArr = explode('?>', $xmlStr);
$reArr = end($reArr);

$xml = curl('https://api.mch.weixin.qq.com/pay/unifiedorder', $reArr);//发送请求 统一下单数据

//解析返回的xml字符串
$re = xmlToObject($xml);

//判断统一下单是否成功
if ($re['result_code'] == 'SUCCESS') {

    //支付请求数据
    $payData = array(
        'appid' => $re['appid'],
        'partnerid' => $re['mch_id'],
        'prepayid' => $re['prepay_id'],
        'noncestr' => getNonceStr(),
        'package' => 'Sign=WXPay',
        'timestamp' => time()
    );


    //生成支付请求的签名
    $paySign = MakeSign($payData);

    $payData['sign'] = $paySign;

    //拼接成APICLOUD所需要支付数据请求
    $payDatas = array(
        'apiKey' => $re['appid'],
        'orderId' => $re['prepay_id'],
        'mchId' => $re['mch_id'],
        'nonceStr' => $payData['noncestr'],
        'package' => 'Sign=WXPay',
        'timeStamp' => $payData['timestamp'],
        'sign' => $paySign
    );

    //返回支付请求数据
    echo json_encode($payDatas);
} else {
    $re['payData'] = "error";
    echo json_encode($re);
}
复制代码

4、预支付下单成功后,将拼接好的支付请求数据返回,也就是上述代码中数组$payDatas(注意:第二次参与签名的字段是:appid、partnerid、prepayid、noncestr、package、timestamp),app端代码如下:

$.ajax({
            url:url,
            data:{
                body:body,
                attach:attach,
                total_fee:total_fee
            },
            dataType:"json",
            type:"post",
            success:function(data){


                if(data.payData != "error"){
                    var wxPay = api.require('wxPay');
                    wxPay.payOrder(data, function(ret, err) {

                        if (ret.status) {
                            //支付成功
                            alert('支付成功');
                            }



                        } else {
                            alert(err.code);

复制代码

5、以上描述,已经亲测没有问题,如果代码或叙述有问题的,欢迎各位大神指教批评;如果有帮到各位初学者的不胜荣幸;另外说下我之前遇到过支付过程中返回-1的问题:

官网上面payOrder()的参数为:appKey、orderId、mchId、nonceStr、timeStamp、package,就会以为参与第二次支付签名的参数是这些,但其实并不是,

那么参与第二次支付签名的参数是:appid、partnerid、prepayid、noncestr、package、timestamp,

生成签名后,需要将payOrder()所需要的参数一一对应重新填写(appKey==appid、orderId==prepayid、mchId==partnerid、nonceStr==noncestr、package==package、timeStamp==timestamp)。

免责声明:文章转载自《移动APP 微信支付完整过程(wxPay 方案一)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Shell命令Vue-CLI 3.x 设置反向代理下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

命名空间(app_name)和实例命名空间(namespace)

先把官网上对应用命名空间(app_name)和实例命名空间(namespace)的解释贴上: app_name(应用命名空间)通常在app.urls模块中指定,如: app_name = "test" //应用命名空间 urlpatterns = [ path("article1/", views.test, name="url_a"), ]...

仿华为 USB mode 实现方法

极力推荐文章:欢迎收藏Android 干货分享 阅读5分钟,每日十点、和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 一、实现效果 二、主要实现思路 三、主要实现代码 四、在Framework 层添加资源的方法 一、实现效果 仿华为USB Mode弹窗实现效果如...

java之拦截器Interceptor

1,拦截器的概念java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截然后再之前或者之后加入某些操作。目前,我们需要掌握的主要...

线程工具类ThreadUtils

1.pom引入guava依赖 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.0</version>...

软件测试方案模板

第一章 概述 ​ 软件的错误是不可避免的,所以必须经过严格的测试。通过对本软件的测试,尽可能的发现软件中的错误,借以减少系统内部各模块的逻辑,功能上的缺陷和错误,保证每个单元能正确地实现其预期的功能。检测和排除子系统(或系统)结构或相应程序结构上的错误,使所有的系统单元配合合适,整体的性能和功能完整。并且使组装好的软件的功能与用户要求(即常说的产品策划案)...

iOS自动化探索(十)代码覆盖率统计

iOS APP代码覆盖率统计 今年Q3季度领导给加了个任务要做前后端代码覆盖率统计, 鉴于对iOS代码比较熟就选择先从iOS端入手,折腾一整天后终于初步把流程跑通了记录如下 覆盖率监测的原理 Xcode中配置编译选项后,编译后会为每个可执行文件生成对应的.gcno文件;之后在代码中调用覆盖率分发函数,会生成对应的.gcda文件。 gcno:包含基本的块信...