微信二維碼支付(native方式)


1.微信支付的官網對接手冊:

地址:https://pay.weixin.qq.com/wiki/doc/api/index.html

微信對接分多中方式,而native是調用微信支付服務在網頁生成二維碼,客戶掃描二維碼支付。

2.准備工作

(1)申請服務號,需要審核認證,300塊錢。

(2)服務號申請通過后,在微信公眾平台開通微信支付

開通參考地址:https://jingyan.baidu.com/album/e8cdb32b0bb7de37042bad7b.html?picindex=3

簡單說下開通流程,需要幾個重要信息,身份證正反面照片,一個對公的銀行賬戶和卡號,申請提交后等待3-5個工作日進行審核。開通的時候回填一個郵箱,開通成功后回把一些信息發到郵箱上面。

 

(3)開通微信支付的郵箱接收到的商品平台信息:

開通之后,APPID是知道了,商戶號也知道了。 

(4)登錄微信商用平台

地址:https://pay.weixin.qq.com/ 

去設置API密匙,下載證書,密匙設置好后不會顯示,所以記得保存。

注意:證書是退款是用到的,不光退款,是你的錢往外出的時候用到證書,可以不用管,下面會講到退款怎么處理。

設置回調接口,就是微信支付成功之后,微信會回調,填寫一個回調地址。

此時,API密匙有了,簽名加密方式就用MD5就行,證書也有了。

(5)另外需要的參數

還剩一個開發者密碼:

這個應該是申請服務號之后設置的,設置之后不會顯示,所以提前需要保存。(我是用公司的服務號,都是開通好的,但是不知道開發者密碼,只能選擇重置)

 重置:

(6)參數已經全了,說一些題外的。

微信分公眾平台,開放平台,商戶平台總共三個平台。了解一下三個平台的區別。

微信三個平台區分(開放,公眾,商戶平台):https://blog.csdn.net/atongmu2017/article/details/94728996

ps:微信開放平台中可以在查看移動應用中去開通微信支付功能,但是這個是對接微信支付的另一種方式,好像是app拉起微信支付,類似於外賣下單支付的時候跳到微信手機客戶端的支付界面。(注意這個區分)

查看界面:

3.下載 SDK

地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1

下載的壓縮包解壓出來有幾個類:

扔到項目下:

我項目用的是jdk1.8,WXPayXmlUtil這個類會報錯,提示XMLConstants.FEATURE_SECURE_PROCESSING找不到。

 解決辦法:把下面這個jar包從libraries中移除,報錯消失。消失之后,再次加入libraries中,也不再報錯。

4.生成訂單二維碼

頁面請求生成二維碼有關的類:

 CommonUtil.java

有兩個方法,一個是發送http請求,用於發送xml參數給微信服務器,另一個是獲取ip,xml參數中有個參數是ip

 

 
package com.jeeplus.modules.wxpay;
 
 
 
import java.io.BufferedReader;
 
import java.io.InputStream;
 
import java.io.InputStreamReader;
 
import java.io.OutputStream;
 
import java.net.URL;
 
import java.util.Iterator;
 
import java.util.Map;
 
import java.util.Set;
 
import java.util.SortedMap;
 
 
 
import javax.net.ssl.HttpsURLConnection;
 
import javax.servlet.http.HttpServletRequest;
 
import org.apache.commons.lang.StringUtils;
 
import third.wxpay.WXPayUtil;
 
 
 
