微信支付集成

微信支付

1:去微信開放平臺註冊應用
https://open.weixin.qq.com/cgi-bin/index?t=home/index&lang=zh_CN&token=2c0fee9c43e1eb8f9febcc7cb73abf598e2d4011

這裏需要注意的是:

包名正確(重要)
簽名正確(重要)
溫馨提示:如果你發佈的正式版本,需要用官方app重新生成簽名,然後在開放平臺重新設置sign,因爲測試版本的keystore與正式版的keystore不一樣。總之,就是你用的keystore生成的sign要和微信開放平臺的時刻保持一致。

微信提供的簽名生成工具
把包名添加上去就可以獲取簽名
注意:把要獲取簽名的應用安裝在手機上
https://res.wx.qq.com/open/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android2.apk

創建移動應用併成功之後會收到騰訊發來的郵件:


Paste_Image.png

通過郵件你能獲得重要的參數:
(1):AppID
(2):微信支付商戶號
(4):前往商戶平臺完成入駐
(4):API祕鑰(自己設置即可,注意一定要32位字母加數字的組合)記得保存好祕鑰,以後要使用

開發前的準備

先了解下交互時序圖,統一下單API、支付結果通知API和查詢訂單API等都涉及簽名過程,調用都必須在商戶服務器端完成。如圖8.6所示。

APP支付時序圖

圖8.6 APP支付時序圖

安卓sdk下載
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1
微信開放平臺
https://open.weixin.qq.com/
微信android開發手冊
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317784&token=&lang=zh_CN
微信app開發步驟
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5

下載開發工具包
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&lang=zh_CN


開始接入微信支付

1.在項目中引入微信開發包


引入jar

2.在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"/>

3.在MainActivity中註冊到爲微信

配置debug簽名

創建應用需要填寫應用簽名,配置在debug下直接用的正式的key,這樣就不用每次打包才能調起微信客戶端

signingConfigs {
        debug {
            storeFile file("你的keystore路徑")
            storePassword "xxx"
            keyAlias "xxx"
            keyPassword "xxx"
        }

        release {
            storeFile file("你的keystore路徑")
            storePassword "xxx"
            keyAlias "xxx"
            keyPassword "xxx"
        }
}

3.在MainActivity中註冊到爲微信


註冊微信
api= WXAPIFactory.createWXAPI(this,ConfigUtil.Wechat_Appid,true);
api.registerApp(ConfigUtil.Wechat_Appid);

4.在點擊的時候向微信發送請求


發送請求
case R.id.wechat_pay:
    PayReq request = new PayReq();
    request.appId = ConfigUtil.Wechat_Appid;
    request.partnerId = "1327244301";
    request.prepayId= "wx2016092009564343e737275f0904349502";
    request.packageValue = "Sign=WXPay";
    request.nonceStr= "70vhVHnJj6ph7mf9";
    request.timeStamp= "1474336603";
    request.sign= "815BC8D5508FD90F7A978856B2174E21";
    api.sendReq(request);
    break;

5.配置回調
[1]在微信管理後臺中配置的包名下新建wxapi包
[2]在wxapi包下新建WXPayEntryActivity的類(注意這個類的位置和名稱不能改變)


新建WXPayEntryActivity類

[3]WXPayEntryActivity類實現IWXAPIEventHandler繼承Activity,該佈局文件自己定義即可


WXPayEntryActivity類實現


[4]在AndroidManifest.xml中註冊activity

<activity
    android:name=".wxapi.WXPayEntryActivity"
    android:exported="true"
    android:launchMode="singleTop"/>

[5]在WXPayEntryActivity類中onCreate中註冊微信


註冊微信
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    api = WXAPIFactory.createWXAPI(this, ConfigUtil.Wechat_Appid);
    api.handleIntent(getIntent(), this);
}

 @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        api.handleIntent(intent, this);
    }

[6]實現onResp

public void onResp(BaseResp baseResp) {
    Log.d(TAG, "onPayFinish, errCode = " + baseResp.errCode);

    if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("標題");
        builder.setMessage(String.valueOf(baseResp.errCode));
        builder.show();
    }
}

baseResp.errCode是返回的錯誤碼


錯誤碼

注意:WXPayEntryActivity類必須叫這個名必須在wxapi包下


微信調不起來:
檢查簽名是否正確
包名是否與微信後臺配置的一致
檢查是否添加權限
檢查代碼 是否在初始化時註冊微信 是否正確發送請求
微信支付調用起來沒有回調:
查看包名是否正確
類名是否正確
在AndroidManifest.xml是否註冊activity

解決方法:
實在掉不起來微信(包名正確簽名正確)就重新安裝微信客戶端 和重新安裝 測試項目

預支付訂單和sign最好在服務器中完成,但若是就想在客戶端做怎麼弄呢?爲方便,那麼我這裏就直接給出代碼,可供大家參考:

/**
 *該類用於在客戶端處理吊起微信支付前,生成prepay_id和sign的方式舉例,
 * 但建議在服務器端處理prepay_id和sign
 **/
public class PayActivity extends Activity {
	// appid
	// 請同時修改 androidmanifest.xml裏面,.PayActivity裏的屬性<data
	// android:scheme=""/>爲新設置的appid
	public  static  String APP_ID;

