Android接入微信支付的方法
1、先在微信開放平臺(tái)申請開發(fā)應(yīng)用,微信開放平臺(tái)會(huì)生成APP的唯一標(biāo)識(shí)APPID。由于需要保證支付安全,需要在開放平臺(tái)綁定商戶應(yīng)用包名和應(yīng)用簽名,設(shè)置好后才能正常發(fā)起支付。
2、注冊APPID (這個(gè)可以放在項(xiàng)目的application里)
商戶APP工程中引入微信JAR包,調(diào)用API前,需要先向微信注冊您的APPID,代碼如下:
final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);
// 將該app注冊到微信
msgApi.registerApp("wxd930ea5d5a258f4f");
3、調(diào)用統(tǒng)一下單api生成預(yù)付單,獲取到prepay_id后將參數(shù)再次簽名傳輸給APP發(fā)起支付。
例:
下面代碼中的訂單號(hào)是需要后臺(tái)生成的
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
WXPrePost post = new WXPrePost();
post.appid = "你的appId";
post.mch_id = "你的商戶號(hào)";
post.nonce_str = StringUtils.genNonceStr();//隨機(jī)字符串 **1
post.body = "商品名稱";
post.detail = "商品的描述";
post.out_trade_no = out_trade_no; //商戶訂單號(hào) **2
post.total_fee = "商品價(jià)格";//單位是分
post.spbill_create_ip = getLocalIpAddress();//ip地址 **3
post.notify_url = "";//這里是后臺(tái)接受支付結(jié)果通知的url地址
post.trade_type = "APP";
post.sign = genPackageSign(post);//簽名 **4
List<NameValuePair> firstSignParams = getFirstSignParams(post);
String xml = toXml(firstSignParams);
String entity = null;
try {
entity = new String(xml.getBytes(), "ISO8859-1");
byte[] buf = Util.httpPost(url, entity);
if (buf != null) {
String content = new String(buf);
Map<String, String> map = decodeXml(content);
if (map != null) {
//再次簽名(參與簽名的字段有 :Appid partnerId prepayId nonceStr TimeStamp package)
String appId = "";
String prepayId = "";
String nonceStr = "";
for (Map.Entry<String, String> entry : map.entrySet()) {
if ("appid".equals(entry.getKey())) {
appId = entry.getValue();
} else if ("prepay_id".equals(entry.getKey())) {
prepayId = entry.getValue();
} else if ("nonce_str".equals(entry.getKey())) {
nonceStr = entry.getValue();
}
}
Log.d(TAG, "run: :" + appId + "/" + prepayId + "/" + nonceStr + "/");
String TimeStamp = String.valueOf(genTimeStamp());
//ok 獲取二次簽名
String secondPackageSign = genSecondPackageSign(getSecondSignParams(appId, prepayId, nonceStr, TimeStamp));
PayReq req = new PayReq();
req.appId = appId;
req.partnerId = "商戶號(hào)";
req.prepayId = prepayId;
req.nonceStr = nonceStr;
req.timeStamp = TimeStamp;
req.packageValue = "Sign=WXPay";
req.sign = secondPackageSign;
req.extData = "app data"; // optional
// System.out.println("genPackageSign3:"+post.getSign()+"/"+secondPackageSign);
// 在支付之前,如果應(yīng)用沒有注冊到微信,應(yīng)該先調(diào)用IWXMsg.registerApp將應(yīng)用注冊到微信
mApi.sendReq(req);
Log.d(TAG, "run: " + appId + "/" + prepayId + "/" + nonceStr + "/" + TimeStamp + "/" + secondPackageSign);
}
}
} catch (Exception e) {
}
public static byte[] httpPost(String url, String entity) {
if (url == null || url.length() == 0) {
Log.e(TAG, "httpPost, url is null");
return null;
}
HttpClient httpClient = getNewHttpClient();
HttpPost httpPost = new HttpPost(url);
try {
httpPost.setEntity(new StringEntity(entity));
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
HttpResponse resp = httpClient.execute(httpPost);
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());
return null;
}
return EntityUtils.toByteArray(resp.getEntity());
} catch (Exception e) {
Log.e(TAG, "httpPost exception, e = " + e.getMessage());
e.printStackTrace();
return null;
}
}
//獲取隨機(jī)字符串的方法
public static String genNonceStr() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
private String toXml(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
sb.append("<xml>");
for (int i = 0; i < params.size(); i++) {
sb.append("<" + params.get(i).getName() + ">");
sb.append(params.get(i).getValue());
sb.append("</" + params.get(i).getName() + ">");
}
sb.append("</xml>");
return sb.toString();
}
public Map<String, String> decodeXml(String content) {
try {
Map<String, String> xml = new HashMap<>();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new StringReader(content));
int event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
String nodeName = parser.getName();
switch (event) {
case XmlPullParser.START_DOCUMENT:
break;
case XmlPullParser.START_TAG:
if (!"xml".equals(nodeName)) {
xml.put(nodeName, parser.nextText());
}
break;
case XmlPullParser.END_TAG:
break;
}
event = parser.next();
}
return xml;
} catch (Exception e) {
}
return null;
}
@NonNull
private List<NameValuePair> getFirstSignParams(WXPrePost params) {
List<NameValuePair> packageParams = new LinkedList<>();
packageParams.add(new BasicNameValuePair("appid", "appId"));
packageParams.add(new BasicNameValuePair("body", params.body));
packageParams.add(new BasicNameValuePair("detail", params.detail));
packageParams.add(new BasicNameValuePair("mch_id", "商戶號(hào)"));
packageParams.add(new BasicNameValuePair("nonce_str", params.nonce_str));
packageParams.add(new BasicNameValuePair("notify_url", params.notify_url));
packageParams.add(new BasicNameValuePair("out_trade_no", params.out_trade_no));
packageParams.add(new BasicNameValuePair("spbill_create_ip", params.spbill_create_ip));
packageParams.add(new BasicNameValuePair("total_fee", params.total_fee + ""));
packageParams.add(new BasicNameValuePair("trade_type", params.trade_type));
packageParams.add(new BasicNameValuePair("sign", params.sign));
return packageParams;
}
public class WXPrePost {
//必須帶的參數(shù)
public String appid;
//微信開放平臺(tái)審核通過的應(yīng)用APPID
public String mch_id;
//微信支付分配的商戶號(hào)
public String nonce_str;
//隨機(jī)字符串,不長于32位。推薦隨機(jī)數(shù)生成算法
public String sign;
//簽名,詳見簽名生成算法
public String body;
// 商品描述交易字段格式根據(jù)不同的應(yīng)用場景按照以下格式:APP——需傳入應(yīng)用市場上的APP名字-實(shí)際商品名稱,天天愛消除-游戲充值。
public String out_trade_no;
// 商戶系統(tǒng)內(nèi)部的訂單號(hào),32個(gè)字符內(nèi)、可包含字母, 其他說明見商戶訂單號(hào)
public int total_fee;
// 訂單總金額,單位為分,詳見支付金額
public String spbill_create_ip;
// 用戶端實(shí)際ip
public String notify_url;
// 接收微信支付異步通知回調(diào)地址,通知url必須為直接可訪問的url,不能攜帶參數(shù)。(后臺(tái)提供的)
public String trade_type;
// 支付類型
// 非必須攜帶的參數(shù)
public String device_info;
// 終端設(shè)備號(hào)(門店號(hào)或收銀設(shè)備ID),默認(rèn)請傳"WEB"
public String detail;
// 商品名稱明細(xì)列表
public String attach;
// 附加數(shù)據(jù),在查詢API和支付通知中原樣返回,該字段主要用于商戶攜帶訂單的自定義數(shù)據(jù)
public String fee_type;
// 符合ISO 4217標(biāo)準(zhǔn)的三位字母代碼,默認(rèn)人民幣:CNY,其他值列表詳見貨幣類型
//
public String time_start;
// 訂單生成時(shí)間,格式為yyyyMMddHHmmss,如2009年12月25日9點(diǎn)10分10秒表示為20091225091010。其他詳見時(shí)間規(guī)則
//
public String time_expire;
// 訂單失效時(shí)間,格式為yyyyMMddHHmmss,如2009年12月27日9點(diǎn)10分10秒表示為20091227091010。其他詳見時(shí)間規(guī)則 注意:最短失效時(shí)間間隔必須大于5分鐘
public String goods_tag;
// 商品標(biāo)記,代金券或立減優(yōu)惠功能的參數(shù),說明詳見代金券或立減優(yōu)惠
//
public String limit_pay;
//no_credit--指定不能使用信用卡支付
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public int getTotal_fee() {
return total_fee;
}
public void setTotal_fee(int total_fee) {
this.total_fee = total_fee;
}
public String getSpbill_create_ip() {
return spbill_create_ip;
}
public void setSpbill_create_ip(String spbill_create_ip) {
this.spbill_create_ip = spbill_create_ip;
}
public String getNotify_url() {
return notify_url;
}
public void setNotify_url(String notify_url) {
this.notify_url = notify_url;
}
public String getTrade_type() {
return trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public String getDevice_info() {
return device_info;
}
public void setDevice_info(String device_info) {
this.device_info = device_info;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getAttach() {
return attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getFee_type() {
return fee_type;
}
public void setFee_type(String fee_type) {
this.fee_type = fee_type;
}
public String getTime_start() {
return time_start;
}
public void setTime_start(String time_start) {
this.time_start = time_start;
}
public String getTime_expire() {
return time_expire;
}
public void setTime_expire(String time_expire) {
this.time_expire = time_expire;
}
public String getGoods_tag() {
return goods_tag;
}
public void setGoods_tag(String goods_tag) {
this.goods_tag = goods_tag;
}
public String getLimit_pay() {
return limit_pay;
}
public void setLimit_pay(String limit_pay) {
this.limit_pay = limit_pay;
}
}
這里給出的參數(shù)都是可以移動(dòng)端自己獲取到的,當(dāng)然,最好是后臺(tái)提供給我們,出于安全性考慮
支付完成,微信會(huì)回調(diào)WXPayEntryActivity,這里就不詳細(xì)說了,微信文檔說的很清晰
在WXPayEntryActivity的onResp()里面返回的微信支付的結(jié)果(注:這個(gè)結(jié)果不能作為我們購買商品成功與否的結(jié)果,要以微信回調(diào)給回臺(tái),然后回臺(tái)告訴我們的支付結(jié)果為準(zhǔn))
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
int code = resp.errCode;
switch (code) {
case 0:
Log.d(TAG, "onPayFinish, errCode = " + "支付成功");
//微信支付成功后去調(diào)后臺(tái),以后臺(tái)返回的支付結(jié)果為準(zhǔn)
//這里是微信支付完成后的回調(diào),在這里請求后臺(tái),讓他來告訴我們到底支付成功沒。
break;
case -1:
Toast.makeText(this, "支付失敗1", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onPayFinish, errCode = " + "支付失敗1");
finish();
break;
case -2:
Toast.makeText(this, "支付取消", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onPayFinish, errCode = " + "支付取消");
finish();
break;
default:
// Toast.makeText(this, "支付失敗2", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onPayFinish, errCode = " + "支付失敗2");
setResult(RESULT_OK);
finish();
break;
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
java使用ZipInputStream實(shí)現(xiàn)讀取和寫入zip文件
zip文檔可以以壓縮格式存儲(chǔ)一個(gè)或多個(gè)文件,本文主要為大家詳細(xì)介紹了java如何使用ZipInputStream讀取Zip文檔與寫入,需要的小伙伴可以參考下2023-11-11
Intellij idea遠(yuǎn)程debug連接tomcat實(shí)現(xiàn)單步調(diào)試
這篇文章主要介紹了Intellij idea遠(yuǎn)程debug連接tomcat實(shí)現(xiàn)單步調(diào)試,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05
淺談spring使用策略模式實(shí)現(xiàn)多種場景登錄方式
本文主要介紹了spring使用策略模式實(shí)現(xiàn)多種場景登錄方式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12