public class CommonUtil {
 
 
 
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
 
try {
 
URL url = new URL(requestUrl);
 
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
 
conn.setDoOutput(true);
 
conn.setDoInput(true);
 
conn.setUseCaches(false);
 
// 設置請求方式(GET/POST)
 
conn.setRequestMethod(requestMethod);
 
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
 
// 當outputStr不為null時向輸出流寫數據
 
if (null != outputStr) {
 
OutputStream outputStream = conn.getOutputStream();
 
// 注意編碼格式
 
outputStream.write(outputStr.getBytes("UTF-8"));
 
outputStream.close();
 
}
 
// 從輸入流讀取返回內容
 
InputStream inputStream = conn.getInputStream();
 
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
 
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
 
String str = null;
 
StringBuffer buffer = new StringBuffer();
 
while ((str = bufferedReader.readLine()) != null) {
 
buffer.append(str);
 
}
 
// 釋放資源
 
bufferedReader.close();
 
inputStreamReader.close();
 
inputStream.close();
 
inputStream = null;
 
conn.disconnect();
 
return buffer.toString();
 
} catch (Exception e) {
 
e.printStackTrace();
 
}
 
return null;
 
}
 
 
 
 
 
/**
 
* 獲取ip
 
* @param request
 
* @return
 
*/
 
public static String getIp(HttpServletRequest request) {
 
if (request == null)
 
return "";
 
String ip = request.getHeader("X-Requested-For");
 
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
 
ip = request.getHeader("X-Forwarded-For");
 
}
 
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
 
ip = request.getHeader("Proxy-Client-IP");
 
}
 
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
 
ip = request.getHeader("WL-Proxy-Client-IP");
 
}
 
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
 
ip = request.getHeader("HTTP_CLIENT_IP");
 
}
 
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
 
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
 
}
 
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
 
ip = request.getRemoteAddr();
 
}
 
return ip;
 
}
 
 
 
}

 

ConfigUtil.java

存放一些支付參數和回調接口信息

 

 
package com.jeeplus.modules.wxpay;
 
 
 
public class ConfigUtil {
 
/**
 
* 服務號相關信息
 
*/
 
public final static String APPID = "";//服務號的應用號
 
public final static String MCH_ID = "";//商戶號
 
public final static String APP_SECRECT = "";//服務號的應用密碼
 
public final static String API_KEY = "";//API密鑰
 
public final static String SIGN_TYPE = "MD5";//簽名加密方式
 
public final static String CERT_PATH = "D:/project/cert/apiclient_cert.p12";//微信支付證書存放路徑地址
 
 
 
public final static String TOKEN = "";//服務號的配置token
 
//微信支付統一接口的回調action
 
//填寫自己網站的接口
 
public final static String NOTIFY_URL = "http://www.baidu.com";
 
 
 
}

 

MatrixToImageWriter.java

地址變成二維碼圖片的類,用到 com.google.zxing.common.BitMatrix這個類,用到zxing這個jar包

package com.jeeplus.modules.wxpay;
 
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.OutputStream;
import java.io.IOException;
import java.util.Hashtable;
import java.awt.image.BufferedImage;
 

public final class MatrixToImageWriter {
 
private static final int BLACK = 0xFF000000;
 
private static final int WHITE = 0xFFFFFFFF;
 
private MatrixToImageWriter() {}
 
public static BufferedImage toBufferedImage(BitMatrix matrix) {
 
int width = matrix.getWidth();
 
int height = matrix.getHeight();
 
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
 
for (int x = 0; x < width; x++) {
 
for (int y = 0; y < height; y++) {
 
image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
 
}
 
}
 
return image;
 
}
 
public static void writeToFile(BitMatrix matrix, String format, File file)
 
throws IOException {
 
BufferedImage image = toBufferedImage(matrix);
 
if (!ImageIO.write(image, format, file)) {
 
throw new IOException("Could not write an image of format " + format + " to " + file);
 
}
 
}
 

 
public static void writeToStream(BitMatrix matrix, String format, OutputStream stream)
 
throws IOException {
 
BufferedImage image = toBufferedImage(matrix);
 
if (!ImageIO.write(image, format, stream)) {
 
throw new IOException("Could not write an image of format " + format);
 
}
 
}
 
 
 
public static void main(String[] args) throws Exception {
 
String text = "www.baidu.com";
 
int width = 300;
 
int height = 300;
 
String format = "gif";
 
Hashtable hints = new Hashtable();
 
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
 
BitMatrix bitMatrix = new MultiFormatWriter().encode(text,
 
BarcodeFormat.QR_CODE, width, height, hints);
 
File outputFile = new File("d:"+File.separator+"new.gif");
 
MatrixToImageWriter.writeToFile(bitMatrix, format, outputFile);
 
}
 
}

 

 

