C#+Hybrid App(Android)实现微信APP支付

之前一直在做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

主要代码如下:

 /// <summary>
    /// 支付方法
    /// </summary>
    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<string, string> sParams = new SortedDictionary<string, string>();
        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 + "');");
    }

    /// <summary>
    /// 执行一条JavaScript函数
    /// </summary>
    /// <param name="page">WEB窗体页</param>
    /// <param name="key">标示脚本块的唯一键</param>
    /// <param name="script">脚本内容</param>
    public static void RunScript(System.Web.UI.Page page, string key, string script)
    {
        page.ClientScript.RegisterStartupScript(page.GetType(), key, "<script language = 'javascript'>" + script + "</script>");
    }

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<string, string> requestXML = GetInfoFromXml(data);
        foreach (KeyValuePair<string, string> k in requestXML)
        {
            if (k.Key == key)
            {
                value = k.Value;
                break;
            }
        }
        return value;
    }

    /// <summary>
    /// 把XML数据转换为SortedDictionary<string, string>集合
    /// </summary>
    /// <param name="strxml"></param>
    /// <returns></returns>
    protected SortedDictionary<string, string> GetInfoFromXml(string xmlstring)
    {
        SortedDictionary<string, string> sParams = new SortedDictionary<string, string>();
        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



阅读更多

没有更多推荐了,返回首页