Android端接入微信支付的详细流程

Posted 轩辕223

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android端接入微信支付的详细流程相关的知识,希望对你有一定的参考价值。

随着微信支付的越来越普及,现在几乎所有的app都会接入微信的支付API,我当前也遇到了这个问题,查了 微信的网页介绍,但还是走了很多弯路,所以把我的经验分享出来,防止网友再走弯路。

我会参照微信的api介绍,加上微信给的demo一步一步来说。

微信支付接入介绍参见:https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=8_5


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

这一步就是用来验证APP合法性的,做APP的人应该都知道,简单配置一下就可以啦。



2、注册APPID

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

API调用前,需要先向微信注册您的APP,代码如下:

final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);

// 将该app注册到微信

msgApi.registerApp("wxd930ea5d5a258f4f");


还要在Manifest文件中加入你的APPID

<span style="color:#222222;"><activity
            android:name=".PayActivity"
            android:label="@string/app_name"
            android:exported="true"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                </span><span style="color:#ff0000;"><data android:scheme="wxf2f565574a968187"/></span><span style="color:#222222;">
            </intent-filter>
        </activity></span>



代码里体现在

<span style="color:#222222;">package com.weixin.paydemo;

public class PayActivity extends Activity 

	private static final String TAG = "MicroMsg.SDKSample.PayActivity";

	PayReq req;
	</span><span style="color:#ff0000;">final IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null);</span><span style="color:#222222;">
	TextView show;
	Map<String,String> resultunifiedorder;
	StringBuffer sb;
	@Override
	protected void onCreate(Bundle savedInstanceState) 
		super.onCreate(savedInstanceState);
		setContentView(R.layout.pay);
		show =(TextView)findViewById(R.id.editText_prepay_id);
		req = new PayReq();
		sb=new StringBuffer();

		</span><span style="color:#ff0000;">msgApi.registerApp(Constants.APP_ID);</span><span style="color:#222222;">
		//生成prepay_id
		Button payBtn = (Button) findViewById(R.id.unifiedorder_btn);
		payBtn.setOnClickListener(new View.OnClickListener() 
			@Override
			public void onClick(View v) 
				GetPrepayIdTask getPrepayId = new GetPrepayIdTask();
				getPrepayId.execute();
			
		);
		Button appayBtn = (Button) findViewById(R.id.appay_btn);
		appayBtn.setOnClickListener(new View.OnClickListener() 

			@Override
			public void onClick(View v) 
				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();
			
		);
		String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
	
</span>


3. 调用支付

商户服务器生成支付订单,先调用统一下单API(详见第7节)生成预付单,获取到prepay_id后将参数再次签名传输给APP发起支付。以下是调起微信支付的关键代码:

IWXAPI api;

PayReq request = new PayReq();

request.appId = "wxd930ea5d5a258f4f";

request.partnerId = "1900000109";

request.prepayId= "1101000000140415649af9fc314aa427",;

request.packageValue = "Sign=WXPay";

request.nonceStr= "1101000000140429eb40476f8896f4c9";

request.timeStamp= "1398746574";

request.sign= "7FFECB600D7157C5AA49810D2D8F28BC2811827B";

api.sendReq(req);

注意:该sign生成字段名列表见调起支付API

代码Demo

private void sendPayReq() 
		msgApi.registerApp(Constants.APP_ID);
		msgApi.sendReq(req);
	
这个req包含参数,参数生成方法如下

private void genPayReq() 
		<span style="color:#ff0000;">req.appId = Constants.APP_ID;
		req.partnerId = Constants.MCH_ID;
		req.prepayId = resultunifiedorder.get("prepay_id");
		req.packageValue = "Sign=WXPay";
		req.nonceStr = genNonceStr();
		req.timeStamp = String.valueOf(genTimeStamp());</span>

		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");
		show.setText(sb.toString());
		Log.e("orion", 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()).toUpperCase();
		Log.e("orion",appSign);
		return appSign;
	


同时,微信支付之前其实是要先生成订单的,生成订单的代码如下

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");
			show.setText(sb.toString());

			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;
		
	

4,这样应该就能调起微信支付了,还有最重要的一步是,接收微信的返回结果,微信定义了一个入口,你需要在你自己的应用程序中定义这个入口,微信在支付完成后会回调这个入口的方法,代码如下:


AndroidManifest文件中先定义

<activity
            android:name="com.weixin.paydemo.wxapi.WXPayEntryActivity"
            android:exported="true"
            android:launchMode="singleTop"/>
        

        <receiver
            android:name="net.sourceforge.simcpux.AppRegister">
            <intent-filter>
                <action android:name="com.tencent.mm.plugin.openapi.Intent.ACTION_REFRESH_WXAPP" />
            </intent-filter>
        </receiver>

public class WXPayEntryActivity extends Activity<span style="color:#ff0000;"> implements IWXAPIEventHandler</span>
	
	private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity";
	
    private IWXAPI api;
	
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pay_result);
        
    	api = WXAPIFactory.createWXAPI(this, Constants.APP_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) 
	

	<span style="color:#ff0000;">@Override
	public void onResp(BaseResp resp) 
		Log.d(TAG, "onPayFinish, errCode = " + resp.errCode);

		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();
		
	</span>


onResp就是支付完成之后回调的方法。


OK,一套完整的微信支付方法就完成了。

之前有网友问,一个APP里面可以有两个微信的APPID吗,也就是可以付款到两个微信账户吗,从代码来看好像是不可以的,因为首先应用程序会注册到一个APPID上,我认为微信会在sendREq的时候验证APPID和应用程序的对应性,但后来我发现其实可以,因为微信并没有这样做,也就是说在第二步注册APPID,你按照正常流程注册完之后,在第三步发送req的时候,你可以使用任意的APPID,想付款到那个账号就发送哪个APPID,是不是很爽,值得注意的是第三步中的req的APPID需要和prepayid里的APPID对应起来。


这样虽然用起来比较方便,但我总觉得可能不安全,也就是说微信之前做了那么多的验证工作,在关键的一步却没有验证,是不是很可笑。虽然还没有想到问题在哪里,再让我考虑下。


OK,到这里就结束了。有问题可以评论


以上是关于Android端接入微信支付的详细流程的主要内容,如果未能解决你的问题,请参考以下文章

在douphp中加入微信支付教程

Android应用跳转到微信和支付宝扫一扫

微信小程序调用微信支付流程,包括提交订单,发起支付

Android 支付宝以及微信支付快速接入流程

Android中微信支付的流程(从请求统一支付接口到真正调起微信支付)

iOS 微信支付流程详解