2018年4月5日補充
注意:
1.Android Studio 3.0
2.gradle 3.0
3.Android 8.0
最近公司弄Ionic框架,項目中需要微信支付,無奈,把我調(diào)過去弄,期間也是幾近崩潰,好在皇天不負有心人揣苏,在看別人的文檔,終于是在項目中集成了微信支付件舵,下面作為一個小白的我卸察,想要把我的經(jīng)驗分享給大家,希望對大家有所幫助铅祸。
先給一個可用的demo吧(運行前先看txt文件)
https://download.csdn.net/download/qq_35229022/10356669
這個demo是基于eclipse開發(fā)的坑质,博主也在Android Studio開發(fā)過微信支付合武,原理都是一樣的,大家把這個demo弄懂了涡扼,在AS上面也是一樣的稼跳。
(溫馨提示:大家下載下來可能會出錯,也有可能不會吃沪。下面給出出錯的解決方法:1.進入項目中的WeIXinPay->Build Path->configure build path汤善,移除那個報錯的jar包。 2.會出現(xiàn)資源找不到的情況票彪,這是因為你沒有v7包萎津,下載一個v7包,或者把出錯的地方都刪除抹镊,只是一個主題,刪除了看起來不好看而已荤傲,當然垮耳,你也可以用你有的主題。 還有一個問題需要提出來遂黍,就是你可能按照里面的text操作的仍然調(diào)不起客戶端终佛,有可能是你沒有安裝微信客戶端,因為我沒有做判斷雾家。這個demo不會出現(xiàn)只能成功支付一次的情況铃彰,博主親測有效。出現(xiàn)只能支付一次只能說明你的簽名沒有對應(yīng))
1.去微信開放平臺申請微信支付服務(wù)芯咧,綁定自己的應(yīng)用這里具體不多講牙捉,但是一定要申請完成,將會得到是三個參數(shù)
//appid 微信分配的公眾賬號ID
public static final String APP_ID = "";
//商戶號 微信分配的公眾賬號ID
public static final String MCH_ID = "";
// API密鑰敬飒,在商戶平臺設(shè)置
public static final String API_KEY= "";
坑點提示:在微信開發(fā)平臺設(shè)置包名和簽名邪铲。這里的包名一定要和你自己的包名一樣,就是manifest中的package,簽名一定要和你用官方app生成的一樣(https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk)无拗。
微信會根據(jù)你的填寫的包名带到,然后對你的keystore進行一種算法,生成你的簽名英染。包名和簽名一定要和微信開放平臺的相同揽惹。不過這里需要注意的是,如果你發(fā)布的正式版本四康,需要用官方app重新生成簽名搪搏,然后在開放平臺重新設(shè)置sign,因為測試版本的keystore與正式版的keystore不一樣闪金∧饺拢總之,就是你用的keystore生成的sign要和微信開放平臺的時刻保持一致。
2.準備工作做好了喝检,接下來就是開發(fā)了嗅辣,先下載微信的jar包,導入挠说。
微信支付分為三個步驟
1.生成prepayId
@Override
protected Map<String, String> doInBackground(String... params) {
// TODO Auto-generated method stub
String url=String.format(params[0]);
String entity=getProductArgs();
Log.e("Simon",">>>>"+entity);
byte[] buf=Util.httpPost(url, entity);
String content = new String(buf);
Log.e("orion", "----"+content);
Map<String,String> xml=decodeXml(content);
return xml;
}
2.生成簽名參數(shù)
private void genPayReq() {
req.appId = Constants.APP_ID;
req.partnerId = Constants.MCH_ID;
if (resultunifiedorder!=null) {
req.prepayId = resultunifiedorder.get("prepay_id");
req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id");
}
else {
Toast.makeText(MainActivity.this, "prepayid為空", Toast.LENGTH_SHORT).show();
}
req.nonceStr = getNonceStr();
req.timeStamp = String.valueOf(genTimeStamp());
List<NameValuePair> signParams = new LinkedList<NameValuePair>();
signParams.add(new BasicNameValuePair("appid", req.appId));
signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
signParams.add(new BasicNameValuePair("package", req.packageValue));
signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
req.sign = genAppSign(signParams);
sb.append("sign\n"+req.sign+"\n\n");
textView.setText(sb.toString());
Log.e("Simon", "----"+signParams.toString());
}
3.調(diào)起支付澡谭。
/*
* 調(diào)起微信支付
*/
private void sendPayReq() {
msgApi.registerApp(Constants.APP_ID);
msgApi.sendReq(req);
Log.i(">>>>>", req.partnerId);
}
下面給出完整代碼 :
package com.alpha.live;
import java.io.StringReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.xmlpull.v1.XmlPullParser;
import com.tencent.mm.sdk.modelpay.PayReq;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.WXAPIFactory;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.util.Xml;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
/**
* Created by Simon on 2016/12/2.
*/
public class MainActivity extends Activity implements OnClickListener {
private Button submitButton;
private Button confirmButton;
private TextView textView;
private StringBuffer sb;
private Map<String,String> resultunifiedorder;
private PayReq req;
private final IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
submitButton=(Button) findViewById(R.id.bt_submit_order);
confirmButton=(Button) findViewById(R.id.bt_corfirm);
textView=(TextView) findViewById(R.id.tv_prepay_id);
submitButton.setOnClickListener(this);
confirmButton.setOnClickListener(this);
sb=new StringBuffer();
req=new PayReq();
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.bt_submit_order:
String urlString="https://api.mch.weixin.qq.com/pay/unifiedorder";
PrePayIdAsyncTask prePayIdAsyncTask=new PrePayIdAsyncTask();
prePayIdAsyncTask.execute(urlString); //生成prepayId
break;
case R.id.bt_corfirm:
genPayReq();//生成簽名參數(shù)
sendPayReq();//調(diào)起支付
break;
default:
break;
}
}
/*
* 調(diào)起微信支付
*/
private void sendPayReq() {
msgApi.registerApp(Constants.APP_ID);
msgApi.sendReq(req);
Log.i(">>>>>", req.partnerId);
}
private long genTimeStamp() {
return System.currentTimeMillis() / 1000;
}
private void genPayReq() {
req.appId = Constants.APP_ID;
req.partnerId = Constants.MCH_ID;
if (resultunifiedorder!=null) {
req.prepayId = resultunifiedorder.get("prepay_id");
req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id");
}
else {
Toast.makeText(MainActivity.this, "prepayid為空", Toast.LENGTH_SHORT).show();
}
req.nonceStr = getNonceStr();
req.timeStamp = String.valueOf(genTimeStamp());
List<NameValuePair> signParams = new LinkedList<NameValuePair>();
signParams.add(new BasicNameValuePair("appid", req.appId));
signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
signParams.add(new BasicNameValuePair("package", req.packageValue));
signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
req.sign = genAppSign(signParams);
sb.append("sign\n"+req.sign+"\n\n");
textView.setText(sb.toString());
Log.e("Simon", "----"+signParams.toString());
}
private String genAppSign(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.size(); i++) {
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
}
sb.append("key=");
sb.append(Constants.API_KEY);
this.sb.append("sign str\n"+sb.toString()+"\n\n");
String appSign = MD5.getMessageDigest(sb.toString().getBytes());
Log.e("Simon","----"+appSign);
return appSign;
}
private class PrePayIdAsyncTask extends AsyncTask<String,Void, Map<String, String>>
{
private ProgressDialog dialog;
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
dialog = ProgressDialog.show(MainActivity.this, "提示", "正在提交訂單");
}
@Override
protected Map<String, String> doInBackground(String... params) {
// TODO Auto-generated method stub
String url=String.format(params[0]);
String entity=getProductArgs();
Log.e("Simon",">>>>"+entity);
byte[] buf=Util.httpPost(url, entity);
String content = new String(buf);
Log.e("orion", "----"+content);
Map<String,String> xml=decodeXml(content);
return xml;
}
@Override
protected void onPostExecute(Map<String, String> result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if (dialog != null) {
dialog.dismiss();
}
sb.append("prepay_id\n"+result.get("prepay_id")+"\n\n");
textView.setText(sb.toString());
resultunifiedorder=result;
}
}
public Map<String,String> decodeXml(String content) {
try {
Map<String, String> xml = new HashMap<String, String>();
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)==false){
//實例化student對象
xml.put(nodeName,parser.nextText());
}
break;
case XmlPullParser.END_TAG:
break;
}
event = parser.next();
}
return xml;
} catch (Exception e) {
Log.e("Simon","----"+e.toString());
}
return null;
}
private String getProductArgs() {
// TODO Auto-generated method stub
StringBuffer xml=new StringBuffer();
try {
String nonceStr=getNonceStr();
xml.append("<xml>");
List<NameValuePair> packageParams=new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("appid",Constants.APP_ID));
packageParams.add(new BasicNameValuePair("body", "APP pay test"));
packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
packageParams.add(new BasicNameValuePair("notify_url", "https://www.baidu.com"));//寫你們的回調(diào)地址
packageParams.add(new BasicNameValuePair("out_trade_no",genOutTradNo()));
packageParams.add(new BasicNameValuePair("total_fee", "1"));
packageParams.add(new BasicNameValuePair("trade_type", "APP"));
String sign=getPackageSign(packageParams);
packageParams.add(new BasicNameValuePair("sign", sign));
String xmlString=toXml(packageParams);
return xmlString;
} catch (Exception e) {
// TODO: handle exception
return null;
}
}
//生成訂單號,測試用,在客戶端生成
private String genOutTradNo() {
Random random = new Random();
// return "dasgfsdg1234"; //訂單號寫死的話只能支付一次损俭,第二次不能生成訂單
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
//生成隨機號蛙奖,防重發(fā)
private String getNonceStr() {
// TODO Auto-generated method stub
Random random=new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
/**
生成簽名
*/
private String getPackageSign(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.size(); i++) {
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
}
sb.append("key=");
sb.append(Constants.API_KEY);
String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
Log.e("Simon",">>>>"+packageSign);
return packageSign;
}
/*
* 轉(zhuǎn)換成xml
*/
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>");
Log.e("Simon",">>>>"+sb.toString());
return sb.toString();
}
}
接下來就是有個支付結(jié)果的頁面代碼。是微信官方提供的一個類杆兵。你要在manifest注冊這個類雁仲。這里需要注意的是,這個類必須放在wxapi包下琐脏,你自己新建一個包即可攒砖。
為了大家可以直接運行這個demo,我的微信加簽都是在本地執(zhí)行的日裙,獲取prepayid和加簽都應(yīng)該在服務(wù)端完成吹艇,還有最終的支付返回結(jié)果也是以服務(wù)端的為準。
下面給出運行結(jié)果圖
大家下載demo然后把參數(shù)換了昂拂,弄下keystore受神,包名,簽名格侯。應(yīng)該就可以用了鼻听。