Android APP微信支付开发的步骤

1.我们看官方文档的步骤

APP端开发步骤: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5

在微信开放平台(https://open.weixin.qq.com)上申请开发应用,管理中心-->创建移动应用,

需要填写资料信息,审核时间大概7个工作日。

审核通过后,微信开放平台会生成APP的唯一标识AppID和AppSecret(要保存好);

在应用详情中有获得微信支付能力选项,我们可以去申请开通,开通后微信会给我们微信支付商户平台的账号和密码

登录地址:https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F

我们可以看 https://jingyan.baidu.com/article/75ab0bcbbf7034d6864db2c3.html,微信支付商户平台-配置密钥。

由此我们在开发过程中需要的三个东西:AppID、商户平台账号MCH_ID、商户密钥API_KEY都有了;


开发Android的时候,设置应用签名和应用包名;
Android APP微信支付开发的步骤_第1张图片

签名工具下载地址https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk




2.在开发过程中请求接口的参数需要用到签名校验

微信支付接口签名的规则
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3


微信支付接口签名校验工具
官方文档地址   https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=20_1


具体编写代码 java 请看这篇文章
http://blog.csdn.net/xb12369/article/details/45716665




3.向微信支付后台请求统一下单接口,生成微信支付预支付订单prepayid,这个本来该后台来做的
Android 微信支付实现统一下单接口,官方文档 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
看文档,主要流程就是把20个左右的参数封装为XML格式发送到微信给的接口地址,这其中就用到第2步中的签名校验。
然后就可以获取到返回的内容了,如果成功里面就有支付所需要的预支付prepayid。



创建请求微信统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder
返回结果model

public class WXPrepareModel {

    private String return_code;
    private String return_msg;
    private String appid;
    private String mch_id;
    private String nonce_str;
    private String sign;
    private String result_code;
    private String prepay_id;
    private String trade_type;

    public String getReturn_code() {
        return return_code;
    }

    public void setReturn_code(String return_code) {
        this.return_code = return_code;
    }

    public String getReturn_msg() {
        return return_msg;
    }

    public void setReturn_msg(String return_msg) {
        this.return_msg = return_msg;
    }

    public String getAppid() {
        return appid;
    }

    public void setAppid(String appid) {
        this.appid = appid;
    }

    public String getMch_id() {
        return mch_id;
    }

    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public String getResult_code() {
        return result_code;
    }

    public void setResult_code(String result_code) {
        this.result_code = result_code;
    }

    public String getPrepay_id() {
        return prepay_id;
    }

    public void setPrepay_id(String prepay_id) {
        this.prepay_id = prepay_id;
    }

    public String getTrade_type() {
        return trade_type;
    }

    public void setTrade_type(String trade_type) {
        this.trade_type = trade_type;
    }

    public String getNonce_str() {
        return nonce_str;
    }

    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }


    @Override
    public String toString() {
        return "WXPrepareModel{" +
                "return_code='" + return_code + '\'' +
                ", return_msg='" + return_msg + '\'' +
                ", appid='" + appid + '\'' +
                ", mch_id='" + mch_id + '\'' +
                ", nonce_str='" + nonce_str + '\'' +
                ", sign='" + sign + '\'' +
                ", result_code='" + result_code + '\'' +
                ", prepay_id='" + prepay_id + '\'' +
                ", trade_type='" + trade_type + '\'' +
                '}';
    }
}


创建一个工具类 
public class WXPayManager {

    // MARK: - 微信参数配置
    public static String API_KEY = ""; // 商户秘钥
    public static String MCH_ID = "";  // 商户id

    public static String APPID = "";

    // 微信支付成功后向咱们后台的,回调地址
    public static String WXNotify_url = "";




    // MARK: - 随机字符串生成
    public static String getRandomString(int length) {
        //length表示生成字符串的长度
        String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }


    // MARK: - 请求xml组装
    public static String getRequestXml(SortedMap parameters){

        StringBuffer sb = new StringBuffer();
        sb.append("");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String key = (String)entry.getKey();
            String value = (String)entry.getValue();
            if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
                sb.append("<"+key+">"+"");
            }else {
                sb.append("<"+key+">"+value+"");
            }
        }
        sb.append("");
        return sb.toString();
    }


    // MARK: - 生成签名
    public static String createSign(String characterEncoding,SortedMap parameters){
        StringBuffer sb = new StringBuffer();

        //所有参与传参的参数按照accsii排序(升序)
        Set es = parameters.entrySet();

        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            if(null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + API_KEY);
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }


    //请求方法
    private static String httpsRequest(Activity activity, 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);
            Toast.makeText(activity, "连接超时", Toast.LENGTH_SHORT).show();

        } catch (Exception e) {
            System.out.println("https请求异常:{}"+ e);
            Toast.makeText(activity, "网络异常", Toast.LENGTH_SHORT).show();
        }
        return null;
    }


    // MARK: - 请求微信接口,生成微信后台的预支付订单
    // 官方:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
    public static void generatePrepaymentOrder(final Activity activity,
                                               final String appid,
                                               String body,
                                               final String mch_id,
                                               String nonce_str,
                                               String wxnotify_url,
                                               String out_trade_no,
                                               String spbill_create_ip,
                                               String total_fee,
                                               String trade_type) {



        final SortedMap parameterMap = new TreeMap();

        parameterMap.put("appid", WXPayManager.APPID);
        parameterMap.put("mch_id", WXPayManager.MCH_ID);
        parameterMap.put("nonce_str", nonce_str);
        parameterMap.put("body", body);
        parameterMap.put("out_trade_no", out_trade_no);
        parameterMap.put("total_fee", total_fee);
        parameterMap.put("spbill_create_ip", spbill_create_ip);
        parameterMap.put("notify_url", WXPayManager.WXNotify_url);
        parameterMap.put("trade_type", trade_type);


        final String sign = WXPayManager.createSign("UTF-8", parameterMap);
        System.out.println("sign==" + sign);

        parameterMap.put("sign", sign);

        final String requestXML = WXPayManager.getRequestXml(parameterMap);
        System.out.println("requestXML==" + requestXML);

        new Thread(){

            @Override
            public void run() {
                super.run();


                String result = httpsRequest(activity,
                        "https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",
                        requestXML);
                System.out.println("result==" + result);


                try {
                    WXPrepareModel prepareModel = WXPayManager.doXMLParse(result);
                    System.out.println("prepareModel==" + prepareModel.toString());


                    if (prepareModel.getResult_code().equals("SUCCESS") &&
                            prepareModel.getReturn_code().equals("SUCCESS")) {


                        // 构造参数列表
                        String packageStr = "Sign=WXPay";
                        String timestamp = "" + System.currentTimeMillis() / 1000;


                        SortedMap parameters = new TreeMap();
                        parameters.put("appid", prepareModel.getAppid());
                        parameters.put("partnerid", prepareModel.getMch_id());
                        parameters.put("prepayid", prepareModel.getPrepay_id());
                        parameters.put("noncestr", prepareModel.getNonce_str());
                        parameters.put("package", packageStr);
                        parameters.put("timestamp", timestamp);


                        String signStr = createSign("UTF-8", parameters);
                        System.out.println("signStr==" + signStr);


                        toPay(activity,
                                prepareModel.getAppid(),
                                prepareModel.getMch_id(),
                                prepareModel.getPrepay_id(),
                                prepareModel.getNonce_str(),
                                timestamp,
                                packageStr,
                                signStr);

                    } else {

                        System.out.println("生成微信后台预支付订单id失败");
                        System.out.println("prepareModel.getReturn_msg==" + prepareModel.getReturn_msg());
                    }


                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("生成微信后台预支付订单id请求结果的 xml解析失败");
                }


            }
        }.start();
    }


    // MARK: - 解析 xml
    public static WXPrepareModel doXMLParse(String strxml) throws Exception {

        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");

        if(null == strxml || "".equals(strxml)) {
            return null;
        }

//        Map m = new HashMap();



        InputStream inputStream = new ByteArrayInputStream(strxml.getBytes("UTF-8"));



        XmlPullParser pullParser = Xml.newPullParser();

        // 设置 参数
        pullParser.setInput(inputStream, "utf-8");

        // 获取事件类型
        int type = pullParser.getEventType();


        WXPrepareModel resultModel = null;


        while (type != XmlPullParser.END_DOCUMENT) {


            // 正式解析
            switch (type) {

                case XmlPullParser.START_TAG: {
                    // 解析开始标签

                    // 具体判断解析到的是哪个标签
                    if ("xml".equals(pullParser.getName())) {

                        resultModel = new WXPrepareModel();

                    } else if ("return_code".equals(pullParser.getName())) {

                        String return_code = pullParser.nextText();
                        System.out.println("return_code==" + return_code);

                        resultModel.setReturn_code(return_code);

                    } else if ("return_msg".equals(pullParser.getName())) {

                        String return_msg = pullParser.nextText();
                        resultModel.setReturn_msg(return_msg);

                    } else if ("appid".equals(pullParser.getName())) {

                        String appid = pullParser.nextText();
                        resultModel.setAppid(appid);

                    } else if ("mch_id".equals(pullParser.getName())) {

                        String mch_id = pullParser.nextText();
                        resultModel.setMch_id(mch_id);

                    } else if ("nonce_str".equals(pullParser.getName())) {

                        String nonce_str = pullParser.nextText();
                        resultModel.setNonce_str(nonce_str);

                    } else if ("sign".equals(pullParser.getName())) {

                        String sign = pullParser.nextText();
                        resultModel.setSign(sign);

                    } else if ("result_code".equals(pullParser.getName())) {

                        String result_code = pullParser.nextText();
                        resultModel.setResult_code(result_code);
                    } else if ("prepay_id".equals(pullParser.getName())) {

                        String prepay_id = pullParser.nextText();
                        resultModel.setPrepay_id(prepay_id);
                    } else if ("trade_type".equals(pullParser.getName())) {

                        String trade_type = pullParser.nextText();
                        resultModel.setTrade_type(trade_type);
                    }



                    break;
                }

                case XmlPullParser.END_TAG: {
                    // 解析结束标签

                    if ("xml".equals(pullParser.getName())) {

                        // 把对象放到集合中
//                    weatherList.add(channelModel);
                    }
                    break;
                }

            }


            // 不停的向下解析
            type = pullParser.next();

        }



        //关闭流
        inputStream.close();

        return resultModel;
    }

    // MARK: - 判断手机是否安装微信,微信版本是否支持支付
    public static Boolean chechWXCanPay(Activity activity) {

        IWXAPI api = WXAPIFactory.createWXAPI(activity, WXPayManager.APPID, false);

        Boolean isCanPay = true;
        if (!api.isWXAppInstalled()) {
            Toast.makeText(activity, "您的手机没有安装微信", Toast.LENGTH_SHORT).show();
            isCanPay = false;
        } else {

            boolean isPaySupported = api.getWXAppSupportAPI() >= Build.PAY_SUPPORTED_SDK_INT;

            if (!isPaySupported) {
//            Toast.makeText(activity, String.valueOf(isPaySupported), Toast.LENGTH_SHORT).show();
                Toast.makeText(activity, "您的微信版本过低,不支持支付", Toast.LENGTH_SHORT).show();
                isCanPay = false;
            }
        }


        return isCanPay;
    }


    // MARK: - 进入微信客服端去支付
    public static void toPay(final Activity activity,
                             final String appId,
                             final String mch_id,
                             final String prepayid,
                             final String noncestr,
                             final String timestamp,
                             final String packageValue,
                             final String sign) {

        // 在主线程中执行
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {


                // IWXAPI 是第三方app和微信通信的openapi接口
                // 通过WXAPIFactory工厂,获取IWXAPI的实例
                IWXAPI api = WXAPIFactory.createWXAPI(activity, WXPayManager.APPID, false);

                // 将该app注册到微信
                api.registerApp(WXPayManager.APPID);


                System.out.println("appId==" + appId);
                System.out.println("mch_id==" + mch_id);
                System.out.println("prepayid==" + prepayid);
                System.out.println("noncestr==" + noncestr);
                System.out.println("timestamp==" + timestamp);
                System.out.println("packageValue==" + packageValue);
                System.out.println("sign==" + sign);


                PayReq req = new PayReq();

                req.appId			= appId;
                req.partnerId		= mch_id;
                req.prepayId		= prepayid;
                req.nonceStr		= noncestr;
                req.timeStamp		= timestamp;
                req.packageValue	= packageValue;
                req.sign			= sign;


                Toast.makeText(activity, "正常调起支付", Toast.LENGTH_SHORT).show();
                // 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
                api.sendReq(req);
            }
        });

    }

}

