本文讲解使用微信支付接口完成在android开发的原生态app中完成微信支付功能, 文章具体讲解了前端android如何集成微信支付功能以及后台如何组装前端需要支付信息, 话不多话, 具体看文章内容吧
00:00 / 07:03正常
本实例项目运行条件:
开发环境: 【Android Studio】
- 到微信开放平台注册帐号并且创建移动应用
https://open.weixin.qq.com/cgi-bin/frame?t=home/app_tmpl&lang=zh_CN
Column 1 | Column 2 | Column 3 |
---|---|---|
Text | Text | Text |
- 获得移动应用的权限【微信支付】
这个权限要求比较高,需要公司资质 并且 每年需要支付300元 才能开通 (这里不作讲解, 具体到官网上申请)
- 配置应用签名, 这个签名通过 android打包文件jks生成或者keystore生成 【如何生成jks文件】
签名文件生成方法:
3.1 keytool -list -v -keystore jks文件(或者keystore文件)
3.2 获取指纹证书md5值, 将md5中的冒号去掉, 大写换成小写 (详情)
总结: 微信开放平台Android应用签名的本质便是我们签名文件jks(或者keystore)的MD5值
- 配置支付密钥, 【如何配置密钥】 【微信配置密钥官网】
- 应用程序开发完成后,debug模式是无法完成支付的,应用程序必须由相应的jks签名之后生成的apk包安装在手机上才能进行分支付(微信会校验应用签名)
- 支付流程讲解
2.1 android程序启动后如下第一张图, 点击【确认支付】
2.1.1 android端向后台请求获得预支付信息
2.1.2 后台根据微信官网平台上的 配置信息 加上 订单信息 生成预支付信息
2.1.3 android端根据预支付信息 拉起微信支付页面进行支付(见下面第二张图)
- 代码详解(Android端)
3.1 在android studio中引入 微信需要使用的jar包
3.2 在android工程对应的包名下面新建 包以及类, wxapi/WXPayEntryActivity
在AndroidManifest.xml中引用 WXPayEntryActivityandroid:icon="@drawable/desk"
br/>android:allowBackup="true"
android:icon="@drawable/desk"
android:label="@string/app_name"br/>android:theme="@style/AppTheme">
android:screenOrientation="portrait"
android:label="@string/app_name">
activity
android:name=".activity.MainActivity"
android:screenOrientation="portrait"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".wxapi.WXPayEntryActivity"
android:screenOrientation="portrait"
android:exported="true"
android:launchMode="singleTop"/>
</application>
WXPayEntryActivity 代码详情(支付完成后,onResp会被调用,BaseResp.ErrCode.ERR_OK 表明支付成功)
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
private static final String TAG = "WXPayEntryActivity";
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Constant.wxApi.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
api.handleIntent(intent, this);
}
@Override
public void onReq(BaseReq req) {
}
/**
* 得到支付结果回调
*/
@Override
public void onResp(BaseResp resp)
{
Log.i(TAG, "onPayFinish, errCode = " + resp.errCode);
String strPayResult = "";
switch (resp.errCode) {
case BaseResp.ErrCode.ERR_OK:
Toast.makeText(this, "付款成功!", Toast.LENGTH_SHORT).show();
break;
case BaseResp.ErrCode.ERR_USER_CANCEL:
//分享取消
//Toast.makeText(this, "付款取消!", Toast.LENGTH_SHORT).show();
//Constant.WEIXIN_PAY_STATUS = "PAY_CANCEL";
break;
case BaseResp.ErrCode.ERR_AUTH_DENIED:
//分享拒绝
//Toast.makeText(this, "付款拒绝!", Toast.LENGTH_SHORT).show();
//Constant.WEIXIN_PAY_STATUS = "PAY_DENY";
break;
}
//向之前页面返回支付结果信息
/*Intent intent = new Intent();
intent.putExtra("payResult", strPayResult);
setResult(100, intent);*/
finish();
}
}
3.3 支付按钮的点击事件
通过http协议向后台请求相应的预支付信息, 根据这些信息组装相应的信息来调用微信接口, 拉起微信支付界面
@OnClick(R.id.pay)
public void pay(){
String orderNum = OrderInfo.generateOutTradeNo();
payService
.wpay(orderNum, totalPrice, address.getText().toString() + "-外卖订单")
.subscribe(new Action1<WeiXinPrePay>() {br/>@Override
public void call(WeiXinPrePay payInfo) {
if (Constant.wxApi != null) {
PayReq req = new PayReq();
req.appId = payInfo.getAppId();// 微信开放平台审核通过的应用APPID
req.partnerId = payInfo.getMchId();// 微信支付分配的商户号
req.prepayId = payInfo.getPrepayId();// 预支付订单号,app服务器调用“统一下单”接口获取
req.nonceStr = payInfo.getNonceStr();// 随机字符串,不长于32位,服务器小哥会给咱生成
req.timeStamp = payInfo.getTimeStamp();// 时间戳,app服务器小哥给出
req.packageValue = "WXPay";// 固定值Sign=WXPay,可以直接写死,服务器返回的也是这个固定值
req.sign = payInfo.getPaySign();// 签名,服务器小哥给出,他会根据: om/wiki/doc/api/app/app.php?chapter=4_3指导得到这个
Constant.wxApi.sendReq(req);
}
}
}, new Action1<Throwable>() {br/>@Override
public void call(Throwable throwable) {
showToast(throwable.getMessage());
}
});
}
4 微信支付Java后台
4.1 后台代码结构图
4.2 微信配置信息 Config.properties
4.3 方法wxpay用于生成预支付订单信息
方法notifyWeiXinPay用于微信支付成功后的回调, 注意: 在手机端使用微信支付成功后,微信服务器会根据提供的回调地址进行回调, parameterMap.put("notify_url", wxnotify); (见下面代码)
在局域网是无法进行回调的,必须将你的服务端放在公网上进行测试, 回调函数会被多次调用,如果第一次成功后,你可以将业务数据状态标志为已处理, 对于相同订单的其它回调就不需要再次处理了br/>@Controller
@RequestMapping("/pay")
public class PayController {
String timeMillis = String.valueOf(System.currentTimeMillis() / 1000);
String randomString = PayCommonUtil.getRandomString(32);
//支付成功后的回调函数
public static String wxnotify = "http://gepanjiang.hk1.tunnelfrp.cc/WxPay/pay/notifyWeiXinPay.htm";
public PayController() {
System.out.println("MainController构造函数");
}
/**
* @param totalAmount 支付金额
* @param description 描述
* @param request
* @return
*/
@RequestMapping(value = "/wxpay.htm", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Result wxpay(HttpServletRequest request) {
Result result = new Result();
Long userId = new Long(1);//baseController.getUserId();
BigDecimal totalAmount = new BigDecimal(request.getParameter("totalPrice"));
String trade_no = "";
String description="";
try {
trade_no = new String(request.getParameter("orderNum").getBytes("ISO-8859-1"),"UTF-8");
description = request.getParameter("description");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String openId = "";
Map<String, String> map = weixinPrePay(trade_no,totalAmount,description,openId,request);
SortedMap<String, Object> finalpackage = new TreeMap<String, Object>();
finalpackage.put("appId", ConfigManager.getInstance().getConfigItem("WXAppID")/*PayCommonUtil.APPID*/);
finalpackage.put("mchId", ConfigManager.getInstance().getConfigItem("MCH_ID"));
Long time = (System.currentTimeMillis() / 1000);
finalpackage.put("timeStamp", time.toString());
finalpackage.put("nonceStr", map.get("nonce_str"));
finalpackage.put("prepayId", map.get("prepay_id"));
finalpackage.put("package", "Sign=WXPay");
finalpackage.put("signType", "MD5");
String sign = PayCommonUtil.createSign("UTF-8", finalpackage);
finalpackage.put("paySign", sign);//官方文档上是sign,当前示例代码是paySign 可能以前的
WeiXinPrePay prePay = new WeiXinPrePay();
prePay.setAppId(ConfigManager.getInstance().getConfigItem("WXAppID"));
prePay.setMchId(ConfigManager.getInstance().getConfigItem("MCH_ID"));
prePay.setTimeStamp(time.toString());
prePay.setNonceStr(map.get("nonce_str"));
prePay.setPrepayId(map.get("prepay_id"));
prePay.setSignType("MD5");
prePay.setPaySign("paySign");
result.setData(prePay);
result.setStateCode(GeneralConstant.SUCCESS);
result.setDesc("微信支付加载成功");
return result;
}
/**
* 统一下单
* 应用场景:商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付。
* @param trade_no
* @param totalAmount
* @param description
* @param openid
* @param sym
* @param request
* @return
*/
@SuppressWarnings("unchecked")
public Map<String, String> weixinPrePay(String trade_no,BigDecimal totalAmount,
String description, String openid, HttpServletRequest request) {
SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
parameterMap.put("appid", ConfigManager.getInstance().getConfigItem("WXAppID")); //应用appid
parameterMap.put("mch_id", ConfigManager.getInstance().getConfigItem("MCH_ID")/*PayCommonUtil.MCH_ID*/); //商户号
//parameterMap.put("device_info", "WEB");
parameterMap.put("nonce_str", randomString);
parameterMap.put("body", description);
parameterMap.put("out_trade_no", trade_no);
parameterMap.put("fee_type", "CNY");
System.out.println("jiner");
BigDecimal total = totalAmount.multiply(new BigDecimal(100)); //接口中参数支付金额单位为【分】,参数值不能带小数,所以乘以100
java.text.DecimalFormat df=new java.text.DecimalFormat("0");
parameterMap.put("total_fee", df.format(total));
System.out.println("jiner2");
parameterMap.put("spbill_create_ip", PayCommonUtil.getRemoteHost(request));
parameterMap.put("notify_url", wxnotify);
parameterMap.put("trade_type", "APP");//"JSAPI"
//trade_type为JSAPI是 openid为必填项
//parameterMap.put("openid", openid);
System.out.println("");
String sign = PayCommonUtil.createSign("UTF-8", parameterMap);
System.out.println("jiner2");
parameterMap.put("sign", sign);
String requestXML = PayCommonUtil.getRequestXml(parameterMap);
System.out.println(requestXML);
String result = PayCommonUtil.httpsRequest(
"https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",
requestXML);
System.out.println(result);
Map<String, String> map = null;
try {
map = PayCommonUtil.doXMLParse(result);
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}
/**
* 此函数会被执行多次,如果支付状态已经修改为已支付,则下次再调的时候判断是否已经支付,如果已经支付了,则什么也执行
* @param request
* @param response
* @return
* @throws IOException
* @throws JDOMException
*/
@RequestMapping(value = "notifyWeiXinPay.htm", produces = MediaType.APPLICATION_JSON_VALUE)
Map<String,String> return_data = new HashMap<String,String>();
if (!PayCommonUtil.isTenpaySign(params)) {
// 支付失败
return_data.put("return_code", "FAIL");
return_data.put("return_msg", "return_code不正确");
return StringUtil.GetMapToXML(return_data);
} else {
System.out.println("===============付款成功==============");
// ------------------------------
// 处理业务开始
// ------------------------------
// 此处处理订单状态,结合自己的订单数据完成订单状态的更新
// ------------------------------
String total_fee = params.get("total_fee");
double v = Double.valueOf(total_fee) / 100;
String out_trade_no = String.valueOf(Long.parseLong(params.get("out_trade_no").split("O")[0]));
Date accountTime = DateUtil.stringtoDate(params.get("time_end"), "yyyyMMddHHmmss");
String ordertime = DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss");
String totalAmount = String.valueOf(v);
String appId = params.get("appid");
String tradeNo = params.get("transaction_id");
return_data.put("return_code", "SUCCESS");
return_data.put("return_msg", "OK");
return StringUtil.GetMapToXML(return_data);
}
}
}
原文地址:http://blog.51cto.com/13636962/2085772