之前一直在做Hybrid App(也就是用Android或者IOS的WebView控件嵌入你的H5应用,看起来跟原生应用一样),支付这块有用到第三方的WAP支付,效果还行,就是微信这块收款不能直接跟客户的账户对接,因为WebView允许H5应用利用Javascript呼叫原生应用,所以决定开发Hybrid App下的微信APP支付。
开发微信APP支付,首先要看腾讯给的开发文档。由于新旧接口差异巨大,所以走了不少弯路(大家说微信开发就是一个巨坑也是有道理),但最重要看官方文档,照着他的文档走应该是没错的,只是有些细节不完整。
好,闲话有点多,开始转入正题。微信APP支付大概流程是:服务器端生成预支付ID,然后APP端取得预支付ID后丢给微信SDK去呼叫微信支付。要进行微信APP支付开发,首先得通过微信公众号认证,然后注册开放平台,最后注册商户平台。公众号是基础,开放平台是管理APP信息的,商户平台相当于支付宝,是管理钱的地方。
开发前的准备
微信公众平台:https://mp.weixin.qq.com/cgi-bin/loginpage?t=wxm2-login&lang=zh_CN
微信开放平台:https://open.weixin.qq.com/
微信商户平台:https://pay.weixin.qq.com/index.php/home/login
开发文档:https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=8_1
公众平台应该是必备的,要申请服务号,每年300块钱。
开放平台是创建应用的地方,生成AppID后面会用到,如下图:
商户平台有两个东西会用到,一个是Partner ID,就是微信支付商户号;一个是Key,就是对商户平台的登录密码进行MD5加密后得到的字串,到API安全>>API密钥>>设置密钥,把这个MD5字串填进去保存就行了,如下图:
1.Android原生应用加入微信SDK
这一步很简单,只要把微信SDK引入你的项目,然后调用就可以了,如下图:
调用代码如下:
@JavascriptInterface
public void setWxPay(String appId,String partnerId,String prepayId,String nonceStr,String timeStamp,String packageValue,String sign) {
api = WXAPIFactory.createWXAPI(this, appId);
api.registerApp(appId); //注册APP到微信
Toast.makeText(MainActivity.this, "获取订单中,请稍等...", Toast.LENGTH_SHORT).show();
try{
if(appId!="" && prepayId!=""){
PayReq req = new PayReq();
req.appId = appId;
req.partnerId = partnerId;
req.prepayId = prepayId;
req.nonceStr = nonceStr;
req.timeStamp = timeStamp;
req.packageValue = packageValue;
req.sign = sign;
req.extData = "app data";
Toast.makeText(MainActivity.this, "正常调起支付", Toast.LENGTH_SHORT).show();
api.sendReq(req);
}else{
Log.d("PAY_GET", "服务器请求错误");
Toast.makeText(MainActivity.this, "服务器请求错误", Toast.LENGTH_SHORT).show();
}
}catch(Exception e){
Log.e("PAY_GET", "异常:"+e.getMessage());
Toast.makeText(MainActivity.this, "异常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
2.服务器端生成预支付ID(prepay_id),并调起支付接口
这一步是最重要也是最容易出问题的地方,错一个小小的地方也可能导致发起支付失败。
服务器端是用C#写的,因为我的H5应用也是C#写的(有点废话)。当我H5应用里一件商品下单后,先生成一条订单记录,状态还是未支付的,这时候已经有了商品的名称、价格等商品信息。我们用这个商品的信息发送给微信支付,让它先生成一个预支付的订单,这个叫“统一下单”。
这里用到了网上大神的一些代码,原文是:http://www.cnblogs.com/vinsonLu/p/4345041.html
主要代码如下:
///
/// 支付方法
///
private void WxPay()
{
string appId = "这里填AppID";
string partnerId = "这里填微信支付商户号";
string key = "这里填MD5加密的字串";
string body = txtProductName.Text.Trim();
string orderNumber = DateTime.Now.ToString("yyyyMMddHHmmss");
int price = int.Parse(txtPrict.Text.Trim());
UnifiedOrder order = new UnifiedOrder();
order.appid = appId;
order.mch_id = partnerId;
order.nonce_str = TenpayUtil.getNoncestr();
order.body = body;
order.out_trade_no = orderNumber;
order.total_fee = price; //单位是分
order.spbill_create_ip = Page.Request.UserHostAddress;
order.notify_url = "http://www.yourdomain.com/notify.aspx";
order.trade_type = "APP";
TenpayUtil tu = new TenpayUtil();
string prepayId = tu.getPrepay_id(order, key);
string nonceStr = order.nonce_str;
string timeStamp = TenpayUtil.getTimestamp();
string packageValue = "Sign=WXPay";
SortedDictionary sParams = new SortedDictionary();
sParams.Add("appid", appId);
sParams.Add("noncestr", nonceStr);
sParams.Add("package", packageValue);
sParams.Add("partnerid", partnerId);
sParams.Add("prepayid", prepayId);
sParams.Add("timestamp", timeStamp);
string sign = tu.getsign(sParams, key);
//调用前台JS
RunScript(this, "", "SetWxPay('" + appId + "','" + partnerId + "','" + prepayId + "','" + nonceStr + "','" + timeStamp + "','" + packageValue + "','" + sign + "');");
}
///
/// 执行一条JavaScript函数
///
/// WEB窗体页
/// 标示脚本块的唯一键
/// 脚本内容
public static void RunScript(System.Web.UI.Page page, string key, string script)
{
page.ClientScript.RegisterStartupScript(page.GetType(), key, "");
}
3.获取微信支付结果返回信息
当你支付后,微信会将支付结果以XML的方式返回给你指定的路径,上面写的是http://www.yourdomain.com/notify.aspx,这个地址必须是可以访问的,并且不能带参数。
特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,防止数据泄漏导致出现“假通知”,造成资金损失。
主要代码如下:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string data = "";
try
{
//接收并读取POST过来的XML文件流
StreamReader reader = new StreamReader(Request.InputStream);
String xmlData = reader.ReadToEnd();
data = xmlData;
}
catch { }
if (GetWxKeyValue(data, "return_code") == "SUCCESS")
{
//这里是支付成功的信息,下面你可以自由发挥了,比如写入数据库,更改状态等
//其他信息请参考https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_7&index=3
}
}
}
private string GetWxKeyValue(string data, string key)
{
string value = "";
SortedDictionary requestXML = GetInfoFromXml(data);
foreach (KeyValuePair k in requestXML)
{
if (k.Key == key)
{
value = k.Value;
break;
}
}
return value;
}
///
/// 把XML数据转换为SortedDictionary集合
///
///
///
protected SortedDictionary GetInfoFromXml(string xmlstring)
{
SortedDictionary sParams = new SortedDictionary();
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlstring);
XmlElement root = doc.DocumentElement;
int len = root.ChildNodes.Count;
for (int i = 0; i < len; i++)
{
string name = root.ChildNodes[i].Name;
if (!sParams.ContainsKey(name))
{
sParams.Add(name.Trim(), root.ChildNodes[i].InnerText.Trim());
}
}
}
catch { }
return sParams;
}
源码下载:http://pan.baidu.com/s/1mhtW7cG