获取ip地址

public class IPHelper {


    // MARK: - 获取内网IP地址
    /**
     * 获取ip地址
     * @return
     */
    public static String getHostIP() {

        String hostIp = null;
        try {
            Enumeration nis = NetworkInterface.getNetworkInterfaces();
            InetAddress ia = null;
            while (nis.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) nis.nextElement();
                Enumeration ias = ni.getInetAddresses();
                while (ias.hasMoreElements()) {
                    ia = ias.nextElement();
                    if (ia instanceof Inet6Address) {
                        continue;// skip ipv6
                    }
                    String ip = ia.getHostAddress();
                    if (!"127.0.0.1".equals(ip)) {
                        hostIp = ia.getHostAddress();
                        break;
                    }
                }
            }
        } catch (SocketException e) {
            Log.i("yao", "SocketException");
            e.printStackTrace();
        }

        if (hostIp == null) {
            hostIp = "0.0.0.0";
        }

        return hostIp;

    }

    // MARK: - 获取外网IP地址
    /**
     * 获取IP地址
     * @return
     */
    public static String GetNetIp() {
        URL infoUrl = null;
        InputStream inStream = null;
        String line = "";
        try {
            infoUrl = new URL("http://pv.sohu.com/cityjson?ie=utf-8");
            URLConnection connection = infoUrl.openConnection();
            HttpURLConnection httpConnection = (HttpURLConnection) connection;
            int responseCode = httpConnection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                inStream = httpConnection.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
                StringBuilder strber = new StringBuilder();
                while ((line = reader.readLine()) != null)
                    strber.append(line + "\n");
                inStream.close();
                // 从反馈的结果中提取出IP地址
                int start = strber.indexOf("{");
                int end = strber.indexOf("}");
                String json = strber.substring(start, end + 1);
                if (json != null) {
                    try {
                        JSONObject jsonObject = new JSONObject(json);
                        line = jsonObject.optString("cip");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                return line;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return line;
    }
}

把inputStream 转换为 String

public class StreamTools {

    // 把一个 inputStream 转换为一个 String
    public static String readStream(InputStream inputStream) throws Exception {

        // 定义一个内存输出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        int len = -1;
        byte[] buffer = new byte[1024]; //1kb

        while ((len = inputStream.read(buffer)) != -1) {

            baos.write(buffer, 0, len);
        }
        inputStream.close();

        String content = new String(baos.toByteArray());


        // 如果服务器是以 gbk 方式编码的,则这个地方写 gbk;否则返回的是乱码
//        String content = new String(baos.toByteArray(), "gbk");

        return content;
    }

}


4.APP端调起支付的参数列表,官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12

微信支付官方 Demo:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1

在开发文档API详细说明 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_4

中,点击Android资源下载可以看到

https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&token=&lang=zh_CN

在 Android Studio环境下集成和在 eclipse环境下集成微信支付 SDK的方法;

Android Studio环境下:已改用gradle形式,发布到jcenter( http://jcenter.bintray.com/),请开发者使用gradle来编译、更新微信SDK。

在build.gradle文件中,添加如下依赖即可:

dependencies {

   compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'

}


dependencies {

   compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'

}

(其中,前者包含统计功能)


eclipse环境下:点击下载 Android开发工具包

注意:因为微信SDK从4.0.2版本开始已改用gradle形式,后续Android开发工具包将不再更新,请开发者尽快改用gradle方式编译、更新微信SDK。

使用微信语音识别接口、语音合成接口。点击下载 语音SDK+Demo+开发文档

使用微信图像识别接口。点击下载 图像SDK+Demo+开发文档

使用微信卡券功能接口。点击下载 卡券SDK+开发文档


范例代码

包含了一个完整的范例工程。该范例的使用可以参阅Android平台上手指南:HelloWeixin@Android。点击下载


签名生成工具

用于获取安装到手机的第三方应用签名的apk包。点击下载 签名生成工具




我们用到这个类,微信支付成功后点击返回商户

WXPayEntryActivity.java ,是支付结果页面;

弹窗中,resp.errCode值的意义:

0 成功 展示成功页面
-1 错误 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。
-2 用户取消 无需处理。发生场景:用户不支付了,点击取消,返回APP。



5.出现问题解决,微信支付 第一次成功,其他无法调起,返回-1(Android eclipse 微信支付之大坑 签名工具问题)
http://blog.csdn.net/ws1836300/article/details/53893102




你可能感兴趣的:(Android APP微信支付开发的步骤)