“支付宝接入要5分钟,微信支付接入要5小时”
有做过支付经验的人,应该对这句话有些微感触。虽然没那么夸张,但确实微信支付的参考文档没有支付宝人性化。下面记录一下我对微信支付的一些理解。
产品注册、功能签约、SDK集成等操作就不细说,微信开发者社区有详细文档。
步骤一:下订单
此步骤中后台的工作量要更多,Android客户端只需提交商品订单号,主要是接收后台返回的数据,而后台返回的数据中,最基本的一些字段有:
prepayId :预支付ID
nonceStr:随机数
timestamp:时间戳
sign:签名
根据业务逻辑不同,可以定义更多字段,但是这四个字段是必须的。
步骤二:构造支付请求参数
代码如下:
val req = PayReq()
req.appId = AppID.WEIXIN_APP_KEY //(应用签约时生成)
req.partnerId = AppID.WX_PAY_PARTNER_ID //(应用签约时生成)
req.prepayId = orderParams.prepayid // (服务器字段)
req.nonceStr = orderParams.noncestr// (服务器字段)
req.timeStamp = orderParams.timestamp.toString() // (服务器字段)
req.sign = orderParams.sign // (服务器字段)
req.packageValue = "Sign=WXPay" // (固定写法,目前不知道该字段何用,可能是SDK里面需要校验)
req.extData = tradeNo // (可选项,附加数据,用于程序员扩展用,稍后会讲述如何使用)
步骤三:请求支付
val api = WXAPIFactory.createWXAPI(activity, AppID.WEIXIN_APP_KEY) // 获取到微信支付api对象
api.sendReq(req) // 发起支付,参数为步骤二构造的PayReq
步骤四:客户端结果回调
需要在应用的包名后面新建一个package,命名为wxapi,在该包下新建Activity,命名为WXPayEntryActivity。注意:以上两个命名必须固定,否则无法回调微信支付结果,具体代码:
class WXPayEntryActivity : Activity(),IWXAPIEventHandler {
companion object{
const val TAG = "WXPayEntryActivity"
}
private lateinit var mApi : IWXAPI
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mApi = WXAPIFactory.createWXAPI(this, AppID.WEIXIN_APP_KEY) // 获取微信支付api对象
mApi.handleIntent(intent, this) // 固定写法
}
// AndroidManifest中设置启动模式为singleTop,所以需要重写onNewIntent方法
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
mApi.handleIntent(intent, this) // 固定写法
}
/**
* 微信支付结果回调
*/
override fun onResp(p0: BaseResp?) {
TODO: 支付结果在这里回调,通过判断参数BaseResp的errCode,来判断客户端收到的支付结果
}
override fun onReq(p0: BaseReq?) {
}
步骤五:向服务器查询真实的支付结果
注意:客户端收到支付结果,只能作为支付流程结束的标志,真实支付结果必须以服务器结果为准
当我们客户端支付完成后,微信服务器会向我们的后端服务器发送支付结果通知,客户端再去请求这个结果,最后展示给用户。
这里会有一个时间差的问题。因为由于网络原因,当客户端支付流程结束,而微信服务器并没有及时通知到后端服务器,这时候请求结果就不是最终的结果,所以这里建议做一个网络请求的轮询。
最后,再说一下如何获取到步骤二中的 extData :
当支付成功后,会在WXPayEntryActivity中获取到exData,该数据会原样返回。该数据可以用来标记支付类型、购买商品类型、购买商品订单等等,获取方法:
val resp = p0 as PayResp // 将BaseResq强转为PayResq
val tradeNo = resp.extData // 再将PayResq的extData取出
最后嘱咐一句: 类似于这种流程性很强并且有多种耗时操作的功能,推荐使用Kotlin couroutine来做。