androidAPP 集成微信支付

最近项目里面需要支付功能,boss一致决定用微信支付,所以在网上查了很多资料,说的不全,完了就找以前的同事指教。算是成功集成上去了。在这里做个总结记录。

1、在APP上集成微信支付,首先当然是当官网上去注册并获取到支付功能。这些不涉及到开发,官网上说的很详细,这里就不多做文章。获取到这些能力了就为开发提供了条件了。开发中会用到的就是平台给的APPID、APPsercet、以及商户平台上设置的APP_key。

2、具备了支付能力等前提条件之后,就是开发过程了。代码里面怎么才能吊起支付了,参照官网上的DEMO自己也做了一些总结和各方大神的指教。分为了下面几个步奏。

(1)、首先当然是将sdk配置进工程环境中,官网中下载Android端SDK,解压后将libmmsdk.jar导入工程,然后将DEMO中Constant.java(这里是参照官方demo的样式写的,当然也可以采用其他方式)、MD5.java、Util.java放入工程(我这里用到了这些),这些先决条件有了之后就可以下一步写代码操作了。

(2)、生成订单信息

生成订单信息采用了如下方法生成,生成订单信息需要签名文件,所以里面包含了生成签名。微信要求所有请求采用XML参数形式,所有生产订单信息之后又需要转换成xml。订单信息需要的请求参数可以到官网上去对照,这里只加入了一些必要的参数。

生成订单信息方法:

//获取产品订单信息
    private String genProductArgs() {
        StringBuffer xml = new StringBuffer();
        try {
            String nonceStr = genNonceStr();

            xml.append("</xml>");
            List<NameValuePair> packageParams = new LinkedList<NameValuePair>();

            packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID)); //APPID

            packageParams.add(new BasicNameValuePair("body", "单价:" + singlePrice + " x " + payment_num.getText().toString() + "份"));  //简单描述

            packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));  //商户ID

            packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));   //随机字符串

            packageParams.add(new BasicNameValuePair("notify_url","http://www.weixin.qq.com/wxpay/pay.php")); //通知地址

            packageParams.add(new BasicNameValuePair("out_trade_no",getTrade()));  //商户订单号

            packageParams.add(new BasicNameValuePair("spbill_create_ip",getLocalHostIp())); //终端IP

            //double price = Double.parseDouble(payment_num.getText().toString()) * (Integer.parseInt(singlePrice) * 100);
            double price = Double.parseDouble(singlePrice) * 100 * n;
            int priceInt = (int) price;
            packageParams.add(new BasicNameValuePair("total_fee", priceInt+""));    //微信接收int型价格

            packageParams.add(new BasicNameValuePair("trade_type", "APP"));  //支付类型

            String sign = genAppSign(packageParams);
            packageParams.add(new BasicNameValuePair("sign", sign));  //签名

            String xmlstring = parseNodeToXML(packageParams);   //转化成xml

            return xmlstring;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

构造这个xml请求参数采用的是httpclient生成的,所以引入了某些包。也可以采用其他方式生成支付订单,只要最后的形式与官网中的形式相同即可。

里面涉及到某些参数的生成,这里列出的是我们项目里面的业务逻辑,当然不同项目可定是不同的。

