直接进入正题,在做微信支付时候,如果写后台的人比较懒,各种参数要Android端自己生成怎么办?其实也是有办法的,就是比较麻烦,而且会有点问题(这是小概率事件了)
微信支付的官方文档说的很清楚了,这一步的参数是要后台生成的。现在我们在Android端生成。直接上代码
微信支付的文档链接:戳这里
/**
*
* @Title: getOrderHttp
* @Description: TODO(拿到订单ID)
* @param 参数 @param money
* @param 参数 @param uid
* @return 返回类型 void
* @throws
*/
private void getOrderHttp(String money,String uid){
String url="http://webui.430.com.cn:81/AppPay/PayWeixin.aspx";
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("uid", uid));
parameters.add(new BasicNameValuePair("money", money));
JSONObject json = HttpUtils.getHttp(url, parameters);
if(null != json){
String orderID = json.optString("orderID");
getWXHttp(orderID,money);
}else {
Log.e("PAY_GET","处理结果异常");
}
}
这里先从后台服务器拿到订单号和金额。然后调用getWXHttp();这个方法。
/**
*
* @Title: getWXHttp
* @Description: TODO(得到微信支付预处理的一些参数并跳转到微信支付)
* @param 参数 @param orderID
* @param 参数 @param money
* @return 返回类型 void
* @throws
*/
private void getWXHttp(String orderID,String money){
Map<String,String> xml=new HashMap<String,String>();
String url="https://api.mch.weixin.qq.com/pay/unifiedorder"; //这个地址就是微信支付文档中请求的地址
String entity = genProductArgs(orderID,money);
byte[] buf = HttpUtils.httpPost(url, entity);
if(buf != null){
String content = new String(buf);
try {
Document doc = (Document)DocumentHelper.parseText(content);
Element root = doc.getRootElement();
List<Element> list = root.elements();
for (Element e : list) {
xml.put(e.getName(), e.getText());
}
} catch (DocumentException e) {
e.printStackTrace();
}
if(xml != null){
PayReq req = new PayReq();
req.appId = xml.get("appid");
req.partnerId = xml.get("mch_id");
req.prepayId = xml.get("prepay_id");
req.packageValue = "Sign=WXPay";
req.nonceStr = xml.get("nonce_str");
req.timeStamp = String.valueOf(StringUtils.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 =StringUtils.genAppSign(signParams);
m_IWxAPI.sendReq(req);
}
}
}
/**
*
* @Title: genProductArgs
* @Description: TODO(拼接参数)
* @param 参数 @param orderID
* @param 参数 @param money
* @param 参数 @return
* @return 返回类型 String
* @throws
*/
private static String genProductArgs(String orderID,String money) {
StringBuffer xml = new StringBuffer();
try {
xml.append("</xml>");
List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("appid", ""));
packageParams.add(new BasicNameValuePair("body", ""));//商品描述,商品或支付单简要描述,必填
packageParams.add(new BasicNameValuePair("mch_id", "")); //商户ID
packageParams.add(new BasicNameValuePair("nonce_str", StringUtils.genNonceStr()));//随机字符串,不长于32位。必填
packageParams.add(new BasicNameValuePair("notify_url", ""));//接收微信支付异步通知回调地址.必填
packageParams.add(new BasicNameValuePair("out_trade_no",));//商户系统内部的订单号,32个字符内、可包含字母,必填
packageParams.add(new BasicNameValuePair("spbill_create_ip",StringUtils.getLocalIpAddress(AppActivity.getContext())));//APP和网页支付提交用户端ip.必填
packageParams.add(new BasicNameValuePair("total_fee", (Integer.parseInt(money)*100)+""));//订单总金额,只能为整数.必填
packageParams.add(new BasicNameValuePair("trade_type", "APP"));//取值如下:JSAPI,NATIVE,APP,WAP,必填
String sign = StringUtils.genPackageSign(packageParams);
packageParams.add(new BasicNameValuePair("sign",sign)); //签名
String xmlstring =toXml(packageParams);
xmlstring = new String(xmlstring.getBytes("UTF-8"), "ISO-8859-1");
return xmlstring;
} catch (Exception e) {
Log.e("e", "genProductArgs fail, 异常: " + e.getMessage());
return null;
}
}
/**
*
* @Title: toXml
* @Description: TODO(转换成String格式的xml)
* @param 参数 @param params
* @param 参数 @return
* @return 返回类型 String
* @throws
*/
private static 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();
}
上面需要转成xml格式的参数,这是微信文档规定的,大家可以去看看。主要步骤就是上面的代码了。
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() != 200) {
//Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());
// return null;
return EntityUtils.toByteArray(resp.getEntity());
}
return EntityUtils.toByteArray(resp.getEntity());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}
private static class SSLSocketFactoryEx extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
public class StringUtils {
/**
*
* @Title: int2ip
* @Description: TODO(将ip的整数形式转换成ip形式 )
* @param 参数 @param ipInt
* @param 参数 @return
* @return 返回类型 String
* @throws
*/
public static String int2ip(int ipInt) {
StringBuilder sb = new StringBuilder();
sb.append(ipInt & 0xFF).append(".");
sb.append((ipInt >> 8) & 0xFF).append(".");
sb.append((ipInt >> 16) & 0xFF).append(".");
sb.append((ipInt >> 24) & 0xFF);
return sb.toString();
}
/**
*
* @Title: getLocalIpAddress
* @Description: TODO(获取当前ip地址 )
* @param 参数 @param context
* @param 参数 @return
* @return 返回类型 String
* @throws
*/
public static String getLocalIpAddress(Context context) {
try {
WifiManager wifiManager = (WifiManager) context
.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int i = wifiInfo.getIpAddress();
return int2ip(i);
} catch (Exception ex) {
return " 获取IP出错鸟!!!!请保证是WIFI,或者请重新打开网络!\n" + ex.getMessage();
}
// return null;
}
/**
*
* @Title: genTimeStamp
* @Description: TODO(生成时间戳)
* @param 参数 @return
* @return 返回类型 long
* @throws
*/
public static long genTimeStamp() {
return System.currentTimeMillis() / 1000;
}
/**
*
* @Title: genAppSign
* @Description: TODO(生成签名)
* @param 参数 @param params
* @param 参数 @return
* @return 返回类型 String
* @throws
*/
public static 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("换成自己的");
String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
return appSign;
}
/**
*
* @Title: genPackageSign
* @Description: TODO(生成签名)
* @param 参数 @param params
* @param 参数 @return
* @return 返回类型 String
* @throws
*/
public static 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("换成自己的");
String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
return packageSign;
}
/**
*
* @Title: genNonceStr
* @Description: TODO(随机字符串)
* @param 参数 @return
* @return 返回类型 String
* @throws
*/
public static String genNonceStr() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
}
public class MD5 {
private MD5() {}
public final static String getMessageDigest(byte[] buffer) {
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(buffer);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
}
上面就是一些用到的帮助类。里面请求方式可以根据自己的网络请求去改写。
最后吐槽一句:该让后台做的事不要拿在Android端来做。