創建訂單的方法:

private void doWx(HttpServletRequest request,HttpServletResponse response) throws Exception {
 
String number=request.getParameter("number")==null?"":request.getParameter("number");
 
Productorder p = productorderService.findUniqueByProperty("number", number);
 
Date date=new Date();
 
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
 
String timeStart=sdf.format(date);
 
Calendar cal=Calendar.getInstance();
 
cal.add(Calendar.DAY_OF_MONTH, 1);
 
Date date1=cal.getTime();
 
String timeExpire=sdf.format(date1);
 
SortedMap<String,String> parameters = new TreeMap<String,String>();
 
parameters.put("appid", ConfigUtil.APPID);
 
parameters.put("body", p.getPname());
 
parameters.put("mch_id", ConfigUtil.MCH_ID);
 
parameters.put("out_trade_no", number);
 
parameters.put("spbill_create_ip",CommonUtil.getIp(request));
 
DecimalFormat df = new DecimalFormat("#");
 
parameters.put("total_fee", df.format(Double.parseDouble(p.getOrdermoney())*100));
 
parameters.put("trade_type", "NATIVE");
 
parameters.put("time_expire", CommonUtil.getOrderExpireTime(startData,5*60*1000L));//二維碼過期時間5分鍾
 
parameters.put("nonce_str", WXPayUtil.generateNonceStr());
 
parameters.put("notify_url", ConfigUtil.NOTIFY_URL);//支付成功后回調的action,與JSAPI相同
 
String generateSignature = WXPayUtil.generateSignature(parameters, ConfigUtil.API_KEY, SignType.MD5);
 
parameters.put("sign", generateSignature);
 
String generateSignedXml = WXPayUtil.generateSignedXml(parameters, ConfigUtil.API_KEY);
 
System.out.println("微信支付預下單請求xml格式::"+generateSignedXml);
 
String result =CommonUtil.httpsRequest(ConfigUtil.UNIFIED_ORDER_URL, "POST", generateSignedXml);
 
System.out.println(result);
 
Map<String, String> map;
 
try {
 
 
 
map = WXPayUtil.xmlToMap(result);
 
String returnCode = map.get("return_code");
 
String resultCode = map.get("result_code");
 
if(returnCode.equalsIgnoreCase("SUCCESS")&&resultCode.equalsIgnoreCase("SUCCESS")){
 
String codeUrl = map.get("code_url");
 
//TODO 拿到codeUrl,寫代碼生成二維碼
 
System.out.println("codeUrl="+codeUrl);
 
int width = 300;
 
int height = 300;
 
//二維碼的圖片格式
 
String format = "JPEG";
 
Hashtable hints = new Hashtable();
 
//內容所使用編碼
 
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
 
BitMatrix bitMatrix = new MultiFormatWriter().encode(codeUrl,
 
BarcodeFormat.QR_CODE, width, height, hints);
 
// response.setContentType("image/JPEG");
 
MatrixToImageWriter.writeToStream(bitMatrix, format, response.getOutputStream());
 
 
 
}
 
} catch (Exception e) {
 
e.printStackTrace();
 
}

 

 

可以把生成二維碼的方法寫成一個接口,測試調用接口,頁面會顯示二維碼

掃描二維碼:

5.創建訂單生成二維碼注意的問題

(1)簽名算法,需要參數拼接起來,加上密匙參數,拼接后MD5加密得到sign這個參數。而其他參數拼接的時候注意要按參數名ASCII碼從小到大排序(字典序),所以用到SortedMap

SortedMap<String,String> parameters = new TreeMap<String,String>();

(2)測試的時候生成二維碼,之后修改訂單金額,請求后顯示不出來二維碼,微信返回信息如下,原因是同一個訂單不允許前后兩次請求金額不同。

<err_code><![CDATA[INVALID_REQUEST]]></err_code><err_code_des><![CDATA[201 商戶訂單號重復]]></err_code_des>

(3)total_fee這個訂單金額參數需要注意,單位是分,所以需要把元轉換成分。

解決辦法:字符串金額轉換成double類型,乘以100,然后去掉小數點后的一個零

  1.  
    DecimalFormat df = new DecimalFormat("#");
  2.  
    parameters.put( "total_fee", df.format(Double.parseDouble(p.getOrdermoney())*100));

有個特別容易出錯的地方,如果金額是12.34,轉換成double類型,然后乘100,你以為最后返回的是1234這個數,其實是1234.0,然后傳給微信也是不成功的。必須是整數。

下面是金額不對的時候,微信返回的錯誤提示信息: 

<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[invalid total_fee]]></return_msg>