//获取订单号
    private String getTrade(){
        long nowTime = System.currentTimeMillis();
        SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmmss");
        return format.format(new Date(nowTime));
    }

    //获取支付签名Sign
    StringBuilder sb = new StringBuilder();
    private 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(Constants.API_KEY);
        this.sb.append("sign str\n" + sb.toString() + "\n\n");
        String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
        return appSign;
    }

    //获取随机字符串
    private String genNonceStr() {
        Random random = new Random();
        return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
    }

    /**
     * 解析为xml格式
     * @param treeNodes
     * @return
     */
    public String parseNodeToXML(List<NameValuePair> treeNodes) {
        StringBuffer xmlnodes = new StringBuffer();
        if (treeNodes != null && treeNodes.size() > 0) {
            xmlnodes.append("<xml>");
            for (int i = 0; i < treeNodes.size(); i++) {
                NameValuePair node = treeNodes.get(i);
                xmlnodes.append("<"+node.getName()+">").append(node.getValue()).append("</"+node.getName()+">");
            }
            xmlnodes.append("</xml>");
        }
        //return xmlnodes.toString();
        String xml = xmlnodes.toString();
        try {
            xml = new String(xml.toString().getBytes(), "ISO8859-1");  //商品详情为中文,将其转化为统一编码,不然获取perpred_id失败
            return xml;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    //获取手机IP
    public String getLocalHostIp() {
        String ipaddress = "";
        try {
            Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
            // 遍历所用的网络接口
            while (en.hasMoreElements()) {
                NetworkInterface nif = en.nextElement();// 得到每一个网络接口绑定的所有ip
                Enumeration<InetAddress> inet = nif.getInetAddresses();
                // 遍历每一个接口绑定的所有ip
                while (inet.hasMoreElements()) {
                    InetAddress ip = inet.nextElement();
                    if (!ip.isLoopbackAddress() && InetAddressUtils.isIPv4Address(ip.getHostAddress())) {
                        return ip.getHostAddress();
                    }
                }
            }
        }
        catch (SocketException e) {
            Log.e("feige", "获取本地ip地址失败");
            e.printStackTrace();
        }
        return ipaddress;
    }

(3)、访问微信后台指定接口,获取perpay_id。

可以说前面的都是为了获取这个perpay_id做准备的,官网上给出的指定接口是“https://api.mch.weixin.qq.com/pay/unifiedorder” 请求采用官网demo中util提供的请求方式

这里采用异步处理方式,当请求指定接口得到perapy_id之后直接吊起支付的方式。

//调用支付获取id
    public void gotoWechat() {
        new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] objects) {   //获取Prepay_id
                String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
                String entity = genProductArgs();   //获取订单信息
                byte[] buf = Util.httpPost(url, entity);
                String content = new String(buf);  //请求成功返回的信息
                //Log.e("orion", content);
                try {
                    xmlParseTest(content);  //解析返回的信息
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (XmlPullParserException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Object o) {
                super.onPostExecute(o);
                wechatPay();
            }
        }.execute();
    }

请求成功返回的数据当然也是xml格式的,需要解析并从中取到perpay_id(返回的结果不止perpay_id,包括其他信息,个人感觉吊起支付只需要perpay_id就行了)。这里也是参考demo中的方式将获取到的信息通过xml解析到

WeixinParentId对象当中。

/**
     * 解析xml
     * 返回prepay_id
     * 通过对象Books获取数据
     */
    WeixinParentId book = null;                //通过对象Books获取数据
    public void xmlParseTest(String str) throws IOException, XmlPullParserException {
        XmlPullParser pullParser = Xml.newPullParser();            //获取XmlPullParser对象
        //InputStream is = getContext().getAssets().open("parse.xml");   //解析文本
        ByteArrayInputStream is = new ByteArrayInputStream(str.getBytes("UTF-8"));
        ArrayList<WeixinParentId> books = null ;

        pullParser.setInput(is, "UTF-8");
        int type = pullParser.getEventType();    //获取事件类型
        while (type != pullParser.END_DOCUMENT) {   //结束文本</books>
            switch(type){
                case XmlPullParser.START_DOCUMENT:    //开始文本<books>
                    books = new ArrayList<WeixinParentId>();
                    break;
                case XmlPullParser.START_TAG:    //开始标记   <book>
                    if (pullParser.getName().equals("xml")) {
                        book = new WeixinParentId();
                    }else if (pullParser.getName().equals("return_msg")) {
                        type = pullParser.next();    //指向下一个位置,不然无法获取数据
                        book.setReturn_msg(pullParser.getText());
                    }else if (pullParser.getName().equals("appid")) {
                        type = pullParser.next();
                        book.setAppid(pullParser.getText());
                    }else if (pullParser.getName().equals("prepay_id")) {
                        type = pullParser.next();
                        book.setPrepay_id(pullParser.getText());
                    }

                    break;
                case XmlPullParser.END_TAG:   //结束标记      </books>
                    if (pullParser.getName().equals("book")) {
                        books.add(book);
                        book = null;    //置为空释放资源
                    }
                    break;
            }
            type = pullParser.next();    //指向下一个标记

        }
        //Log.e("test", "book------id----" + book.getPrepay_id());
    }

成功执行这不之后,book对象中perpay_id已经被赋值。只需在异步中取出使用即可。


//获取到perpay_id之后吊起微信支付
    protected void wechatPay() {
        PayReq req = new PayReq();
        req.appId = Constants.APP_ID;
        req.partnerId = Constants.MCH_ID;
        req.prepayId = book.getPrepay_id();
        req.packageValue = "Sign=WXPay";
        req.nonceStr = genNonceStr();
        req.timeStamp = String.valueOf(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 = genAppSign(signParams);
        sb.append("sign\n" + req.sign + "\n\n");
        // 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
        //Log.e("test","book.getPrepay_id()----------"+book.getPrepay_id()+"-------genNonceStr()-------"+genNonceStr()+"--------genTimeStamp()-------"+genTimeStamp()+"---genAppSign(signParams)--"+genAppSign(signParams));
        api.sendReq(req);
        // dialog.dismiss();

    }

    //获取时间搓
    private long genTimeStamp() {
        return System.currentTimeMillis() / 1000;
    }

把前面的异步操作方法赋给一个按钮点击事件,如果所有步奏正确,就可以进入支付界面了,如下图:



点击确支付当然就是输入密码什么的操作了,支付成功后有一个反馈信息如下图:



点击完成,当然是回到APP咯,这里就是微信提供的一个回调了。也就是官网上强调的wxapi包下的
WXPayEntryActivity里的Onresp()方法中做回调处理,该包必须在项目工程包目录下才能回调成功。下面贴出的是示例工程结构



在回调中弹出了对话框提示用户支付成功并处理其他逻辑。

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {

    private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity";

    private IWXAPI api;

    @Override public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

//        setContentView(R.layout.activity_main2);
        api = WXAPIFactory.createWXAPI(this, Constants.APP_ID);
        api.handleIntent(getIntent(), this);
        api.registerApp(Constants.APP_ID);
    }

    @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) {
        int errCode = resp.errCode;

        if (errCode == 0) {

            // 0成功 展示成功页面
            // Intent intent = new Intent("name");
            // sendBroadcast(intent);
            // Log.e("test","支付成功的回调方法--onResp--");
            // Toast.makeText(this,"支付完成",Toast.LENGTH_SHORT).show();

            new AlertDialog.Builder(this).setMessage("支付成功").setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    finish();
                    PaymentActivity.instance.finish();

                    Intent intent = new Intent(WXPayEntryActivity.this, PuzzGameActivity.class);
                    intent.putExtra("ISPLAY",true);
                    startActivity(intent);

                }
            }).setTitle("提示").create().show();

            Toast.makeText(this,"点击确定按钮开始参与拼图游戏活动",Toast.LENGTH_LONG).show();

        }
        else if (errCode == -1) {
            //-1 错误 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。
            new AlertDialog.Builder(this).setMessage("支付出错").setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    finish();
                }
            }).setTitle("提示").create().show();
            finish();
        }
        else if (errCode == -2) {
            //-2 用户取消 无需处理。发生场景:用户不支付了,点击取消,返回APP。
            finish();
        }
    }

}

