android集成微信支付,脱坑篇

本屌也是做开发多年,遇到微信支付也是用起来相当棘手,今天就要写一篇脱坑攻略。

微信支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1#

集成步骤:

1、申请appkID。

2、下载sdk,放到项目lib文件夹下。

3、添加权限:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

4、添加微信回调activity:

<activity
            android:name=".wxapi.WXPayEntryActivity"
            android:exported="true" />

并在项目根目录下创建包:wxapi,在wxapi包内创建WXPayEntryActivity。如下:


注意:微信官方对于此类并没有做过多的介绍,废话少说直接上代码:

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {

    //app_id 替换为你的应用从官方网站申请到的合法appid
    private static final String WXAPP_ID = "xxxxxxxxxxxxx";

    private IWXAPI api;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);//此处布局并没有什么用   并不显示,设置一个空页面就好
        api = WXAPIFactory.createWXAPI(this,WXAPP_ID);
        api.handleIntent(getIntent(), this);
    }

    @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) {
        //Log.d(TAG, "onPayFinish, errCode = " + resp.errCode);
        //resp.errCode  0:成功  -1:失败  -2:取消
        if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
      /* AlertDialog.Builder builder = new AlertDialog.Builder(this);
         builder.setTitle(R.string.app_tip);
         builder.setMessage(getString(R.string.pay_result_callback_msg, resp.errStr +";code=" + String.valueOf(resp.errCode)));
         builder.show();
         */
            if (0== resp.errCode){
                //                支付成功     为方便页面刷新等    此处我用的 
                ReceiverUtils.paysuc(this);
            }else if (-1== resp.errCode){
                //                支付失败     为方便页面刷新等    此处我用的广播

                ReceiverUtils.payfaile(this);
            }else if (-2== resp.errCode){
                //                取消支付    为方便页面刷新等    此处我用的广播

                ReceiverUtils.payfaile(this);
            }
//            UIUtils.showToastSafe("支付结果:"+resp.errCode);
            finish();
        }
    }
}
5、为了方便以后使用,我把支付相关的都放在基类里面,其实放在工具类中也挺好,因为activity中逻辑很多,很可能会有微信银联等其他支付集成,所以放在基类中提供一个方法就行,代码看起来更好看一些,还不影响activity中的逻辑。(注意:微信支付需要二次加密才能成功成功支付,不然会一直失败,在这个地方我就被坑了大半天,这两次加密全都放在后台加密最好,前端请求到支付的 实体PayReq后直接调用支付就好了,如果这第二次加密是放在前端做的话,就需要下面的方法了)废话少说直接上代码,代码中我会做解释:

public class JKPayActivity extends JKActivity {

   private static final String WXORIVATEKEY = "asdasdasdjasdkjahsdjkha";//微信支付设置的key
   //app_id 替换为你的应用从官方网站申请到的合法appid
   private static final String WXAPP_ID = "wxaasdasdq12d1d0";
   //IWXAPI是第三方app和微信通信的openapi接口
   private IWXAPI api;

   /**
    * 微信支付的初始化,在页面oncreat方法中一定要调用
    */
   public void initWx() {
      //工厂模式获取实例
      api = WXAPIFactory.createWXAPI(this, WXAPP_ID, true);
   }

   /**
    * 进行微信支付,此方法直接调起微信支付   此支付官方要求需要放在子线程调用
    *
    * @param bean 从后台获取的经过第一次加密的实体,包含以下属性(如果后台经过两次加密,则此处不需要进行加密,直接发起支付)。
    *             String appId;
    *             String nonceStr;
    *             String partnerid;
    *             String prepay_id;
    *             String sign;
    *             String timeStamp;
    */
   public void gotoWxPay(final WXPayBean bean) {
      new Thread(new Runnable() {
         @Override
         public void run() {
            PayReq req = new PayReq();
            StringBuffer sb = new StringBuffer();
            genPayReq(req, bean, sb);//参数   可以看成微信支付实体的赋值    把后台生成的订单信息赋值给PayReq
            //将应用的appid注册到微信
            api.registerApp(WXAPP_ID);
            api.sendReq(req);
         }
      }).start();
   }