6.回調接口

支付成功之后,微信會回調你在商用平台上設置的微信回調接口,里面處理支付成功后的業務邏輯。下面的提供參考: 

/**
 
* 微信回調接口
 
* http://127.0.0.1:8080/qcloud/a/payInterface/notifyWeiXinPay
 
* @param request
 
* @param response
 
* @return
 
* @throws Exception
 
*/
 
@RequestMapping(value="/notifyWeiXinPay",produces="text/html;charset=utf-8")
 
@ResponseBody
 
public String notifyWeiXinPay(HttpServletRequest request, HttpServletResponse response) throws Exception {
 
Map<String,String> return_data = new HashMap<String,String>();
 
//讀取參數
 
InputStream inputStream ;
 
StringBuffer sb = new StringBuffer();
 
inputStream = request.getInputStream();
 
String s ;
 
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
 
while ((s = in.readLine()) != null){
 
sb.append(s);
 
}
 
in.close();
 
inputStream.close();
 
 
 
//解析xml成map
 
Map<String, String> map = WXPayUtil.xmlToMap(sb.toString());
 
//判斷簽名是否正確
 
// if(true) {
 
 
 
if(WXPayUtil.isSignatureValid(map, ConfigUtil.API_KEY)) {
 
if(!map.get("return_code").toString().equals("SUCCESS")){
 
return_data.put("return_code", "FAIL");
 
return_data.put("return_msg", "return_code不正確");
 
}else{
 
if(!map.get("result_code").toString().equals("SUCCESS")){
 
return_data.put("return_code", "FAIL");
 
return_data.put("return_msg", "result_code不正確");
 
return WXPayUtil.mapToXml(return_data);
 
}
 
 
 
String orderno = (String)map.get("out_trade_no");//商戶訂單號
 
String transaction_id = (String)map.get("transaction_id");//微信支付訂單號
 
String time_end = (String)map.get("time_end");//支付完成時間yyyyMMddHHmmss
 
BigDecimal total_fee = new BigDecimal(map.get("total_fee").toString());
 
//付款完成后,支付寶系統發送該交易狀態通知
 
Productorder order = productorderService.findUniqueByProperty("order_no", orderno);
 
if(order==null) {
 
System.out.println("訂單不存在");
 
return_data.put("return_code", "FAIL");
 
return_data.put("return_msg", "訂單不存在");
 
return WXPayUtil.mapToXml(return_data);
 
}
 
 
 
BigDecimal num = new BigDecimal("100");
 
BigDecimal ordermoney = new BigDecimal(order.getOrdermoney());
 
ordermoney = ordermoney.multiply(num);
 
//訂單已經支付
 
if(order.getOrderstatus().equals("1")){
 
System.out.println("訂單已經支付");
 
return_data.put("return_code", "SUCCESS");
 
return_data.put("return_msg", "OK");
 
return WXPayUtil.mapToXml(return_data);
 
}
 
//如果支付金額不等於訂單金額返回錯誤
 
if(ordermoney.compareTo(total_fee)!=0){
 
System.out.println("資金異常");
 
return_data.put("return_code", "FAIL");
 
return_data.put("return_msg", "金額異常");
 
return WXPayUtil.mapToXml(return_data);
 
}
 
//更新訂單信息
 
try {
 
System.out.println("更新訂單信息");
 
SimpleDateFormat sdf1=new SimpleDateFormat("yyyyMMddHHmmss");
 
SimpleDateFormat sdf2=new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
 
order.setOrderstatus("1");
 
order.setPaytime(sdf2.format(sdf1.parse(time_end)));
 
order.setPaymentway("1");
 
productorderService.update(order);
 
 
 
System.out.println("插入已經支付的訂單表");
 
//插入已經支付的訂單表(product_order_pay)
 
List<String> goodsIds = productgoodsService.getGoodsIdsByOrderno(orderno);
 
for (String gid : goodsIds) {
 
Productorderpay productorderpay = new Productorderpay();
 
productorderpay.setUserid(order.getUserid());
 
productorderpay.setPpid(gid);
 
productorderpay.setEndtime(order.getOrderendtime());
 
productorderpayService.insert(productorderpay);
 
}
 
 
 
return_data.put("return_code", "SUCCESS");
 
return_data.put("return_msg", "OK");
 
return WXPayUtil.mapToXml(return_data);
 
} catch (Exception e) {
 
e.printStackTrace();
 
return_data.put("return_code", "FAIL");
 
return_data.put("return_msg", "更新訂單失敗");
 
return WXPayUtil.mapToXml(return_data);
 
}
 
}
 
} else{
 
System.out.println("通知簽名驗證失敗");
 
return_data.put("return_code", "FAIL");
 
return_data.put("return_msg", "簽名錯誤");
 
}
 
return WXPayUtil.mapToXml(return_data);
 
}

 

 

