微信APP支付服務端和Android 端詳解及其demo
最近在開發APP微信支付和支付寶支付,Android 端和後端都是我自己開發的,發現兩家公司的文件都不是很友好,特別是微信,接觸過或者開發過的人都應該有所體會。因此我特意把開發的過程梳理了,做下記錄,方便以後可能還用得到,同時也方便後來的一些開發者,希望如此吧。文章較長,耐心看吧,因為這篇文章涉及到了服務端和安卓端的開發。如果你是服務端開發者,那就只需要看服務端部分,如果是Android開發者,就只需要看Android部分即可。
這篇整理的是APP微信支付服務端和Android 端,文末有服務端和Android demo的下載連結。
本文為原創文章,轉載請註明來源。
1. 準備工作
微信支付開發需要用到應用id(appid)、商戶號(mch_id)和祕鑰(key),為了獲取這幾個重要的引數,需要我們做以下幾個步驟獲取。如果已經有了這幾個引數則可以直接跳過這一步。
1.建立應用(獲取appid)
要開發APP微信支付,需要在微信開放平臺(http://open.weixin.qq.com)上建立應用以獲得應用id。微信有幾個平臺,一定要搞清楚,否則開發過程會覺得很混亂。最好先把這幾個平臺的作用和幾個重要的名詞搞清楚,官方名詞解釋的連結:
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=2_2
註冊/登入開發平臺後進入管理中心建立應用,根據提示填寫相應資料後提交稽核,稽核結果一般三天工作日左右可以檢視。注意應用簽名不要搞錯,推薦使用官方工具生成,文末有工具下載的連結。
稽核通過之後,在管理中心頁面即可看到成功建立的應用,點選檢視進入詳情頁面即可看到appid,如圖:
2.申請商戶號
商戶號通過微信支付成功申請開通後獲得,通過後可以在申請的郵件中找到,也可以在微信商戶平臺/賬戶中心/賬戶設定/API安全中找到,就不貼圖了。
3.設定祕鑰
祕鑰由我們自己設定,可以在微信商戶平臺按照提示要求進行設定。也可按一下路徑設定:微信商戶平臺(https://pay.weixin.qq.com/)–>賬戶中心–>賬戶設定–>API安全–>金鑰設定
4.下載證書
我們服務端開發用的是官方封裝的SDK,支付部分需要用到證書,如果所有邏輯都是自己寫的話也可以不用,但是與支付相關的其他介面就必須用到了,所以乾脆都用證書的方式進行開發。在微信商戶平臺(pay.weixin.qq.com)–>賬戶中心–>賬戶設定–>API安全這個頁面有下載的按鈕,也不貼圖了。
二、梳理流程
商戶系統和微信支付系統主要互動說明:
步驟1:使用者在商戶APP中選擇商品,提交訂單,選擇微信支付。
步驟2:商戶後臺收到使用者支付單,呼叫微信支付統一下單介面。
步驟3:統一下單介面返回正常的prepay_id,再按簽名規範重新生成簽名後,將資料傳輸給APP。參與簽名的欄位名為appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式為Sign=WXPay
步驟4:商戶APP調起微信支付。
步驟5:商戶後臺接收支付通知。
步驟6:商戶後臺查詢支付結果。
補充說明:
1.商戶服務端主要負責步驟2、步驟3中的簽名、步驟5和步驟6的結果處理。在不少的應用中展示支付結果是不依賴於步驟6的,APP端調起支付後在回撥類中直接展示支付結果,這樣商戶服務端也可以不需要步驟6。雖然這樣基本都是沒什麼問題的,但是最好是按照官方的要求,展示支付結果要依賴於商戶後臺查詢的支付結果。
2.APP端主要負責步驟1和步驟4,如果支付結果依賴於商戶後臺的查詢結果,則還需要步驟6。
3.步驟3這一步驟,很多人在這裡被坑了,一定不要用預支付介面返回來的簽名,需要重新生成,而且參與的欄位有且只有上面提到的6個,而且都是小寫,其中時間戳的單位為秒—10位數,時間戳可以重新獲取。
三、 服務端的程式碼(為了簡化,這裡的支付結果不依賴於商戶後臺的查詢結果)
服務端開發的有兩種方式,其一是可以按照官方文件,所有邏輯都由自己來寫,其二是使用官方封裝的SDK開發。我選擇的是第二種,這個方便一些。
1.開發環境
開發工具 :IntelliJ IDEA
構建工具 :Maven
2.引入SDK依賴
2.1 Maven 構建
在pop.xml中新增
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
2.2如果使用Grade 構建,則在模組build.grade檔案中的dependencies 範圍內新增:
compile group: 'com.github.wxpay', name: 'wxpay-sdk', version: '0.0.3'
2.3如果是eclipse 或者 IDEA用Grade 構建的話,可以直接下載jar 再匯入,至於怎麼匯入jar 包,網上有很多教程,這裡略過。當然Maven也是可以jar包的,只是比較麻煩些,在我的支付寶支付開發文章裡有maven 環境下匯入jar包的教程。
微信支付SDK Jar包下載連結:
https://download.csdn.net/download/m_sicily/10643021
3.設定配置檔案,在呼叫官方封裝的SDK時需要
import com.github.wxpay.sdk.WXPayConfig;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class WXConfigUtil implements WXPayConfig {
private byte[] certData;
public static final String APP_ID = "應用id";
public static final String KEY = "祕鑰";
public static final String MCH_ID = "商戶id";
public WXConfigUtil() throws Exception {
String certPath = "證書地址";//從微信商戶平臺下載的安全證書存放的路徑
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
}
@Override
public String getAppID() {
return APP_ID;
}
//parnerid,商戶號
@Override
public String getMchID() {
return MCH_ID;
}
@Override
public String getKey() {
return KEY;
}
@Override
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
@Override
public int getHttpConnectTimeoutMs() {
return 8000;
}
@Override
public int getHttpReadTimeoutMs() {
return 10000;
}
}
4.後端生成的預支付訂單號以及非同步回撥
4.1控制層
import com.example.wxpay.module.service.WXserviceImpl;
import com.example.wxpay.module.util.WxMD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/v1/weixin")
public class WXController {
@Autowired
private WXserviceImpl wxPayService;
/**
* 統一下單
* 官方文件:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
* @param user_id
* @param total_fee
* @return
* @throws Exception
*/
@PostMapping("/apppay.json")
public Map<String, String> wxPay(@RequestParam(value = "userId") String user_id,
@RequestParam(value = "totalFee") String total_fee
) throws Exception {
String attach = "{\"user_id\":\"" + user_id + "\"}";
//請求預支付訂單
Map<String, String> result = wxPayService.dounifiedOrder(attach, total_fee);
Map<String, String> map = new HashMap<>();
WxMD5Util md5Util = new WxMD5Util();
//返回APP端的資料
//參加調起支付的簽名欄位有且只能是6個,分別為appid、partnerid、prepayid、package、noncestr和timestamp,而且都必須是小寫
//參加調起支付的簽名欄位有且只能是6個,分別為appid、partnerid、prepayid、package、noncestr和timestamp,而且都必須是小寫
//參加調起支付的簽名欄位有且只能是6個,分別為appid、partnerid、prepayid、package、noncestr和timestamp,而且都必須是小寫
map.put("appid", result.get("appid"));
map.put("partnerid", result.get("mch_id"));
map.put("prepayid", result.get("prepay_id"));
map.put("package", "Sign=WXPay");
map.put("noncestr", result.get("nonce_str"));
map.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));//單位為秒
// 這裡不要使用請求預支付訂單時返回的簽名
// 這裡不要使用請求預支付訂單時返回的簽名
// 這裡不要使用請求預支付訂單時返回的簽名
map.put("sign", md5Util.getSign(map));
map.put("extdata", attach);
return map;
}
/**
* 支付非同步結果通知,我們在請求預支付訂單時傳入的地址
* 官方文件 :https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_7&index=3
*/
@RequestMapping(value = "/notify.json", method = {RequestMethod.GET, RequestMethod.POST})
public String wxPayNotify(HttpServletRequest request, HttpServletResponse response) {
String resXml = "";
try {
InputStream inputStream = request.getInputStream();
//將InputStream轉換成xmlString
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
resXml = sb.toString();
String result = wxPayService.payBack(resXml);
return result;
} catch (Exception e) {
System.out.println("微信手機支付失敗:" + e.getMessage());
String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[報文為空]]></return_msg>" + "</xml> ";
return result;
}
}
}
4.2 服務層
import java.util.Map;
public interface WXservice {
Map<String, String> dounifiedOrder(String attach, String total_fee) throws Exception;
String payBack(String notifyData);
}
import com.example.wxpay.module.util.WXConfigUtil;
import com.example.wxpay.module.util.WxMD5Util;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class WXserviceImpl implements WXservice {
private static final Logger logger = LoggerFactory.getLogger("MainLogger");
public static final String SPBILL_CREATE_IP = "你的伺服器ip地址";
public static final String NOTIFY_URL = "http://你的域名/v1/weixin/notify.json";
public static final String TRADE_TYPE_APP = "APP";
/**
* 呼叫官方SDK 獲取預支付訂單等引數
* @param attach 額外引數
* @param total_fee 總價
* @return
* @throws Exception
*/
@Override
public Map<String, String> dounifiedOrder(String attach, String total_fee) throws Exception {
WxMD5Util md5Util = new WxMD5Util();
Map<String, String> returnMap = new HashMap<>();
WXConfigUtil config = new WXConfigUtil();
WXPay wxpay = new WXPay(config);
Map<String, String> data = new HashMap<>();
//生成商戶訂單號,不可重複
String out_trade_no = "wxpay" + System.currentTimeMillis();
data.put("appid", config.getAppID());
data.put("mch_id", config.getMchID());
data.put("nonce_str", WXPayUtil.generateNonceStr());
String body = "訂單支付";
data.put("body", body);
data.put("out_trade_no", out_trade_no);
data.put("total_fee", total_fee);
//自己的伺服器IP地址
data.put("spbill_create_ip", SPBILL_CREATE_IP);
//非同步通知地址(請注意必須是外網)
data.put("notify_url", NOTIFY_URL);
//交易型別
data.put("trade_type", TRADE_TYPE_APP);
//附加資料,在查詢API和支付通知中原樣返回,該欄位主要用於商戶攜帶訂單的自定義資料
data.put("attach", attach);
String sign1 = md5Util.getSign(data);
data.put("sign", sign1);
try {
//使用官方API請求預付訂單
Map<String, String> response = wxpay.unifiedOrder(data);
System.out.println(response);
String returnCode = response.get("return_code"); //獲取返回碼
//若返回碼為SUCCESS,則會返回一個result_code,再對該result_code進行判斷
if (returnCode.equals("SUCCESS")) {//主要返回以下5個引數
String resultCode = response.get("result_code");
returnMap.put("appid", response.get("appid"));
returnMap.put("mch_id", response.get("mch_id"));
returnMap.put("nonce_str", response.get("nonce_str"));
returnMap.put("sign", response.get("sign"));
if ("SUCCESS".equals(resultCode)) {//resultCode 為SUCCESS,才會返回prepay_id和trade_type
//獲取預支付交易回話標誌
returnMap.put("trade_type", response.get("trade_type"));
returnMap.put("prepay_id", response.get("prepay_id"));
return returnMap;
} else {
//此時返回沒有預付訂單的資料
return returnMap;
}
} else {
return returnMap;
}
} catch (Exception e) {
System.out.println(e);
//系統等其他錯誤的時候
}
return returnMap;
}
/**
*
* @param notifyData 非同步通知後的XML資料
* @return
*/
@Override
public String payBack(String notifyData) {
WXConfigUtil config = null;
try {
config = new WXConfigUtil();
} catch (Exception e) {
e.printStackTrace();
}
WXPay wxpay = new WXPay(config);
String xmlBack = "";
Map<String, String> notifyMap = null;
try {
notifyMap = WXPayUtil.xmlToMap(notifyData); // 呼叫官方SDK轉換成map型別資料
if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {//驗證簽名是否有效,有效則進一步處理
String return_code = notifyMap.get("return_code");//狀態
String out_trade_no = notifyMap.get("out_trade_no");//商戶訂單號
if (return_code.equals("SUCCESS")) {
if (out_trade_no != null) {
// 注意特殊情況:訂單已經退款,但收到了支付結果成功的通知,不應把商戶的訂單狀態從退款改成支付成功
// 注意特殊情況:微信服務端同樣的通知可能會多次傳送給商戶系統,所以資料持久化之前需要檢查是否已經處理過了,處理了直接返回成功標誌
//業務資料持久化
System.err.println("支付成功");
logger.info("微信手機支付回撥成功訂單號:{}", out_trade_no);
xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
logger.info("微信手機支付回撥失敗訂單號:{}", out_trade_no);
xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[報文為空]]></return_msg>" + "</xml> ";
}
}
return xmlBack;
} else {
// 簽名錯誤,如果資料裡沒有sign欄位,也認為是簽名錯誤
//失敗的資料要不要儲存?
logger.error("手機支付回撥通知簽名錯誤");
xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[報文為空]]></return_msg>" + "</xml> ";
return xmlBack;
}
} catch (Exception e) {
logger.error("手機支付回撥通知失敗", e);
xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[報文為空]]></return_msg>" + "</xml> ";
}
return xmlBack;
}
}
5.MD5加密
import com.github.wxpay.sdk.WXPayConstants;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
public class WxMD5Util {
public String getSign(Map<String, String> data) throws Exception {
WXConfigUtil config = new WXConfigUtil();
Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if (data.get(k).trim().length() > 0) // 引數值為空,則不參與簽名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
sb.append("key=").append(config.getKey());
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] array = new byte[0];
try {
array = md.digest(sb.toString().getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
StringBuilder sb2 = new StringBuilder();
for (byte item : array) {
sb2.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb2.toString().toUpperCase();
}
}
後期我會把查詢訂單等功能也加上。
四、 安卓端
Android Studio環境下:
在build.gradle檔案中,新增如下依賴即可:
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
}
或
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
}
(其中,前者包含統計功能)
4.在AndroidManifest.xml 清單配置檔案中新增必要的許可權
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
5.在調起支付之前一定記得要註冊微信,否則無法調起支付。註冊微信有幾種方式,其中一種如下:IWXAPI wxapi = WXAPIFactory.createWXAPI(this, APP_ID,false);
6.注意回撥的類的位置和類名有嚴格規定,不能更改。微信支付回撥的類類名必須是WXPayEntryActivity,類的路徑必須是:應用包名+wxipa,否則微信將無法回撥。如下圖:
7. 在AndroidManifest.xml宣告回撥類的時候務必加上android:exported=”true”,否則調不起支付介面。
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop" />
8.如果程式碼要混淆,加上以下程式碼以避免相關類被混淆
-keep class com.tencent.mm.opensdk.** {
*;
}
-keep class com.tencent.wxop.** {
*;
}
-keep class com.tencent.mm.sdk.** {
*;
}
9.執行APP的時候,需要正式打包後的APP,或者在配置檔案中指定相應的簽名檔案,否則支付返回都是-1。
10.應該避免使用者快速點選支付按鈕。
11.貼上Android端主要程式碼:
調起支付程式碼
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.example.R;
import com.tencent.mm.opensdk.modelpay.PayReq;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
//AppId
import static com.example.wxapi.util.WeiXinConstants.APP_ID;
public class WXPayActivity extends AppCompatActivity {
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
private static final String TAG = "PayActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wxpay);
final IWXAPI wxapi = WXAPIFactory.createWXAPI(this, APP_ID,false);
final Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
button.setEnabled(false);
String url = "商戶服務端介面";
Request request = new Request.Builder().url(url).build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
button.setEnabled(true);
Toast.makeText(WXPayActivity.this, "請求失敗", Toast.LENGTH_LONG).show();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try {
JSONObject jsonObject = new JSONObject(response.body().string());
Log.i(TAG,jsonObject.toString());
int code = jsonObject.getInt("code");
if (code == 0) {
JSONObject data = jsonObject.getJSONObject("data");
String appId = data.getString("appid");
String partnerId = data.getString("partnerid");
String prepayId = data.getString("prepayid");
String packageValue = data.getString("package");
String nonceStr = data.getString("noncestr");
String timeStamp = data.getString("timestamp");
String extData = data.getString("extdata");
String sign = data.getString("sign");
PayReq req = new PayReq();
req.appId = appId;
req.partnerId = partnerId;
req.prepayId = prepayId;
req.packageValue = packageValue;
req.nonceStr = nonceStr;
req.timeStamp = timeStamp;
req.extData = extData;
req.sign = sign;
boolean result = wxapi.sendReq(req);
Toast.makeText(WXPayActivity.this, "調起支付結果:" +result, Toast.LENGTH_LONG).show();
//
} else {
Toast.makeText(WXPayActivity.this, "資料出錯", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
button.setEnabled(true);
}
});
}
});
}
}
回撥程式碼
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.example.R;
import com.tencent.mm.opensdk.constants.ConstantsAPI;
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import static com.example.wxapi.util.WeiXinConstants.APP_ID;
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
private final String TAG = "WXPayEntryActivity";
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pay_result);
api = WXAPIFactory.createWXAPI(this, APP_ID);
api.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
api.handleIntent(intent, this);
}
@Override
public void onReq(BaseReq req) {
}
@Override
public void onResp(BaseResp resp) {
Log.i(TAG,"errCode = " + resp.errCode);
//最好依賴於商戶後臺的查詢結果
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
//如果返回-1,很大可能是因為應用簽名的問題。用官方的工具生成
//簽名工具下載:https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
builder.setMessage(getString(R.string.pay_result_callback_msg, String.valueOf(resp.errCode)));
builder.show();
}
}
}
五、 總結
凡事經歷過了,覺得也就那麼回事,但是第一次經歷的時候,往往會覺得無厘頭,特別是開發過程中出現問題的時候,有時還不好排查。有幾個地方特別需要注意的雖然在程式碼中有註釋了,但是還是想統一記錄下。
服務端:
1. 如果開發哪功能出問題了,別急,先把該功能的相關文件詳細過一遍,甚至多遍,這很重要,這能讓你解決大部分問題了。錯誤的方式是,先去百度或者谷歌相關問題,因為這往往得不到你想要的答案,雖然官方文件有點坑,但是熟悉了之後就得還好吧。往往官方文件能給出最直接最準確的答案。
2. 檢查申請的幾個引數是有出入,特別是祕鑰和應用簽名。
3. 生成預支付訂單後返回給移動端用的sign 引數一定不要用統一下單返回的sign,需要重新簽名,而且簽名的欄位有且只有6個,而且都是小寫,我就是在坑裡滾了很久,我的key有大寫的字母。
4. 兩個單位值得注意下,涉及到時間戳的時候注意要用秒級(10位數),如果是毫秒級的,轉換成秒級的;涉及到錢的要用分為單位,不能有小數點.
5. 訂單號務必確保唯一,否則prepay_id 返回null.
Android 端:
1. 在微信開放平臺生成的應用簽名不要搞錯,最好用官方給的工具生成。
2. 在APP端調起支付的時候,需要正式打包的apk才能調起。或者在APP的build.grade檔案中配置線上調式打包的簽名和正式的一樣,預設情況下線上打包用的是系統預設生成的簽名,正式打包通常由開發者生成的新的簽名。
3. 微信支付回撥的類類名必須是WXPayEntryActivity,類的路徑務必是:應用包名+wxipa,否則微信將無法回撥(我記得以前開發微信登入分享等也有類似強制要求,這裡我就不去驗證了)。也就是說開發微信的相關功能的某些類必須在wxapi下,而且wxapi這個包必須在應用包下。我知道有點繞,檢視上文的截圖說明吧。這個只能說廠大了他們說了算吧
4. 配置檔案中回撥的activity 的exported 的屬性必須為true —android:exported=”true”,name屬性為exported不要改。
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop" />
歡迎關注我的公眾號,不定時推送一些使用的技術文章:kk魯
或者我個人微信,開發過程遇到問題可以問我,我會試著儘量幫忙。