	// 商戶號
	public  static String MCH_ID ;
	// API密鑰,在商戶平臺設置
	public static String API_KEY ;
	private String body;
	private  String total;
	PayReq req;
	final IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null);
	Map<String, String> resultunifiedorder;
	StringBuffer sb;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		 APP_ID= getIntent().getStringExtra("appid");
		 MCH_ID=getIntent().getStringExtra("partnerid");
		 API_KEY=getIntent().getStringExtra("apikey");
		 body=getIntent().getStringExtra("body");

		req = new PayReq();
		sb = new StringBuffer();
		msgApi.registerApp(APP_ID);

		// 生成prepay_id
		GetPrepayIdTask getPrepayId = new GetPrepayIdTask();
		getPrepayId.execute();
	}

	private class GetPrepayIdTask extends AsyncTask<Void, Void, Map<String, String>> {
		private ProgressDialog dialog;
		@Override
		protected void onPreExecute() {
			dialog = ProgressDialog.show(PayActivity.this, getString(R.string.app_tip), getString(R.string.getting_prepayid));
		}

		@Override
		protected Map<String, String> doInBackground(Void... params) {

			String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
			String entity = genProductArgs();

			Log.e("orion", entity);

			byte[] buf = Util.httpPost(url, entity);  //執行與獲取預付款訂單請求,並獲得訂單byte

			String content = new String(buf);
			Log.e("orion", content);
			Map<String, String> map = decodeXml(content);
			return map;
		}

		@Override
		protected void onPostExecute(Map<String, String> result) {
			if (dialog != null) {
				dialog.dismiss();
			}
			sb.append("prepay_id\n" + result.get("prepay_id") + "\n\n");

			resultunifiedorder = result;

			if (result.get("prepay_id") != null) {
				genPayReq();  //吊起支付請求
			} else {
				Toast.makeText(getApplicationContext(), "調用微信支付失敗!", Toast.LENGTH_SHORT).show();
			}
		}
	}

	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("orion", e.toString());
		}
		return null;

	}

	private String genNonceStr() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}

	private long genTimeStamp() {
		return System.currentTimeMillis() / 1000;
	}

	private String genOutTradNo() {
		Random random = new Random();
		String out_trade_no = MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
		return out_trade_no;
	}
	private String genProductArgs() {
		StringBuffer xml = new StringBuffer();

		try {
			String nonceStr = genNonceStr();
			xml.append("</xml>");
			List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
			packageParams.add(new BasicNameValuePair("appid", APP_ID));
			packageParams.add(new BasicNameValuePair("body", body));//物品
			packageParams.add(new BasicNameValuePair("mch_id", MCH_ID));
			packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
			packageParams.add(new BasicNameValuePair("notify_url", "http://baidu.com"));
			packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo()));
			packageParams.add(new BasicNameValuePair("spbill_create_ip", getPhoneIp()));
			packageParams.add(new BasicNameValuePair("total_fee", getIntent().getStringExtra("total_fee")));//金額
			packageParams.add(new BasicNameValuePair("trade_type", "APP"));
			String sign = genPackageSign(packageParams);
			packageParams.add(new BasicNameValuePair("sign", sign));
			String xmlstring = toXml(packageParams);
			return new String(xmlstring.getBytes(), "ISO8859-1");
			// return xmlstring;

		} catch (Exception e) {
		//	Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage());
			return null;
		}

	}
	private void genPayReq() {
		req.appId = APP_ID;
		req.partnerId = MCH_ID;
		req.prepayId = resultunifiedorder.get("prepay_id");
		req.packageValue = "Sign=WXPay";
		req.nonceStr = genNonceStr();
		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");
		sendPayReq();
		Log.e("orion", signParams.toString());

	}

	/**
	 * 獲取預支付訂單時需要生成的PackageSign簽名
	 */

	private String genPackageSign(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(API_KEY);
		String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
		Log.e("orion", packageSign);
		return packageSign;
	}

	//吊起支付時需要生成的AppSign簽名
	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(API_KEY);

		this.sb.append("sign str\n" + sb.toString() + "\n\n");
		String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
		Log.e("orion", appSign);
		return appSign;
	}

	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("orion", sb.toString());
		return sb.toString();
	}

	// 發起微信支付
	private void sendPayReq() {

		msgApi.registerApp(APP_ID);
		msgApi.sendReq(req);
	}

	public static String getPhoneIp() {
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
				NetworkInterface intf = en.nextElement();
				for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
					InetAddress inetAddress = enumIpAddr.nextElement();
					if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
						return inetAddress.getHostAddress().toString();
					}
				}
			}
		} catch (Exception e) {
		}
		return "127.0.0.1";
	}
}

其中Util中涉及的代碼如下:

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;
		}
	}

其他文檔:

微信開發平臺官網:申請流業務流程 訂單簽名算法及驗證

微信支付集成及爬坑:代碼詳談

集成微信登錄 :http://www.jianshu.com/p/d95e4343e231

Android實現點擊支付按鈕,彈起自定義輸入法進行密碼輸入: 點我哦!

微信掃一掃揭祕:  猛戳這裏!

發佈了30 篇原創文章 · 獲贊 15 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章