7.支付頁面

(1)顯示二維碼:頁面中img標簽來顯示二維碼,img的src指向的是生成二維碼的請求。

(2)查詢訂單支付狀態:同一個頁面,去寫一個定時異步請求方法,去查詢訂單是否支付成功,支付成功做下一步處理。

(3)頁面代碼參考: 

<body>
 
<!--nav-->
 
<jsp:include page="/eb_headerhs2017.jsp" />
 
<div class="section">
 
<div class="section_div">
 
<div class="section_div_top clear">
 
<p class="section_div_p">訂單提交成功,請盡快付款!訂單號:${orderNo}</p>
 
<p class="section_div_p2">
 
應付金額 <span class="section_div_span">${orderMoney}</span></p>
 
</div>
 
<div class="section_div_bottom clear">
 
<p class="section_bottom_p">微信支付</p>
 
<div class="QRcode">
 
<img class="QRcode_img"
 
src="填寫生成二維碼接口?orderNo=${orderNo}" alt="二維碼">
 
<div class="QRcode_div clear">
 
<img class="QRcode_div_img"
 
src="images/hs/weixinzhifuerweima_10.png" alt="">
 
<div class="QRcode_div_div">
 
<p>請使用微信掃一掃</p>
 
<p>掃描二維碼支付</p>
 
</div>
 
</div>
 
</div>
 
<img class="phone_saosao" src="images/hs/phone_saosao_03.png" alt="">
 
<p class="section_bottom_p2">選擇其他支付方式</p>
 
</div>
 
</div>
 
 
 
</div>
 
<script type="text/javascript">
 
var wxTM = setInterval(function() {
 
getWxPayStatus();
 
},5000)
 
function getWxPayStatus(){
 
jQuery.ajax({
 
type: 'POST',
 
url: "填寫查詢支付狀態接口?orderNo=${orderNo}",
 
dataType: 'json',
 
success: function(result){
 
if(result.res==1){
 
clearInterval(wxTM);
 
window.location.href="ebHsPay.jsp?payStatus=1&orderNo=${orderNo}";
 
}
 
}
 
});
 
}
 
</script>
 
<div class="con_bot"></div>
 
<!--bottom-->
 
<jsp:include page="/eb_footerhs2017.jsp" />
 
</body>

 

8.訂單支付狀態接口

微信提供了查詢訂單狀態的接口,但是一般不去對接微信。對接微信的只涉及一個生產二維碼接口。

