公司最近需要接微信支付,由于微信支付相关文档不全,在集成过程中,遇到了很多坑,这里记录一下,希望能帮到需要帮助的人。
好了,开始吧!!
1.申请微信开发者账号
微信开放平台网址:https://open.weixin.qq.com/
开发者对申请开发者账号已经不能再熟悉了吧,而且这步没什么坑,跳过!!
2.创建移动应用
(1)
(2)
注意图标的尺寸:
- 小图标28*28
- 大图标108*108
(3)
app的签名值,在微信文档说是用下载签名工具(apk),这个工具使用相当麻烦!!要先安装应用,然后才能获取,获取之后,还不能拷贝,要一个一个输入到电脑中!!
后来发现,其实app的签名就是keystore的MD5小写值,再去掉冒号!
一条命令便可获取keystore的MD5呢:keytool -v -list -keystore keystore的路径
如图:
MD5值:77:DA:83:87:F8:95:AE:A5:23:08:B8:96:90:62:23:12
转为小写:77:da:83:87:f8:95:ae:a5:23:08:b8:96:90:62:23:12
去掉冒号:77da8387f895aea52308b89690622312
那么app的签名为77da8387f895aea52308b89690622312
提交审核之后,一般需要1-5个工作日,只能等!!这里我想吐槽一下,微信的审核实在是龟速呀!!
3.申请开通微信支付
应用审核通过后,要申请开通支付功能后,才能使用。
之后就是填各种企业资料,很简单的,这里就不方便透露了!!
需要注意的是,微信支付是需要手续费的,线上的一般为0.6%;当然,不同类型,手续费是不一样的,这个得根据工具经营的类型有关!
填完这种资料后,又是漫长的等待审核 ……
4.Android接入微信支付(重点)
对我们Android来说,这是重点,因为这里的坑很多!!
先来看一张官方的微信支付业务流程:
其实我们要做的有以下3步:
请求服务端生成支付订单
Android请求生成订单,一般来说,服务器应该返回调起微信支付的所有参数;
由于很多参数可以在Android端生成,所以服务端需要返回预支付id(prepayid)和签名key就行了。(其实这样是不安全的,无奈,做后台的人不返回,只能我来生成咯)
整合参数,通过调用微信SDK调起微信支付
由于服务端没有给我返回这些参数,所以我得自己整合。
我们先来看看所需要参数:
appid:微信开放平台创建应用的AppID
noncestr:随机数(不能超过32位)
package:Sign=WXPay(固定值)
partnerid:商户ID
prepayid:预支付ID(服务器返回)
timestamp:10位时间戳(单位是秒)
sign:签名这里着重说一下sign签名,这个东西我试了一个下午!!大坑呀!!
根据官方文档,生成sign的算法是将所有字段,加密方式和服务端的一样,用一样的key就行了!!
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
请注意一句话:按照参数名ASCII字典序排序,我就是没有注意到这句话,调了一个下午!!
这个意思是,我们拼接key和value时,要根据key的ASCII字典序的顺序去拼接!!
不然调不起微信支付,返回来-1!!
处理微信支付的结果
这一步是处理微信支付的结果,需要把官方demo的net.sourceforge.simcpux.wxapi包下的WXPayEntryActivity.java文件拷贝到我们应用的包名.wxapi
比如我应用的包名是com.example.johan,那么把WXPayEntryActivity.java文件拷贝到com.example.johan.wxapi的包下
这个一定要严格遵守,不然接收不到微信支付结果!!
最后,给出部分代码:
// 请求服务器生成订单
core.requestOrder(new Callback() {
public void onSuccess(Result result) {
String prepayId= result.prepayId;
String key = result.key;
// 整合参数
// 时间戳
String time = String.valueOf(System.currentTimeMillis());
if (time.length() > 10) {
time = time.substring(0, 10);
}
// 随机数
String random = RandomUtil.generateString(32).toUpperCase();
StringBuilder signBuilder = new StringBuilder();
// 顺序一定不能乱,乱了调不起微信支付 xxx填写自己的东西
signBuilder.append("appid=").append("xxxxxxxxxxxxxx").append("&")
.append("noncestr=").append(random).append("&")
.append("package=").append("Sign=WXPay").append("&")
.append("partnerid=").append("xxxxxxxxxxxx").append("&")
.append("prepayid=").append(prepayId).append("&")
.append("timestamp=").append(time).append("&")
.append("key=").append(key);
// 签名加密
String sign = MD5.encode(signBuilder.toString()).toUpperCase();
// 调起微信支付
PayReq request = new PayReq();
request.appId = "xxxxxxxxxxxxxx";
request.partnerId = "xxxxxxxxxxxx";
request.prepayId = prepayId;
request.packageValue = "Sign=WXPay";
request.nonceStr = random;
request.timeStamp = time;
request.sign = sign;
wxApi.sendReq(request);
}
})
处理微信支付结果:
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler{
public static final String ACTION_WXPAY_RESULT = "wxpay_result";
public static final String KEY_OF_CODE = "code";
public static final String KEY_OF_MSG = "message";
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ui_wx_pay_entry);
api = WXAPIFactory.createWXAPI(this, "xxxxxxxxxx");
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) {
Intent intent = new Intent(ACTION_WXPAY_RESULT);
intent.putExtra(KEY_OF_CODE, resp.errCode);
intent.putExtra(KEY_OF_MSG, resp.errStr);
sendBroadcast(intent);
finish();
}
}
我这里通过广播方式将微信支付的结果广播出去,让发起微信支付请求的类自己处理!!
以上是我接入微信支付所遇到的一些事,希望能帮到有需要的人!!