这样所有步骤就几乎完全了,结合官方示例和文档,应该可以快速的在项目中加入支付功能了。

当然,这里所涉及到的步骤全是在app客户端进行的,官网上建议将获取签名等操作放在服务后台进行,应该是为了安全吧,也就是客服端将订单信息传给服务端。服务端返回吊起支付必要的信息

(包括perpay_id、商户id 、签名等),然后由客户端吊起微信支付的。

时间: 2024-09-30 06:12:23

androidAPP 集成微信支付的相关文章

小程序服务端集成微信支付

摘要: 换取openid->统一下单->发起支付,三步走,其中二次签名比较坑人. 该demo源码已托管到码云:http://git.oschina.net/dotton/lendoo-wx,欢迎下载. 理论上集成微信支付的全部工作可以在小程序端完成,因为小程序js有访问网络的能力,但是为了安全,不暴露敏感key,而且可以使用官方提供的现成php demo更省力,于是在服务端完成签名与发起请求,小程序端只做一个wx.requestPayment(OBJECT)接口的对接. 整体集成过程与JSAP

iOS第三方支付集成——微信支付

近期笔者开发的项目中,需要用到支付宝支付和微信支付.大概一个月前,支付宝就已经集成完毕并可以正常使用.但在集成坑爹的微信支付SDK时,遇到了诸多问题,搞了将近三个星期.期间不断的跟后台同事核对代码(签名.下单),支付流程,其中的血泪艰辛,不言而喻.现笔者把集成过程中遇到的一些问题记录下来,供自己和大家参考.如果有什么不对的地方,也请大家多多指正: 吐槽完了,下面出正文. 补充说明:第一准备阶段不需要开发者负责操作,如果你是iOS开发人员,只想找到调用微信支付的代码,可直接跳过 第一准备阶段. 一

安卓 集成微信支付和支付宝

最近比较闲,公司项目更换后台,于是自己来研究微信支付和支付宝支付,把自己学习的过程写下来,以备以后查看. 注:要集成微信支付和支付宝功能,必须要有以下几个配置信息,而这写信息需要公司去微信支付和支付宝开放平台申请并提供给开发者,当然自己也可以去申请,这里作者用的是公司提供的,这里不纠结这些过程.获得这些信息以后 将配置信息放到一个静态类中,以共统一使用,但是处于安全考虑,微信与支付宝推荐这些数据放到服务器,这里作者把他们都放在前端,整个过程都是前端处理,实际开发尽量预处理订单生成放到后端处理.

iOS 集成微信支付

目前项目里有微信支付的需求,调研过一段时间后,发现其实并没有想象中的那么困难.如果你只是想实现该功能,一个方法足以,但是若你想深入了解实现原理.就需要花费更多的功夫了.目前我只清楚微信支付需要做签名,一种是在后台签名,一种是自己在前端签名.其实这对前端来说代码量并没有多大的改变,最大的区别是在后台签名逻辑更容易理解,而在前端签名逻辑有些混乱. 现在,小编也只是知道怎么使用,而不得其精髓,现在我附上我的学习链接,为了避免以后链接出现不可用情况,请各位理解小编的粘贴复制. 博客园(幻想无极) htt

iOS开发集成微信支付

首先需要理清楚流程: 1.用户使用APP客户端,选择商品下单. 2.商户客户端(就是你做的APP)将用户的商品数据传给商户服务器,请求生成支付订单. 3.商户后台调用统一下单API向微信的服务器发送请求,微信服务器生成预付单,并生成一个prepay_id返回给商户后台. 4.商户后台将这个prepay_id返回给商户客户端. 5.用户点击确认支付,这时候商户客户端调用SDK打开微信客户端,进行微信支付. 6.微信客户端向微信服务器发起支付请求并返回支付结果(他们之间交互用的就是prepay_id

iOS集成微信支付

微信支付的开发 前言:之前听说过微信支付有很多坑,其实没有想象的那么坑,整体感觉很容易上手,按照它的流程来不会有错!PS:官方的流程看的TMD烦,好啦,废话有点多,进入开发.(ps:每个微信的版本一直都在更新,这是2015/6/1给你们做的标记 1.    导入微信支付库 微信开放平台新增了微信模块用户统计功能,便于开发者统计微信功能模块的用户使用和活跃情况.开发者需要在工程中链接上:SystemConfiguration.framework,libz.dylib,libsqlite3.0.dy

PC端网站集成微信支付的关键代码

目前来看,PC段实现微信支付,需要生成二维码,然后用微信扫码支付. 微信支付官网DEMO没有ASP.NET的,只能自己从帮助文档里扣代码摸索.这里需要说明几点特别要注意的. 看了下微信官网的文档,总结支付方式应该是两种: 1.Navite 静态链接方式. 2.JSAPI 方式.这种应该是手机端用到的.只支持微信内置浏览器. 我使用的是第一种方式. 但是据文档描述,这种方式还分为两种.请求流程不同,如下: 1.发送支付请求到微信 -> 微信返回支付Prepay_ID -> 发送支付信息到微信 -

iOS集成微信支付各种坑收录

统一下单的参数要拼接成XML格式,使用AFN请求时,要对参数转义,直接传入字典给AFN,无法识别(这个接口,微信demo中并没有提供示例) AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; //这里传入的xml字符串只是形似xml,但是不是正确是xml格式,需要使用af方法进行转义 manager.responseSerializer = [[AFHTTPResponseSerial

微信支付集成

一.在微信开发平台进行账号注册 注册网址 https://open.weixin.qq.com/cgi-bin/readtemplate?t=regist/regist_tmpl&lang=zh_CN 挨个填写信息即可 二.资质认证 1.点击数据中心,开发者资质认知,现在申请 现在进入如下界面 2.点击完同意协议之后,开始填写其他的信息 1>.企业业务资料 2>.管理员信息 3>.企业基本资料 准备好申请人的身份证证件照正反 ps:三证合一:组织机构代码证.企业工商营业执照.税务