Android移动开发-在Android项目里集成调用微信支付开发的实现

如今移动支付比较火,尤其是在中国的市场。移动支付也称为手机支付,就是允许用户使用其移动终端(通常是手机)对所消费的商品或服务进行账务支付的一种服务方式。单位或个人通过移动设备、互联网或者近距离传感直接或间接向银行金融机构发送支付指令产生货币支付与资金转移行为,从而实现移动支付功能。移动支付将终端设备、互联网、应用提供商以及金融机构相融合,为用户提供货币支付、缴费等金融业务。
谈到移动支付,不得不说阿里旗下的蚂蚁金融的支付以及腾讯旗下的微信支付。那么现在在就谈谈如何Android项目里集成调用微信支付开发的实现方式。

首先访问微信开放平台官网,网址为:https://open.weixin.qq.com/ 。然后用自己的邮箱注册并认证为开发者,接着在平台首页依次点击“资源中心”——“Android资源下载”,即可在打开的页面中下载开发工具包jar包与Demo程序示例代码,下载地址为: https://res.wx.qq.com/open/zh_CN/htmledition/res/dev/download/sdk/WeChatSDK_Android221cbf.zip
注意这里的开发包libmmsdk.jar同时集成了微信分享与微信支付的SDK。
使用微信支付需要先申请测试应用,在微信开放平台登录成功后,依次单击链接“管理中心”——“创建移动应用”,填写应用相关信息,提交成功后返回应用列表页面。然后查看应用详情页,在接口信息栏目中发现默认已获得微信分享的权限,而微信支付权限需要另外申请开通。

  • Android项目集成调用微信支付的流程

这里写图片描述

商户系统和微信支付系统主要交互说明:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay
步骤4:商户APP调起微信支付。
步骤5:商户后台接收支付通知。
步骤6:商户后台查询支付结果。

  • 导入开发资源

将下载的jar包放入商户应用工程的libs目录下。

  • 配置权限声明
<uses-permission android:name="android.permission.INTERNET"/>
  • 配置回调activity
        <!-- 微信支付回调页面 -->
        <activity
            android:name="com.fukaimei.wechatpay.WXPayEntryActivity"
            android:exported="true"
            android:launchMode="singleTop">
        </activity>
  • GetPrepayIdTask.java逻辑代码如下:
package com.fukaimei.wechatpay.task;

import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Random;

import org.json.JSONObject;

import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;

//import com.alibaba.fastjson.JSONObject;
import com.fukaimei.wechatpay.bean.GetPrepayIdResult;
import com.fukaimei.wechatpay.bean.LocalRetCode;
import com.fukaimei.wechatpay.bean.WechatConstants;
import com.fukaimei.wechatpay.util.MD5;
import com.fukaimei.wechatpay.util.WechatUtil;
import com.tencent.mm.sdk.modelpay.PayReq;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.WXAPIFactory;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

public class GetPrepayIdTask extends AsyncTask<String, Void, GetPrepayIdResult> {
	private static final String TAG = "GetPrepayIdTask";
	private Context context;
	private ProgressDialog dialog;
	private String accessToken;
	private String[] goods_info;

	public GetPrepayIdTask(Context context, String accessToken) {
		this.context = context;
		this.accessToken = accessToken;
	}

	@Override
	protected void onPreExecute() {
		dialog = ProgressDialog.show(context, "提示", "正在获取预支付订单...");
	}

	@Override
	protected GetPrepayIdResult doInBackground(String... params) {
		goods_info = new String[] { params[0], params[1], params[2] };
		String url = String.format("https://api.weixin.qq.com/pay/genprepay?access_token=%s", accessToken);
		String entity = genProductArgs();
		Log.d(TAG, "doInBackground, url = " + url + ", entity = " + entity);

		GetPrepayIdResult result = new GetPrepayIdResult();
		byte[] buf = WechatUtil.httpPost(url, entity);
		if (buf == null || buf.length == 0) {
			result.localRetCode = LocalRetCode.ERR_HTTP;
			return result;
		}

		String content = new String(buf);
		Log.d(TAG, "doInBackground, response content = " + content);
		result.parseFrom(content);
		return result;
	}

	@Override
	protected void onPostExecute(GetPrepayIdResult result) {
		if (dialog != null) {
			dialog.dismiss();
		}
		if (result.localRetCode == LocalRetCode.ERR_OK) {
			Toast.makeText(context, "获取prepayid成功", Toast.LENGTH_LONG).show();
			payWithWechat(result);
		} else {
			Toast.makeText(context, "获取prepayid失败,原因" + result.localRetCode.name(), Toast.LENGTH_LONG).show();
		}
	}

	private IWXAPI mWeixinApi;

	// // 如果获取token和预付标识在服务器实现,只留下支付动作在客户端实现,那么下面要异步调用
	// private void payWithWechat() {
	// final String payInfo = "";
	//
	// Runnable payRunnable = new Runnable() {
	// @Override
	// public void run() {
	// sendWXPayReq(payInfo);
	// }
	// };
	//
	// Thread payThread = new Thread(payRunnable);
	// payThread.start();
	// }

	private String genPackage(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(WechatConstants.PARTNER_KEY); // 注意:不能hardcode在客户端,建议genPackage这个过程都由服务器端完成

		// 进行md5摘要前,params内容为原始内容,未经过url encode处理
		String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(Locale.getDefault());
		return URLEncodedUtils.format(params, "utf-8") + "&sign=" + packageSign;
	}

	private String genNonceStr() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}

	private long genTimeStamp() {
		return System.currentTimeMillis() / 1000;
	}

	private String getTraceId() {
		return "crestxu_" + genTimeStamp();
	}

	private String genOutTradNo() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}

	private long timeStamp;
	private String nonceStr, packageValue;

	private String genSign(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();
		int i = 0;
		for (; i < params.size() - 1; i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append(params.get(i).getName());
		sb.append('=');
		sb.append(params.get(i).getValue());

		String sha1 = WechatUtil.sha1(sb.toString());
		Log.d(TAG, "genSign, sha1 = " + sha1);
		return sha1;
	}

	private String genProductArgs() {
		JSONObject json = new JSONObject();

		try {
			json.put("appid", WechatConstants.APP_ID);
			String traceId = getTraceId(); // traceId
											// 由开发者自定义,可用于订单的查询与跟踪,建议根据支付用户信息生成此id
			json.put("traceid", traceId);
			nonceStr = genNonceStr();
			json.put("noncestr", nonceStr);

			List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
			packageParams.add(new BasicNameValuePair("bank_type", "WX"));
			packageParams.add(new BasicNameValuePair("body", goods_info[0]));
			packageParams.add(new BasicNameValuePair("description", goods_info[1]));
			packageParams.add(new BasicNameValuePair("fee_type", "1"));
			packageParams.add(new BasicNameValuePair("input_charset", "UTF-8"));
			packageParams.add(new BasicNameValuePair("notify_url", "http://weixin.qq.com"));
			packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo()));
			packageParams.add(new BasicNameValuePair("partner", WechatConstants.PARTNER_ID));
			packageParams.add(new BasicNameValuePair("spbill_create_ip", "196.168.1.1"));
			packageParams.add(new BasicNameValuePair("total_fee", ""
					+ (int) (Float.parseFloat(goods_info[2]) * 100)));
			packageValue = genPackage(packageParams);

			json.put("package", packageValue);
			timeStamp = genTimeStamp();
			json.put("timestamp", timeStamp);

			List<NameValuePair> signParams = new LinkedList<NameValuePair>();
			signParams.add(new BasicNameValuePair("appid", WechatConstants.APP_ID));
			signParams.add(new BasicNameValuePair("appkey", WechatConstants.APP_KEY));
			signParams.add(new BasicNameValuePair("noncestr", nonceStr));
			signParams.add(new BasicNameValuePair("package", packageValue));
			signParams.add(new BasicNameValuePair("timestamp", String.valueOf(timeStamp)));
			signParams.add(new BasicNameValuePair("traceid", traceId));
			json.put("app_signature", genSign(signParams));

			json.put("sign_method", "sha1");
		} catch (Exception e) {
			Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage());
			return null;
		}

		return json.toString();
	}

	private void payWithWechat(GetPrepayIdResult result) {
		PayReq req = new PayReq();
		req.appId = WechatConstants.APP_ID;
		req.partnerId = WechatConstants.PARTNER_ID;
		req.prepayId = result.prepayId;
		req.nonceStr = nonceStr;
		req.timeStamp = String.valueOf(timeStamp);
		req.packageValue = "Sign=" + packageValue;

		List<NameValuePair> signParams = new LinkedList<NameValuePair>();
		signParams.add(new BasicNameValuePair("appid", req.appId));
		signParams.add(new BasicNameValuePair("appkey", WechatConstants.APP_KEY));
		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 = genSign(signParams);

		Log.d(TAG, "WXAPIFactory.createWXAPI");
		mWeixinApi = WXAPIFactory.createWXAPI(context, WechatConstants.APP_ID);
		// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
		Log.d(TAG, "mWeixinApi.sendReq");
		mWeixinApi.sendReq(req);
	}
}
  • GetAccessTokenTask.java逻辑代码如下:
