场景:个人的外包项目,后台说app端自己去微信那边下单自己签名完成支付;
一脸蒙蔽啊,还有这样的操作?;默默的打开微信开发文档,跟着文档一步一步集成 微信支付开发者平台
主要难点在调用微信的统一下单接口,配置与签名问题
// 使用该map可以自动按key排序
SortedMap<String, String> parameterMap = new TreeMap<>();
parameterMap.put("appid", weixinPay.getApp_id()); // APPID
parameterMap.put("mch_id", weixinPay.getPartner()); // 商户id
parameterMap.put("nonce_str", nonce_str); // 随机字符串
parameterMap.put("body", orderNo); // 在支付时显示的信息
parameterMap.put("out_trade_no", orderNo); // 订单号,注意唯一,且一个订单号只能有一个价格,不能改价格不改订单号;已踩过的坑 :(
int price = (int) (Double.valueOf(receivable)*100);
parameterMap.put("total_fee", String.valueOf(price)); // 支付的钱 单位是分
parameterMap.put("spbill_create_ip", IpGetUtil.getIPAddress(PayActivity.this)); // 自己的IP地址
parameterMap.put("notify_url", weixinPay.getNotify_url()); // 支付回调url
parameterMap.put("trade_type", "APP"); // 支付方式
// 获取签名 该签名是通过前面的参数来得到的签名
String sign = PayCommonUtil.createSign("UTF-8", parameterMap,weixinPay.getPartner_key());
parameterMap.put("sign", sign);
微信使用的是xml格式,所以我们还要将map数据转换为xml格式,将map转换为xml字符串
/**
* 将Map转换为XML格式的字符串
*
* @param data Map类型数据
* @return XML格式的字符串
*/
public static String mapToXml(Map<String, String> data) throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
org.w3c.dom.Document document = documentBuilder.newDocument();
org.w3c.dom.Element root = document.createElement("xml");
document.appendChild(root);
for (String key: data.keySet()) {
String value = data.get(key);
if (value == null) {
value = "";
}
value = value.trim();
org.w3c.dom.Element filed = document.createElement(key);
filed.appendChild(document.createTextNode(value));
root.appendChild(filed);
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
try {
writer.close();
}
catch (Exception ex) {
}
return output;
}
然后就可以通过调用微信的下单接口去下单了
/**
* 微信下单调用
* @param requestUrl 微信下单url
* @param requestMethod 请求方法
* @param outputStr 参数
* @return 返回结果,xml格式
*/
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
try {
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
return buffer.toString();
} catch (ConnectException ce) {
System.out.println("连接超时:{}" + ce);
} catch (Exception e) {
System.out.println("https请求异常:{}" + e);
}
return null;
}
得到返回的结果后为了方便处理,将xml转换为map
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
*/
public static Map<String, String> xmlToMap(String strXML) throws Exception {
try {
Map<String, String> data = new HashMap<>();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
// do nothing
}
return data;
} catch (Exception ex) {
Log.e("WXPayUtil", "xmlToMap: ",ex );
throw ex;
}
}
成功失败就看返回的结果了,如果返回成功继续,如果失败了就看下是签名的问题还是配置key的问题,微信提供了一个验证签名的工具,可以对比与自己的签名是否相同验证签名
先别激动,要再次签名
封装参数
// 将微信返回的xml数据再次封装到一个map中
SortedMap<String, String> finalParams = new TreeMap<>();
finalParams.put("appid", weixinPay.getApp_id()); // APPID
finalParams.put("partnerid", weixinPay.getPartner()); // 商户id
finalParams.put("prepayid", map.get("prepay_id")); // 预支付id
finalParams.put("package", "Sign=WXPay"); // 签名方式
finalParams.put("noncestr", map.get("nonce_str")); // 随机字符传
finalParams.put("timestamp", timeStamp); // 时间戳 String.valueOf(System.currentTimeMillis() / 1000)
// 再次签名
String finalSign = PayCommonUtil.createSign("UTF-8", finalParams,weixinPay.getPartner_key());
finalParams.put("paySign", finalSign);
发起支付
IWXAPI mIwxapi = WXAPIFactory.createWXAPI(PayActivity.this.getApplicationContext(), weixinPay.getApp_id());
mIwxapi.registerApp(weixinPay.getApp_id());
PayReq req = new PayReq();
req.appId = weixinPay.getApp_id();
req.partnerId = weixinPay.getPartner();
req.prepayId = map.get("prepay_id");
req.packageValue = "Sign=WXPay";
req.nonceStr = finalParams.get("noncestr");
req.timeStamp = timeStamp;
req.sign = finalSign;
req.extData = "PayActivity"; // 额外参数,可以在回调那得到该数据,可用于区分回调
if (req.checkArgs()) {
mIwxapi.sendReq(req);
} else {
mHandler.sendEmptyMessage(WX_PAY_EROR);
}
什么?没有回调?一闪就什么都没了?
坑啊坑
回调的activity配置要设置android:exported="true"
<activity android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop">
</activity>
当然还有回调处理
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PayConfigBean o = Hawk.get(Define.SP_NAME_PAYCONFIG);
if (o!=null && o.getWeixin_pay()!=null) {
api = WXAPIFactory.createWXAPI(this, o.getWeixin_pay().getApp_id());
api.handleIntent(getIntent(), this);
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
if (api!=null) {
api.handleIntent(intent, this);
}
}
@Override
public void onReq(BaseReq req) {
}
@Override
public void onResp(final BaseResp resp) {
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
if (resp.errCode == 0) {
sendBroadcast(new Intent(Define.sendBroadcast_pay_success));
} else {
String errStr = resp.errStr;
if (errStr == null) {
if (resp.errCode == -2) {
errStr = "用户取消";
} else {
errStr = "支付失败:" + resp.errCode;
}
Toast.makeText(WXPayEntryActivity.this,errStr,Toast.LENGTH_SHORT).show();
}
}
}
finish();
}
}
到此一下午就这样在微信支付的坑中度过了,记载一下!!! 整体代码有空再贴吧,9:30啦,下班明天早上可以10点上班ok