安卓微信支付开发基本流程-实际开发篇

时间:2021-07-07 17:46:19

之前写过一篇微信支付的官方demo篇,点击查看详情。现在支付模块已经完成了,所以应该把正式项目中的问题和源码和记录下,以备以后参考。


安卓端的app支付流程官方讲的比较详细了,所以开发的时候一定要仔细阅读,按照步骤开发,碰到问题基本百度都能搞定。点击这里查看官方app开发文档


Android开发要点说明

1、后台设置

商户在微信开放平台申请开发应用后,微信开放平台会生成APP的唯一标识APPID。由于需要保证支付安全,需要在开放平台绑定商户应用包名和应用签名,设置好后才能正常发起支付。设置界面在【开放平台】中的栏目【管理中心 / 修改应用 / 修改开发信息】里面,如图8.8红框内所示。

安卓微信支付开发基本流程-实际开发篇

图8.8

应用包名:是在APP项目配置文件AndroidManifest.xml中声明的package值,例如DEMO中的package="net.sourceforge.simcpux"。(这里强调一下,应用包名是用来支付结果回调的,所以要配置清单文件中的包名,否则支付后不会调起回调!)

应用签名:根据项目的应用包名和编译使用的keystore,可由签名工具生成一个32位的md5串,在调试的手机上安装签名工具后,运行可生成应用签名串,如图8.9所示,绿色串即应用签名。签名工具下载地址https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk(应用签名是为了保证传输的安全性)

安卓微信支付开发基本流程-实际开发篇

图8.9

2、注册APPID

商户APP工程中引入微信JAR包,调用API前,需要先向微信注册您的APPID,代码如下:

 
 

private IWXAPI api= WXAPIFactory.createWXAPI(this, null);

 将该app注册到本地微信

api.registerApp("这里添你申请的appid");	

3、调起支付

商户服务器生成支付订单,先调用统一下单API(点这里,这个接口由后台人员调用)生成预付单,获取到prepay_id后封装数据(点击查看需要的参数列表)调其本地微信APP发起支付。app端请求服务器获取预支付订单号,其他信息可以在app端生成。(比如签名key可以保存在app端,但是不太安全)

以下是调起微信支付的关键代码:

<span style="white-space:pre">	</span>/**
	 * 本地根据key生成签名sign
	*/
	String randomString = getRandomStringByLength(12);//生成唯一字随机字符串
	String time = System.currentTimeMillis()+"";//生成时间戳
	String pre_id = json.getString("prepay_id");//从返回数据获取订单号
	SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
	parameters.put("appid", "你的appid");
	parameters.put("partnerid", "你的商户id");
	parameters.put("prepayid", pre_id);
	parameters.put("package", "Sign=WXPay");
	parameters.put("noncestr", randomString);
	parameters.put("timestamp",time );
	String signed = createSign("UTF_8", parameters);
	/**
	 * 封装好请求参数
	 */
						
	PayReq req = new PayReq();
	req.appId = "你的appid";
	req.partnerId = "你的商户id";
	req.prepayId = pre_id;
	req.nonceStr = randomString;
	req.timeStamp = time;
	req.packageValue = "Sign=WXPay";
	req.sign =signed;
	LogUtil.d("pre_id",pre_id.toString());

	// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
	api.sendReq(req);
请求后台获取预支付订单号以后,封装数据加签名,然后调起微信支付。  

生成随机字符串的方法:(直接用)

/**
	 * 生成随机字符串
	 * @param length
	 * @return
	 */
	public static String getRandomStringByLength(int length) {
		String base = "abcdefghijklmnopqrstuvwxyz0123456789";
		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();
	}
签名方法:(直接用)

private static String Key = "输入你设置的key";//<span style="color: rgb(34, 34, 34); font-family: 'Helvetica Neue', 'Hiragino Sans GB', 'Microsoft YaHei', 黑体, Arial, sans-serif; font-size: 14px; line-height: 22.4px;">key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置</span>
	/**
	 * 微信支付签名算法sign 
	 * @param characterEncoding
	 * @param parameters
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();//1.所有参与传参的参数按照accsii排序(升序)  
		Iterator it = es.iterator();
		while(it.hasNext()) {//2.生成字符串
			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=" + Key);//3.把key拼接进去
		String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();//md5加密
		return sign;
	}
附上官方的签名算法解释: 点这里


4、支付结果回调

参照微信SDK Sample,在xxx.xxx.xxx.wxapi包路径中实现WXPayEntryActivity类(注意这里的xxx路径要和清单文件中的报名路径一致。)

比如我的路径是这样的

安卓微信支付开发基本流程-实际开发篇

在清单文件中注册的包名必须是

安卓微信支付开发基本流程-实际开发篇

如果这2个路径不一致,无法调起回调方法。

在WXPayEntryActivity类中实现onResp函数,支付完成后,微信APP会返回到商户APP并回调onResp函数,开发者需要在该函数中接收通知,判断返回错误码,如果支付成功则去后台查询支付结果再展示用户实际支付结果。注意一定不能以客户端返回作为用户支付的结果,应以服务器端的接收的支付通知或查询API返回的结果为准。代码示例如下:(代码可以直接用)

package com.dudu.helper3.wxapi;


import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.dudu.helper3.BaseActivity;
import com.dudu.helper3.R;
import com.dudu.helper3.Utils.LogUtil;
import com.tencent.mm.sdk.modelbase.BaseReq;
import com.tencent.mm.sdk.modelbase.BaseResp;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.sdk.openapi.WXAPIFactory;
public class WXPayEntryActivity extends BaseActivity implements IWXAPIEventHandler {


	private IWXAPI api;
	private TextView tv_res;


	@Override public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		LogUtil.d("jieguo","ol");

       setContentView(R.layout.activity_pay_result);
		tv_res = (TextView) findViewById(R.id.tv_res);
		Button btn_back = (Button) findViewById(R.id.btn_back);
		btn_back.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				finish();
			}
		});
		initHeadView("支付结果",true,false,0);
		api = WXAPIFactory.createWXAPI(this, "wxa43dd59c979e6ab7");
		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) {
		int errCode = resp.errCode;
		LogUtil.d("resp",resp.errCode+"");

		if (errCode == 0) {
			// 0成功 展示成功页面
			tv_res.setText("支付成功");
		}
		else if (errCode == -1) {
			//-1 错误 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。 
			tv_res.setText("支付失败:"+resp.errStr);
			finish();
		}
		else if (errCode == -2) {
			//-2 用户取消 无需处理。发生场景:用户不支付了,点击取消,返回APP。  
			finish();
		}
	}


}  

PS:补充一个问题,上线以后反应客户不能正常调起支付,原因是应用签名当时提交的debug版本的,而正式版的keystore是不一样的,所以不能正常调起
安卓微信支付开发基本流程-实际开发篇
在网页那里重新设置下签名就行了