package com.fukaimei.wechatpay.task;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

import com.fukaimei.wechatpay.bean.GetAccessTokenResult;
import com.fukaimei.wechatpay.bean.LocalRetCode;
import com.fukaimei.wechatpay.bean.WechatConstants;
import com.fukaimei.wechatpay.util.WechatUtil;

public class GetAccessTokenTask extends AsyncTask<String, Void, GetAccessTokenResult> {
    private static final String TAG = "GetAccessTokenTask";
    private Context context;
    private ProgressDialog dialog;
    private String[] goods_info;

    public GetAccessTokenTask(Context context) {
        this.context = context;
    }

    @Override
    protected void onPreExecute() {
        dialog = ProgressDialog.show(context, "提示", "正在获取access token...");
    }

    @Override
    protected GetAccessTokenResult doInBackground(String... params) {
        goods_info = new String[]{params[0], params[1], params[2]};
        GetAccessTokenResult result = new GetAccessTokenResult();
        String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
                WechatConstants.APP_ID, WechatConstants.APP_SECRET);
        Log.d(TAG, "get access token, url = " + url);

        byte[] buf = WechatUtil.httpGet(url);
        if (buf == null || buf.length == 0) {
            result.localRetCode = LocalRetCode.ERR_HTTP;
            return result;
        }

        String content = new String(buf);
        result.parseFrom(content);
        return result;
    }

    @Override
    protected void onPostExecute(GetAccessTokenResult result) {
        if (dialog != null) {
            dialog.dismiss();
        }

        Log.d(TAG, "RetCode=" + result.localRetCode + ", errCode=" + result.errCode + ", errMsg=" + result.errMsg);
        if (result.localRetCode == LocalRetCode.ERR_OK) {
            Toast.makeText(context, "获取access token成功, accessToken = " + result.accessToken, Toast.LENGTH_LONG).show();
            GetPrepayIdTask getPrepayId = new GetPrepayIdTask(context, result.accessToken);
            getPrepayId.execute(goods_info[0], goods_info[1], goods_info[2]);
        } else {
            Toast.makeText(context, "获取access token失败,原因: " + result.localRetCode.name(), Toast.LENGTH_LONG).show();
        }
    }
}
  • 在WechatConstants里配置相关与支付宝签约的商家密钥和账号等,WechatConstants.java逻辑代码如下:
package com.fukaimei.wechatpay.bean;

public class WechatConstants {
    // APP_ID 替换为你的应用从官方网站申请到的合法appId
    public static final String APP_ID = "";
    public static final String APP_SECRET = "";
    // wxd930ea5d5a258f4f 对应的支付密钥
    public static final String APP_KEY = "";
    
    /** 商家向财付通申请的商家id */
    public static final String PARTNER_ID = "";
    public static final String PARTNER_KEY = "";
    
    public static class ShowMsgActivity {
		public static final String STitle = "showmsg_title";
		public static final String SMessage = "showmsg_message";
		public static final String BAThumbData = "showmsg_thumb_data";
	}
}

  • layout/activity_wxpay.xml界面布局代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp" >

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:src="@drawable/laoganma"
        android:scaleType="fitCenter" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="商品名称:"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <EditText
            android:id="@+id/et_goods_title"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:padding="5dp"
            android:background="@drawable/editext_selector"
            android:text="小米MIX 2"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </LinearLayout>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="商品描述:"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <EditText
            android:id="@+id/et_goods_desc"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:padding="5dp"
            android:background="@drawable/editext_selector"
            android:text="全面屏2.0,骁龙835处理器,全陶瓷机身。"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </LinearLayout>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="商品价格:"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <EditText
            android:id="@+id/et_goods_price"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:padding="5dp"
            android:background="@drawable/editext_selector"
            android:enabled="false"
            android:inputType="numberDecimal"
            android:text="0.01"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="元"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </LinearLayout>
    
    <Button
        android:id="@+id/btn_wechat"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="微信支付"
        android:textColor="@color/black"
        android:textSize="17sp" />

</LinearLayout>
  • WxpayActivity.java逻辑代码如下:
package com.fukaimei.wechatpay;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;

import com.fukaimei.wechatpay.task.GetAccessTokenTask;

public class WxpayActivity extends AppCompatActivity implements OnClickListener {
	private static final String TAG = "WxpayActivity";
	private EditText et_goods_title;
	private EditText et_goods_desc;
	private EditText et_goods_price;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_wxpay);
		et_goods_title = (EditText) findViewById(R.id.et_goods_title);
		et_goods_desc = (EditText) findViewById(R.id.et_goods_desc);
		et_goods_price = (EditText) findViewById(R.id.et_goods_price);
		findViewById(R.id.btn_wechat).setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_wechat) {
			String title = et_goods_title.getText().toString();
			String desc = et_goods_desc.getText().toString();
			String price = et_goods_price.getText().toString();
			new GetAccessTokenTask(this).execute(title, desc, price);
		}
	}
}
  • layout/activity_wxpay_result.xml界面布局代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp" >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="5dp"
        android:text="这是微信支付结果页面"
        android:textColor="@color/black"
        android:textSize="17sp" />

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:textColor="@color/black"
        android:textSize="17sp" />

</LinearLayout>
  • WXPayEntryActivity.java逻辑代码如下:
package com.fukaimei.wechatpay;

import com.fukaimei.wechatpay.bean.WechatConstants;
import com.tencent.mm.sdk.constants.ConstantsAPI;
import com.tencent.mm.sdk.modelbase.BaseReq;
import com.tencent.mm.sdk.modelbase.BaseResp;
import com.tencent.mm.sdk.modelbase.BaseResp.ErrCode;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.sdk.openapi.WXAPIFactory;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

public class WXPayEntryActivity extends AppCompatActivity implements IWXAPIEventHandler {
	private static final String TAG = "WXPayEntryActivity";
	private IWXAPI api;
	private TextView tv_result;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_wxpay_result);
		tv_result = (TextView) findViewById(R.id.tv_result);
		api = WXAPIFactory.createWXAPI(this, WechatConstants.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) {
	}

	@Override
	public void onResp(BaseResp resp) {
		Log.d(TAG, "onResp, errCode = " + resp.errCode);
		String result = "";
		if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
			switch (resp.errCode) {
			case ErrCode.ERR_OK:
				result = "微信支付成功";
				break;
			case ErrCode.ERR_COMM:
				result = "微信支付失败:" + resp.errCode + "," + resp.errStr;
				break;
			case ErrCode.ERR_USER_CANCEL:
				result = "微信支付取消:" + resp.errCode + "," + resp.errStr;
				break;
			default:
				result = "微信支付未知异常:" + resp.errCode + "," + resp.errStr;
				break;
			}
		}
		Toast.makeText(this, result, Toast.LENGTH_LONG).show();
		tv_result.setText(result);
	}
}

———————— The end ————————

如果您觉得这篇博客写的比较好的话,赞赏一杯咖啡吧~~
在这里插入图片描述


Demo程序源码下载地址一(GitHub)
Demo程序源码下载地址二(Gitee)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值