   /**
    * 将后台数据赋值给微信支付的实体中
    *
    * @param req  微信支付的实体
    * @param bean 后台经过一次加密的订单信息
    * @param sb   没什么用处,只为打印log方便查看
    */
   private void genPayReq(PayReq req, WXPayBean bean, StringBuffer sb) {
      if (bean == null || bean.getData() == null) {
         UIUtils.showToastSafe("支付失败");
         return;
      }
      WXPayBean.DataBean.ParamsBean params = bean.getData().getParams();
      req.appId = params.getAppId();
      req.partnerId = params.getPartnerid();
      req.prepayId = params.getPrepay_id();
//    req.packageValue = "prepay_id="+params.getPrepay_id();  这个值有些网上这样设置,我也试过,并没有什么卵用
      req.packageValue = "Sign=WXPay";   //就这样设置
      req.nonceStr = params.getNonceStr();
      req.timeStamp = params.getTimeStamp();
//    req.sign = ......    如果后台进行了二次加密   就不需要下面的操作,直接将req   return
      //以下为二次加密,就只为了req.sign这个属性赋值   MyNameValuePair就是自定义的键值对   稍后会贴出代码
      List<MyNameValuePair> signParams = new LinkedList<>();  //将订单信息放到键值对中进行第二次加密
      signParams.add(new MyNameValuePair("appid", req.appId));
      signParams.add(new MyNameValuePair("noncestr", req.nonceStr));
      signParams.add(new MyNameValuePair("package", "Sign=WXPay"));
      signParams.add(new MyNameValuePair("partnerid", req.partnerId));
      signParams.add(new MyNameValuePair("prepayid", req.prepayId));
      signParams.add(new MyNameValuePair("timestamp", req.timeStamp));
      req.sign = genAppSign(signParams);//二次加密
      sb.append("sign\n" + req.sign + "\n\n");
      Log.e("orion", signParams.toString());

   }

   /**
    * 二次加密
    *
    * @param params
    * @return
    */
   private String genAppSign(List<MyNameValuePair> 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(WXORIVATEKEY);
      return stringToMD5(sb.toString()).toUpperCase();
   }

   /**
    * 将字符串转成MD5值
    *
    * @param string 需要转换的字符串
    * @return 字符串的MD5值
    */
   public static String stringToMD5(String string) {
      byte[] hash;

      try {
         hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
      } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
         return null;
      } catch (UnsupportedEncodingException e) {
         e.printStackTrace();
         return null;
      }

      StringBuilder hex = new StringBuilder(hash.length * 2);
      for (byte b : hash) {
         if ((b & 0xFF) < 0x10)
            hex.append("0");
         hex.append(Integer.toHexString(b & 0xFF));
      }
      return hex.toString();
   }

}

public class MyNameValuePair  {
    private String name;
    private String value;

    public MyNameValuePair(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

此处存在一个坑,稍后说。

微信就这样集成完毕了,在activity的oncreat中调用initWx(),然后调起微信支付的时候直接调用gotoWxPay()就好了。

下面介绍集成微信支付失败的坑:
1、签名不对:平常测试一些第三方都是需要签名的,因为一般运行项目都会使用工具默认的debug签名,所以会导致第三方的功能失败,此时就需要下面的操作了,运行时直接签名,此时手机上的app就是签过名的,同时还可以看log日志,再也不需要打包发送到手机上看效果了

(1)我用的是android studio  ,所以签名直接在gradle中配置就行(在android{} 中添加如下代码,注意上下顺序不可调换  其中的信息替换成自己的就行   :keyalias 、keypassword、storefile、storepassword):

//配置keystore签名
    signingConfigs {
        release {
            keyAlias 'app'
            keyPassword '123456789'
            storeFile file('C:/Users/iningke/Desktop/xxx/key/xxx.jks')
            storePassword '123456789'
        }
    }
    buildTypes {
//        release {
//            minifyEnabled false
//            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//        }
        release {
            signingConfig signingConfigs.release
        }
        debug {
            signingConfig signingConfigs.release
        }
    }

(2)也可以直接打开设置(右键app,选择)


下图设置好也是同样的效果



2,支付失败:参数不对,主要体现在二次加密后的sign值不对,如果调起支付的时候签名没问题,那就要看看这个地方了,不管是后台还是前端,进行第二次签名的时候都要放到  微信公众平台支付接口调试工具  中,地址为:https://pay.weixin.qq.com/wiki/tools/signverify/    


只要你二次加密得到的值跟微信调试工具的值一样,这才说明你的签名是对的,有些人很难想到是加密算法导致支付失败的。

入坑需谨慎,别人的拿来用还是要自己祥读的,微信的开发文档我就不详细介绍了,支付可以按照上面的集成,但是真正出问题还是要详细阅读官方文档的。


请大家多多关注,一起成长

http://blog.csdn.net/qq_21709449


总结的不周之处请谅解,谢谢



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值