统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返回预支付订单号的接口,目前微信支付所有场景均使用这一接口。下面介绍的是其中APP的支付的配置与实现流程
前言
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返回预支付订单号的接口,目前微信支付所有场景均使用这一接口。下面介绍的是其中APP的支付的配置与实现流程
配置
1.首先登录微信开放平台,注册账号。
https://open.weixin.qq.com/
2.点击创建移动应用

3.获取到移动应用的APPID

4.打开前端uniapp的项目,在主目录下找到manifest.json文件->APP模块配置->Payment->微信支付->将微信开放平台的应用APPID填写在对应的位置

5.根据微信开放平台提供的工具对项目包的包名进行签名的获取



下载链接:https://developers.weixin.qq.com/doc/oplatform/Downloads/Android_Resource.html#%E7%AD%BE%E5%90%8D%E7%94%9F%E6%88%90%E5%B7%A5%E5%85%B7
安装完毕是这样的:输入您的应用包名进行签名的获取即可

6.申请开通微信支付


微信商户号绑定APPID

选择我的产品,申请开通APP、JSAPI支付

选择账户中心->api安全,进行证书与密钥的申请,v2/v3都可以申请,调用的api不同,并不冲突

到此为止关于app微信支付的配置就基本完成了。
流程实现(后端)(PHP)
- 创建Wechatpay.php文件,放到指定文件目录下(我是放到了extend目录)
| <?php |
| |
| class Wechatpay{ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function curl_https($url, $xml='', $useCert=false){ |
| |
| $ch = curl_init(); |
| |
| curl_setopt($ch, CURLOPT_TIMEOUT, 30); |
| curl_setopt($ch,CURLOPT_URL, $url); |
| |
| |
| curl_setopt($ch, CURLOPT_HEADER, FALSE); |
| |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); |
| |
| if(stripos($url,"https://")!==FALSE){ |
| curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); |
| curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); |
| curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); |
| }else{ |
| curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); |
| curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2); |
| } |
| if($useCert == true){ |
| |
| |
| curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); |
| curl_setopt($ch,CURLOPT_SSLCERT,""); |
| curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); |
| curl_setopt($ch,CURLOPT_SSLKEY,""); |
| } |
| |
| curl_setopt($ch, CURLOPT_POST, TRUE); |
| curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); |
| |
| $data = curl_exec($ch); |
| |
| if($data){ |
| curl_close($ch); |
| return $data; |
| } else { |
| $error = curl_errno($ch); |
| curl_close($ch); |
| |
| } |
| |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| function ToUrlParams($urlObj) |
| { |
| $buff = ""; |
| foreach ($urlObj as $k => $v) |
| { |
| if($k != "sign"){ |
| $buff .= $k . "=" . $v . "&"; |
| } |
| } |
| |
| $buff = trim($buff, "&"); |
| return $buff; |
| } |
| |
| |
| |
| function arrayToXml($arr) |
| { |
| $xml = "<xml>"; |
| foreach ($arr as $key=>$val) |
| { if (is_numeric($val)){ |
| $xml.="<".$key.">".$val."</".$key.">"; |
| }else{ |
| $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; |
| |
| } |
| |
| } |
| $xml.="</xml>"; |
| return $xml; |
| } |
| |
| |
| function xmlToArray($xml) |
| { |
| |
| libxml_disable_entity_loader(true); |
| $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); |
| return $values; |
| } |
| |
| |
| |
| |
| |
| function getRandString($len=12,$str='ABCDEFGHIJKLMNOPQRSTUVWYXZabcdefghijklmnopqrstuvwyxz1234567890'){ |
| $strlen=strlen($str)-1; |
| $string=''; |
| for ($i=0; $i < $len; $i++) { |
| $r=rand(1,$strlen); |
| $string=$string.$str[$r]; |
| } |
| return $string; |
| } |
| |
| |
| } |
2.定义公共变量
| private $config = array( |
| 'appid_app' => "wx******", |
| 'mch_id' => "*******", |
| 'api_key' => "*************", |
| 'notify_url' => 'https://***', |
| ); |
3.支付接口
| public function AppPay($busid,$price,$code,$type,$attach){ |
| $businessInfo=$this->BusinessModel->find($busid); |
| Loader::import('wechatpay.Wechatpay', EXTEND_PATH,".php"); |
| $wechatpay = new \Wechatpay(); |
| $url='https://api.mch.weixin.qq.com/pay/unifiedorder'; |
| $parameters = array( |
| 'appid' => $this->config["appid_app"], |
| 'mch_id' => $this->config['mch_id'], |
| 'nonce_str' => $wechatpay->getRandString(30), |
| 'body' => '购买商品测试', |
| 'out_trade_no' => $code, |
| 'total_fee' => $price * 100, |
| 'spbill_create_ip' => $this->get_client_ip(), |
| 'notify_url' => $this->config["notify_url"], |
| 'trade_type' => "APP", |
| 'sign_type' => "MD5", |
| 'attach' => $attach |
| ); |
| |
| |
| ksort($parameters); |
| |
| $String = $wechatpay->ToUrlParams($parameters); |
| |
| |
| $String = $String."&key=".$this->config['api_key']; |
| $String2=$String; |
| |
| $time=time(); |
| $parameters['sign']=strtoupper(md5($String)); |
| $xmlData=$wechatpay->arrayToXml($parameters); |
| $return=$wechatpay->xmlToArray($wechatpay->curl_https($url,$xmlData)); |
| if($return["return_code"]=="SUCCESS" && $return["result_code"]=="SUCCESS"){ |
| |
| $prepay_id = $return['prepay_id']; |
| |
| $signParams = array( |
| 'appid' => $this->config["appid_app"], |
| 'partnerid' => $this->config['mch_id'], |
| 'prepayid' => $return['prepay_id'], |
| 'package' => 'Sign=WXPay', |
| 'noncestr' => $wechatpay->getRandString(30), |
| 'timestamp' => (string)$time, |
| ); |
| |
| |
| ksort($signParams); |
| $signString = $wechatpay->ToUrlParams($signParams); |
| $signString = $signString . "&key=" . $this->config['api_key']; |
| $sign = strtoupper(md5($signString)); |
| |
| |
| $signParams['sign'] = $sign; |
| |
| |
| $this->result($signParams, '1', '二次签名成功!', 'json'); |
| }else{ |
| echo json_encode(array("status"=>false,"msg"=>$return)); |
| $this->result($return, '0', '签名失败!', 'json'); |
| } |
| } |
| |
| |
| |
| |
| |
| public function get_client_ip(){ |
| if ($_SERVER['REMOTE_ADDR']) { |
| $cip = $_SERVER['REMOTE_ADDR']; |
| } elseif (getenv("REMOTE_ADDR")) { |
| $cip = getenv("REMOTE_ADDR"); |
| } elseif (getenv("HTTP_CLIENT_IP")) { |
| $cip = getenv("HTTP_CLIENT_IP"); |
| } else { |
| $cip = "unknown"; |
| } |
| return $cip; |
| } |
- 支付回调
| |
| public function wxpaynotify(){ |
| $xml = file_get_contents('php://input'); |
| Loader::import('wechatpay.Wechatpay', EXTEND_PATH,".php"); |
| $wechatpay = new \Wechatpay(); |
| |
| $data = $wechatpay->xmlToArray($xml); |
| |
| $data_sign = $data['sign']; |
| |
| unset($data['sign']); |
| $sign = $wechatpay->ToUrlParams($data); |
| $payData=$sign; |
| $sign=strtoupper(md5($sign."&key=".$this->config["api_key"])); |
| |
| if ( ($sign===$data_sign) && ($data['result_code']=='SUCCESS') ) { |
| |
| |
| |
| $result = true; |
| }else{ |
| file_put_contents('payResult.tex','验签失败!'); |
| $result = false; |
| } |
| |
| if ($result) { |
| $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; |
| }else{ |
| $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>'; |
| } |
| echo $str; |
| |
| } |
流程实现(前端)(Vue)(APP)
| uni.getProvider({ |
| service: 'payment', |
| success: function(ress) { |
| |
| if (~ress.provider.indexOf('wxpay')) { |
| let orderInfo={ |
| "appid": result.data.appid, |
| "noncestr": result.data.noncestr, |
| "package": "Sign=WXPay", |
| "partnerid": result.data.partnerid, |
| "prepayid": result.data.prepayid, |
| "timestamp": result.data.timestamp, |
| "sign": result.data.sign |
| } |
| |
| uni.requestPayment({ |
| "provider": "wxpay", |
| "orderInfo": orderInfo, |
| success(res) { |
| |
| console.log('支付成功', res); |
| uni.showToast({ |
| title: '支付成功!', |
| icon: 'none', |
| duration: 1000 |
| }) |
| }, |
| fail(res) { |
| |
| console.log('支付失败', res); |
| uni.showToast({ |
| title: res.errMsg, |
| icon: 'none', |
| duration: 2000 |
| }) |
| } |
| }) |
| |
| } |
| } |
| }); |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验