Android—基于微信开放平台v3SDK,开发微信支付填坑。

ling4444 8年前
   <p>接触微信支付之前听说过这是一个坑,,,心里已经有了准备。。。我以为我没准跳坑出不来了,没有想到我填上了,调用成功之后我感觉公司所有的同事都是漂亮的,隔着北京的大雾霾我仿佛看见了太阳~~~好了,装逼结束。。。进入正题</p>    <p>开发准备:</p>    <p>1.在微信开放平台申请账号</p>    <p>2.成功后创建应用,就是填一些看似很官方很正经的资料了。。。(说审核7天左右,没有意外的情况下你的app第二天就审核成功了是不是很开心,有了appid,是不是就可以调用微   信支付了????-------想多了,真的)</p>    <p>3.微信支付是需要额外申请的:需要资料审核,账户验证,协议签署等步骤,(我记得,,资料审核要填写的东西好多,,,好多,,,账户验证就是你审核成功后微信会发送邮件到你   注册时登记的邮箱账号,其中含有随机金额用于账户验证,协议签署,略,太简单)一定要好好阅读你邮件的任何信息,因为有的细节错了,,,你可能填坑很久。。。。。。</p>    <p>正式开发阶段:</p>    <p>问题1:</p>    <p>调用官方的SDK发现只能成功的调起一次微信,再次支付的时候怎么也调用不起来了</p>    <p>解决:</p>    <p>似乎不是什么正经方法:在手机设置中管理应用程序,清除微信数据,缓存,,再来一遍,绝对可以调起来(当然还是只是一次。。。。)</p>    <p>继续:</p>    <p>我认为要用微信支付嘛,,就只看了调用支付接口的文档:</p>    <p><img src="https://simg.open-open.com/show/1128c727c1d6457461c7e95f82707f83.png"></p>    <p>后来发现需要的参数prepayid是怎么也找不到啊,,后来才发现这个prepayid是先调用”统一下单“这个接口时候温馨反过来的东西,但是官方的SDK中并没有统一下单的代码。坑吗???</p>    <p>所以要先看统一下单文档了    <a href="/misc/goto?guid=4959725726310271571" rel="nofollow,noindex">https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1</a></p>    <p>1.使用自己的APP调用的时候把官网down下来的SDK中WXPayEntryActivity拷贝到自己的项目,所在包的名字最后一定是.wxapi(我连包一起拷了。。。。)</p>    <p>2.在项目清单文件中填写:</p>    <p><img src="https://simg.open-open.com/show/6ee52434fbd56dd934ef4b1602d8fb2d.png"></p>    <p>3.SDK中的AppRegister拷贝下来,,,里面换成你自己的appid,然后在项目清单中也注册一下。</p>    <p><img src="https://simg.open-open.com/show/ba09d36210579d8843b47380e8dc06c1.png"></p>    <p>4.重点来了,,就是你APP要调微信支付的activity,我这还叫PayActivity</p>    <p>要调起微信支付页面,要在这个activity中,将你的app注册到微信</p>    <p><img src="https://simg.open-open.com/show/46aba16abd513a54dd9ae8372df9a032.png"></p>    <p>接下来先调用统一下单获取prepayid,参数,微信人家要xml格式的!我们就得发送xml格式的!</p>    <p><img src="https://simg.open-open.com/show/bc0a723f7f9620e8b0cc3aa0b56b4337.png"></p>    <p>好了调用的时候把这个方法的返回值当参数传,,等待微信返回success吧!。。</p>    <p>我遇见的错误:签名错误</p>    <p>我的原因是大意了 ConfigUtil.NOTIFY_URL这个参数写的空字符串</p>    <p>还有是因为debug版运行的,没有打包运行</p>    <p>返回成功之后,可以调用支付接口了</p>    <p><img src="https://simg.open-open.com/show/1bc32a96f42f840055d61f9099ee56b6.png"></p>    <p>不要忘了这一步去跳转界面,,,,,</p>    <p><img src="https://simg.open-open.com/show/f578cf50fc1259a0848ab9ed33b226f1.png"></p>    <p>没有跳转到微信支付可能是你由运行的debug版本,,,,没有打包。。。。。</p>    <p>下面是我的PayActivity完整代码:</p>    <pre>  <code class="language-java">package com.example.taijiapp.ui;    import java.io.StringReader;  import java.net.InetAddress;  import java.net.NetworkInterface;  import java.net.SocketException;  import java.util.Enumeration;  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.example.taijiapp.R;  import com.example.taijiapp.util.Constants;  import com.example.taijiapp.util.MD5;  import com.example.taijiapp.util.T;  import com.example.taijiapp.util.Util;  import com.example.taijiapp.utils.ConfigUtil;  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.ProgressDialog;  import android.content.Context;  import android.net.wifi.WifiInfo;  import android.net.wifi.WifiManager;  import android.os.AsyncTask;  import android.os.Bundle;  import android.util.Log;  import android.util.Xml;  import android.view.View;  import android.widget.Button;    public class PayActivity extends Activity {   PayReq req;   private IWXAPI msgApi;   Map<String, String> resultunifiedorder;   StringBuffer sb;   @Override   protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.pay);    req = new PayReq();    sb = new StringBuffer();    msgApi = WXAPIFactory.createWXAPI(this, Constants.APP_ID);    /**     * 将app注册到微信     */    boolean registerApp = msgApi.registerApp(Constants.APP_ID);    T.show(this, "注册========"+registerApp+"");    Button appayBtn = (Button) findViewById(R.id.appay_btn);    Button check_pay_btn = (Button) findViewById(R.id.check_pay_btn);    appayBtn.setOnClickListener(new View.OnClickListener() {       @Override     public void onClick(View v) {      GetPrepayIdTask getPrepayId = new GetPrepayIdTask();      getPrepayId.execute();     }    });    /**     * 将该app注册到微信     */    check_pay_btn.setOnClickListener(new View.OnClickListener() {       @Override     public void onClick(View v) {      genPayReq();      sendPayReq();           }    });  //  // 生成签名参数  //  Button appay_pre_btn = (Button) findViewById(R.id.appay_pre_btn);  //  appay_pre_btn.setOnClickListener(new View.OnClickListener() {  //  //   @Override  //   public void onClick(View v) {  //    genPayReq();  //   }  //  });   }   /**    * 生成签名    */     private String genPackageSign(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.KEY);    Log.e("拼接=====", sb.toString());    String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();    Log.e("orion生成签名===", packageSign);    return packageSign;   }     /**    * 签名工具 不含商户密钥 -暂时不用 = * 编码格式 UTF-8 = * @return    */   public static String createSignNoKey(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('&');    }    String signStr = sb.toString();    String subStr = signStr.substring(0, signStr.length() - 1);    // 注意sign转为大写    return MD5.getMessageDigest(subStr.getBytes()).toUpperCase();   }     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.KEY);      this.sb.append("sign str\n" + sb.toString() + "\n\n");    String appSign = MD5.getMessageDigest(sb.toString().getBytes());    Log.e("orion", appSign);    return appSign;   }     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("orion", sb.toString());    return sb.toString();   }     private class GetPrepayIdTask extends AsyncTask<Void, Void, Map<String, String>> {      private ProgressDialog dialog;      @Override    protected void onPreExecute() {     dialog = ProgressDialog.show(PayActivity.this, getString(R.string.app_tip),       getString(R.string.getting_prepayid));    }      @Override    protected void onPostExecute(Map<String, String> result) {     if (dialog != null) {      dialog.dismiss();     }     sb.append("prepay_id\n" + result.get("prepay_id") + "\n\n");       resultunifiedorder = result;      }      @Override    protected void onCancelled() {     super.onCancelled();    }      @Override    protected Map<String, String> doInBackground(Void... params) {       String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");     String entity = genProductArgs();     Log.e("orion===发送过去", entity);     byte[] buf = Util.httpPost(url, entity);       String content = new String(buf);     Log.e("orion", content);     Map<String, String> xml = decodeXml(content);       return xml;    }   }     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("orion", e.toString());    }    return null;     }      /**       * 生成随机数       * @return       */   private String genNonceStr() {    Random random = new Random();    return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());   }      /**       * 时间戳       * @return       */   private long genTimeStamp() {    return System.currentTimeMillis() / 1000;   }      /**       * 随机数       * @return       */   private String genOutTradNo() {    Random random = new Random();    return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());   }      /**       * 获取设备的ip地址       * @return       */   public String getLocalIpAddress() {    try {     for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {      NetworkInterface intf = en.nextElement();      for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {       InetAddress inetAddress = enumIpAddr.nextElement();       if (!inetAddress.isLoopbackAddress()) {        return inetAddress.getHostAddress().toString();       }      }     }    } catch (SocketException ex) {    }    return null;   }     private String getWifiIp() {    // 获取wifi服务    WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);    // 判断wifi是否开启    if (!wifiManager.isWifiEnabled()) {     wifiManager.setWifiEnabled(true);    }    WifiInfo wifiInfo = wifiManager.getConnectionInfo();    int ipAddress = wifiInfo.getIpAddress();    String ip = intToIp(ipAddress);    return ip;   }      /**       * 转化成Ip地址的格式       * @param i       * @return       */   private String intToIp(int i) {      return (i & 0xFF) + "." + ((i >> 8) & 0xFF) + "." + ((i >> 16) & 0xFF) + "." + (i >> 24 & 0xFF);   }     private String genProductArgs() {    StringBuffer xml = new StringBuffer();    String ip = getWifiIp();    if (ip == "" && ip == "") {     ip = getLocalIpAddress();    }    try {     String nonceStr = genNonceStr();     xml.append("</xml>");     List<NameValuePair> packageParams = new LinkedList<NameValuePair>();     packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID));     packageParams.add(new BasicNameValuePair("body", "APPtest"));     packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));     packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));     packageParams.add(new BasicNameValuePair("notify_url", ConfigUtil.NOTIFY_URL));     packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo()));     packageParams.add(new BasicNameValuePair("spbill_create_ip", ip));     packageParams.add(new BasicNameValuePair("total_fee", "100"));     packageParams.add(new BasicNameValuePair("trade_type", "APP"));     String sign = genPackageSign(packageParams);     packageParams.add(new BasicNameValuePair("sign", sign));     String xmlstring = toXml(packageParams);     return xmlstring;    } catch (Exception e) {     Log.e("TAG", "fail, ex = " + e.getMessage());     return null;    }   }     private void genPayReq() {    req.appId = Constants.APP_ID;    req.partnerId = Constants.MCH_ID;    req.prepayId = resultunifiedorder.get("prepay_id");    req.packageValue = "prepay_id=" + resultunifiedorder.get("prepay_id");    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");    Log.e("orion==genPayReq===============", signParams.toString());     }     private void sendPayReq() {    boolean sendReq = msgApi.sendReq(req);    T.show(this, "微信跳转====="+sendReq+"");   }    }  </code></pre>    <p>里面没有的类,,,,呐:  <a href="/misc/goto?guid=4959725726407377808" rel="nofollow,noindex">http://download.csdn.net/detail/meijuanyou/9571223</a> 自己下载一下拷贝一下。。。</p>    <p>参考资料     <a href="/misc/goto?guid=4959725726407377808" rel="nofollow,noindex">http://blog.csdn.net/meijuanyou/article/details/51863720</a></p>    <p>备忘,希望能给大家带来帮助。。。</p>    <p> </p>    <p>来自:http://www.cnblogs.com/yunfang/p/6078208.html</p>    <p> </p>