怎么去查詢支付狀態,在支付回調的接口中已經知道訂單支付成功還是失敗,把狀態更新到數據庫對應的訂單數據中。查詢訂單狀態是從數據庫差的,而不是非得去對接微信的查詢訂單狀態接口。

9.退款

上面提到自己的賬戶往外掏錢(退款、發紅包)會用到證書,但是退款一般也不對接微信。

退款的業務邏輯:可以創建一個退款申請表,記錄用戶退款申請,項目中有這么一個版塊。讓使用項目管理員去查看這些數據,聯系用戶為什么退款,讓管理員自己處理,真正退款是在微信商用平台上面去退款。平台上有退款的功能,而不是去寫代碼對接微信退款。

原因:一方面不用寫這塊代碼。另一方面,萬一你這個網站退款的接口被黑會是個問題。還有就是退款請求不會太多,何必走接口。

10.其他

自己也是第一次對接微信,有些細節需要注意的地方,我是向經常做商品支付項目的公司同事詢問了解的。

支付這塊考慮詳細點,代碼的可擴展,復用等。越詳細越好。不至於之后客戶一提需求就改動這塊代碼,或者這塊代碼根本用不了。

(1)建表:一般是訂單表和商品表,訂單只存訂單的信息,商品去關聯訂單。比如考慮是否有優惠折扣,創建對應的表。

訂單表字段參考

 

 

(2)查詢用戶是否訂購過這個訂單

訂單表是從一開始數據是不會刪除的,里面的數據只會越來越多。里面有支付成功的訂單,超時支付失效的訂單等等。

比如,用戶訂購了一個視頻,查詢用戶是否訂購了這個視頻,是否能播放。不可能去查詢原始的訂單表,到后面數據量大了,查詢速度特別慢。需要另建一個表,里面只保存支付成功的訂單,一些關鍵信息,如訂單編號,訂單用戶,到期時間。去查詢這個表,之后可以把這個表里的過期訂單刪除。

(3)訂單編號

一開始我的訂單編號是隨機生成的十六位數字,但是不要這樣做。

訂單號要一眼能看到這個訂單的信息,比如BOOK20190511xxxx,VIDEO20180613xxx,當看到這個訂單就知道這個訂單是訂購的什么,訂購的時間。在訂單編號里面加上用戶信息等等,到時候去查詢這個訂單的時候,看到這個訂單編號大致先了解這個訂單的信息,而不是一堆隨機數據,什么信息也看不出來。

(4)支付從頁面到后台的流程

我看到一個電商平台的項目代碼,里面的流程可以參考下。

頁面用img的src屬性去請求一個controller的pay方法,這個方法中什么都沒做,只是處理下請求參數,然后然后請求到原來的頁面。二維碼怎么生成,在請求返回的過程中,攔截器攔截了請求,根據參數生成二維碼返回原來頁面。

 

11.補充

(1)微信回調

上面因為我只有一個類型的訂單,回調寫在回調的方法里,但是這樣寫不好。

回調方法處理是個入口,根據不同的訂單類型再去跳轉不同的回調處理方法。便於之后的擴展,調整修改方便,而不是一改動就去改統一的那個回調方法。

(2)手機app接微信支付

因為這種支付方式注意是網站生成二維碼,用戶掃描支付的。

手機app接微信支付,最好使接像上面提到的,類似美團的,訂外賣支付直接跳轉到微信。

現在這種方式也可以,需要注意一些地方:

①微信創建訂單接口,會返回一個支付地址,之前是把這個地址生成二維碼圖片展示,而手機app是直接打開這個地址,手機會跳到微信支付。

②支付成功的頁面,需要判斷是從網站來的還是手機來的,分別顯示不同的頁面。

③支付成功之后的回調,手機app會跳到空白頁,蘋果的會打開賽風瀏覽器顯示支付成功的頁面。再跳回app很多余

 

原文鏈接:https://blog.csdn.net/atongmu2017/article/details/94725934


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM