Android微信支付详解与Demo

2018年4月5日补充

注意:
1.Android Studio 3.0
2.gradle 3.0
3.Android 8.0


最近公司弄Ionic框架,项目中需要微信支付,无奈,把我调过去弄,期间也是几近崩溃,好在皇天不负有心人,在看别人的文档,终于是在项目中集成了微信支付,下面作为一个小白的我,想要把我的经验分享给大家,希望对大家有所帮助。

先给一个可用的demo吧(运行前先看txt文件)
https://download.youkuaiyun.com/download/qq_35229022/10356669

这个demo是基于eclipse开发的,博主也在Android Studio开发过微信支付,原理都是一样的,大家把这个demo弄懂了,在AS上面也是一样的。

(温馨提示:大家下载下来可能会出错,也有可能不会。下面给出出错的解决方法:1.进入项目中的WeIXinPay->Build Path->configure build path,移除那个报错的jar包。 2.会出现资源找不到的情况,这是因为你没有v7包,下载一个v7包,或者把出错的地方都删除,只是一个主题,删除了看起来不好看而已,当然,你也可以用你有的主题。 还有一个问题需要提出来,就是你可能按照里面的text操作的仍然调不起客户端,有可能是你没有安装微信客户端,因为我没有做判断。这个demo不会出现只能成功支付一次的情况,博主亲测有效。出现只能支付一次只能说明你的签名没有对应)

1.去微信开放平台申请微信支付服务,绑定自己的应用这里具体不多讲,但是一定要申请完成,将会得到是三个参数

 //appid 微信分配的公众账号ID
  public static final String APP_ID = "";

  //商户号 微信分配的公众账号ID
   public static final String MCH_ID = "";

 //  API密钥,在商户平台设置
  public static final  String API_KEY= "";

坑点提示:在微信开发平台设置包名和签名。这里的包名一定要和你自己的包名一样,就是manifest中的package,签名一定要和你用官方app生成的一样(https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk)。
微信会根据你的填写的包名,然后对你的keystore进行一种算法,生成你的签名。包名和签名一定要和微信开放平台的相同。不过这里需要注意的是,如果你发布的正式版本,需要用官方app重新生成签名,然后在开放平台重新设置sign,因为测试版本的keystore与正式版的keystore不一样。总之,就是你用的keystore生成的sign要和微信开放平台的时刻保持一致。

2.准备工作做好了,接下来就是开发了,先下载微信的jar包,导入。
微信支付分为三个步骤
1.生成prepayId

   @Override
    protected Map<String, String> doInBackground(String... params) {
        // TODO Auto-generated method stub
        String url=String.format(params[0]);
        String entity=getProductArgs();
        Log.e("Simon",">>>>"+entity);
        byte[] buf=Util.httpPost(url, entity);
        String content = new String(buf);
        Log.e("orion", "----"+content);
        Map<String,String> xml=decodeXml(content);

        return xml;
    }

2.生成签名参数

   private void genPayReq() {

    req.appId = Constants.APP_ID;
    req.partnerId = Constants.MCH_ID;
    if (resultunifiedorder!=null) {
        req.prepayId = resultunifiedorder.get("prepay_id");
        req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id");
    }
    else {
        Toast.makeText(MainActivity.this, "prepayid为空", Toast.LENGTH_SHORT).show();
    }
    req.nonceStr = getNonceStr();
    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");

    textView.setText(sb.toString());

    Log.e("Simon", "----"+signParams.toString());

}

3.调起支付。

 /*
 * 调起微信支付
 */
private void sendPayReq() {


    msgApi.registerApp(Constants.APP_ID);
    msgApi.sendReq(req);
    Log.i(">>>>>", req.partnerId);
}

下面给出完整代码 :

  package com.alpha.live;

  import java.io.StringReader;
  import java.util.HashMap;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Random;

  import org.apache.http.NameValuePair;
  import org.apache.http.message.BasicNameValuePair;
  import org.xmlpull.v1.XmlPullParser;

  import com.tencent.mm.sdk.modelpay.PayReq;
  import com.tencent.mm.sdk.openapi.IWXAPI;
  import com.tencent.mm.sdk.openapi.WXAPIFactory;

  import android.app.Activity;
  import android.app.AlertDialog;
  import android.app.ProgressDialog;
  import android.os.AsyncTask;
  import android.os.Bundle;
  import android.util.Log;
  import android.util.Xml;
  import android.view.View;
  import android.view.View.OnClickListener;
  import android.widget.Button;
  import android.widget.TextView;
  import android.widget.Toast;
  /**
  * Created by Simon on 2016/12/2.
  */
  public class MainActivity extends Activity implements OnClickListener {
private Button submitButton;
private Button confirmButton;
private TextView textView;
private StringBuffer sb;
private Map<String,String> resultunifiedorder;
private PayReq req;
private final IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null);
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    submitButton=(Button) findViewById(R.id.bt_submit_order);
    confirmButton=(Button) findViewById(R.id.bt_corfirm);
    textView=(TextView) findViewById(R.id.tv_prepay_id);
    submitButton.setOnClickListener(this);
    confirmButton.setOnClickListener(this);
    sb=new StringBuffer();
    req=new PayReq();
}
@Override
public void onClick(View v) {
    // TODO Auto-generated method stub
    switch (v.getId()) {
    case R.id.bt_submit_order:
        String urlString="https://api.mch.weixin.qq.com/pay/unifiedorder";
         PrePayIdAsyncTask prePayIdAsyncTask=new PrePayIdAsyncTask();
         prePayIdAsyncTask.execute(urlString);      //生成prepayId

    break;
    case R.id.bt_corfirm:
        genPayReq();//生成签名参数
        sendPayReq();//调起支付
    break;
    default:
        break;
    }
}
/*
 * 调起微信支付
 */
private void sendPayReq() {


    msgApi.registerApp(Constants.APP_ID);
    msgApi.sendReq(req);
    Log.i(">>>>>", req.partnerId);
}
private long genTimeStamp() {
    return System.currentTimeMillis() / 1000;
}
private void genPayReq() {

    req.appId = Constants.APP_ID;
    req.partnerId = Constants.MCH_ID;
    if (resultunifiedorder!=null) {
        req.prepayId = resultunifiedorder.get("prepay_id");
        req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id");
    }
    else {
        Toast.makeText(MainActivity.this, "prepayid为空", Toast.LENGTH_SHORT).show();
    }
    req.nonceStr = getNonceStr();
    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");

    textView.setText(sb.toString());

    Log.e("Simon", "----"+signParams.toString());

}
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());
    Log.e("Simon","----"+appSign);
    return appSign;
}
private class PrePayIdAsyncTask extends AsyncTask<String,Void, Map<String, String>>
{
    private ProgressDialog dialog;
    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        dialog = ProgressDialog.show(MainActivity.this, "提示", "正在提交订单");

    }
    @Override
    protected Map<String, String> doInBackground(String... params) {
        // TODO Auto-generated method stub
        String url=String.format(params[0]);
        String entity=getProductArgs();
        Log.e("Simon",">>>>"+entity);
        byte[] buf=Util.httpPost(url, entity);
        String content = new String(buf);
        Log.e("orion", "----"+content);
        Map<String,String> xml=decodeXml(content);

        return xml;
    }

    @Override
    protected void onPostExecute(Map<String, String> result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        if (dialog != null) {
            dialog.dismiss();
        }
        sb.append("prepay_id\n"+result.get("prepay_id")+"\n\n");
        textView.setText(sb.toString());
        resultunifiedorder=result;
    }
}

public Map<String,String> decodeXml(String content) {

    try {
        Map<String, String> xml = new HashMap<String, String>();
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(new StringReader(content));
        int event = parser.getEventType();
        while (event != XmlPullParser.END_DOCUMENT) {

            String nodeName=parser.getName();
            switch (event) {
            case XmlPullParser.START_DOCUMENT:

                break;
            case XmlPullParser.START_TAG:

                if("xml".equals(nodeName)==false){
                    //实例化student对象
                    xml.put(nodeName,parser.nextText());
                }
                break;
            case XmlPullParser.END_TAG:
                break;
            }
            event = parser.next();
        }

        return xml;
    } catch (Exception e) {
        Log.e("Simon","----"+e.toString());
    }
    return null;

}
private String getProductArgs() {
    // TODO Auto-generated method stub
    StringBuffer xml=new StringBuffer();
    try {
        String nonceStr=getNonceStr();
        xml.append("<xml>");
        List<NameValuePair> packageParams=new LinkedList<NameValuePair>();
        packageParams.add(new BasicNameValuePair("appid",Constants.APP_ID));
        packageParams.add(new BasicNameValuePair("body", "APP pay test"));
        packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
        packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
        packageParams.add(new BasicNameValuePair("notify_url", "https://www.baidu.com"));//写你们的回调地址
        packageParams.add(new BasicNameValuePair("out_trade_no",genOutTradNo()));
        packageParams.add(new BasicNameValuePair("total_fee", "1"));
        packageParams.add(new BasicNameValuePair("trade_type", "APP"));

        String sign=getPackageSign(packageParams);
        packageParams.add(new BasicNameValuePair("sign", sign));
        String xmlString=toXml(packageParams);
        return xmlString;
    } catch (Exception e) {
        // TODO: handle exception
        return null;
    }
}
//生成订单号,测试用,在客户端生成
private String genOutTradNo() {
    Random random = new Random();
//      return "dasgfsdg1234"; //订单号写死的话只能支付一次,第二次不能生成订单
    return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
//生成随机号,防重发
    private String getNonceStr() {
    // TODO Auto-generated method stub
    Random random=new Random();

    return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
/**
 生成签名
 */

private String getPackageSign(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);


    String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
    Log.e("Simon",">>>>"+packageSign);
    return packageSign;
}
/*
 * 转换成xml
 */
private String toXml(List<NameValuePair> params) {
    StringBuilder sb = new StringBuilder();
    sb.append("<xml>");
    for (int i = 0; i < params.size(); i++) {
        sb.append("<"+params.get(i).getName()+">");


        sb.append(params.get(i).getValue());
        sb.append("</"+params.get(i).getName()+">");
    }
    sb.append("</xml>");

    Log.e("Simon",">>>>"+sb.toString());
    return sb.toString();
}

}  

接下来就是有个支付结果的页面代码。是微信官方提供的一个类。你要在manifest注册这个类。这里需要注意的是,这个类必须放在wxapi包下,你自己新建一个包即可。

为了大家可以直接运行这个demo,我的微信加签都是在本地执行的,获取prepayid和加签都应该在服务端完成,还有最终的支付返回结果也是以服务端的为准。

下面给出运行结果图

5699111-bfa7ffc16f631377.png
微信支付

5699111-bbb3ec04ede2bfc9.png
image.png

大家下载demo然后把参数换了,弄下keystore,包名,签名。应该就可以用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值