Android三方支付对接方案
场景
用户在APP中下单,跳转到支付宝/微信中完成支付,支付完后跳回到APP内,展示支付结果。
支付宝对接
接入前准备
步骤
-
添加支付宝sdk依赖。
api com.alipay.sdk:alipaysdk-android:+@aar
-
拿到后端返回的换起支付宝的支付参数,进行支付。
private void aliPay(String info) { // Toast.makeText(mContext, "正在支付...", Toast.LENGTH_LONG).show(); final String orderInfo = info; // 订单信息 Runnable payRunnable = new Runnable() { @Override public void run() { PayTask alipay = new PayTask(mContext); Map<String, String> result = alipay.payV2(orderInfo, true); Message msg = new Message(); msg.what = SDK_ALIPAY_FLAG; msg.obj = result; aliPayHandler.sendMessage(msg); } }; Thread payThread = new Thread(payRunnable); payThread.start(); }
- orderInfo:App 支付请求参数字符串,主要包含商家的订单信息,key=value 形式,以 & 连接。
- isShowPayLoading:为true,将在唤起pay接口时增加loading作为过渡。
- 创建handle接收支付返回的结果。
private Handler aliPayHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == SDK_ALIPAY_FLAG) {
Map<String, String> payResult = ((Map<String, String>) msg.obj);
/**
对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultStatus = payResult.get("resultStatus");
// 判断resultStatus 为9000则代表支付成功
if (TextUtils.equals(resultStatus, "9000")) {
// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
mListener.payResult(1);
} else {
mListener.payResult(-1);
// 该笔订单真实的支付结果,需要依赖服务端的异步通知。
// ToastUtil.INSTANCE.toast("支付失败");
}
}
}
};
- 拿到支付回调后,轮询后端接口,拿到最终的支付结果。
注意事项
Android10新增了包可见权限,访问外部apk,需要在mainfest中添加对应apk的包名。
<queries>
<!-- 微信支付客户端-->
<package android:name="com.tencent.mm" />
<!-- 支付宝支付客户端-->
<package android:name="com.eg.android.AlipayGphone" />
</queries>
微信对接
接入前准备
https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_5_1.shtml
步骤
-
添加微信sdk依赖。
implementation com.tencent.mm.opensdk:wechat-sdk-android-without-mta:5.5.8
-
在app中进行微信的注册。
private var wxApi: IWXAPI? = null fun getWxApi(): IWXAPI? { if (wxApi == null) { // 注册微信 wxApi = WXAPIFactory.createWXAPI(ContextHolder.get(), ConstantConfig.WX_APPID) wxApi?.registerApp(ConstantConfig.WX_APPID) } return wxApi }
-
拿到后端返回的换起微信支付的参数,我们可以转换为微信需要的对象。
req.appId = ConstantConfig.WX_APPID req.partnerId = prePayData.partnerid //这些数据都是接口返回的 req.timeStamp = prePayData.timestamp req.nonceStr = prePayData.noncestr req.prepayId = prePayData.prepayid req.sign = prePayData.sign req.packageValue = "Sign=WXPay"
- appid:微信开放平台审核通过的移动应用appid 。
- partnerid:商户号mchid对应的值
- prepayid:微信返回的支付交易会话ID,该值有效期为2小时
- package:固定值Sign=WXPay
- noncestr:随机字符串,不长于32位。
- timestamp:时间戳,秒。
- sign:签名,使用字段appId、timeStamp、nonceStr、prepayid计算得出的签名值
- 唤起支付。
/**
* @param payFrom 支付来源
* 微信支付start
*/
fun wxPay(prePayData: PrePayBean, error:()->Unit) {
if (getWxApi() != null) {
if (getWxApi()?.isWXAppInstalled == true) {
val req = PayReq()
req.appId = ConstantConfig.WX_APPID
req.partnerId = prePayData.partnerid //这些数据都是接口返回的
req.timeStamp = prePayData.timestamp
req.nonceStr = prePayData.noncestr
req.prepayId = prePayData.prepayid
req.sign = prePayData.sign
req.packageValue = "Sign=WXPay"
getWxApi()?.sendReq(req)
} else {
error.invoke()
ToastUtil.showNormal( "微信客户端未安装")
}
}
}
- 在包名目录下建一个wxapi的目录,新建WXPayEntryActivity接收返回的支付。
class WXPayEntryActivity : Activity(), IWXAPIEventHandler {
private var mContext: Context? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mContext = this@WXPayEntryActivity
PayUtil.getWxApi()?.handleIntent(intent, this)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
PayUtil.getWxApi()?.handleIntent(intent, this)
}
override fun onReq(baseReq: BaseReq) {
finish()
}
override fun onResp(resp: BaseResp) {
LogUtils.e( "payResp.onResp ")
if (resp.type == ConstantsAPI.COMMAND_PAY_BY_WX) {
val payResp = resp as PayResp
val extData = payResp.extData //区分支付来源
val bundle = Bundle()
LogUtils.e( "payResp.extData = $extData ${resp.errCode}")
bundle.putString("payFrom", extData)
if (resp.errCode == BaseResp.ErrCode.ERR_OK) {
// 微信支付成功,发个通知
MsgSender.getInstance().send(Channel.RechargeChannel.WX_PAY_SUCCESS,bundle)
} else {
MsgSender.getInstance().send(Channel.RechargeChannel.WX_PAY_FAIL,bundle)
}
}else{
MsgSender.getInstance().send(Channel.RechargeChannel.WX_PAY_FAIL,Bundle())
}
finish()
}
}
记得在manifest文件中注册一下。
<activity
android:name="kball.winpowerdata.wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
综上,支付流程就结束了,我们可以拿到支付的结果,成功或者失败去做app自定义的展示。
注意事项
Android10新增了包可见权限,访问外部apk,需要在mainfest中添加对应apk的包名。
<queries>
<!-- 微信支付客户端-->
<package android:name="com.tencent.mm" />
<!-- 支付宝支付客户端-->
<package android:name="com.eg.android.AlipayGphone" />
</queries>
FAQ
1.android SDK提示:微信appid不对?
注册微信api时需填写微信官网上注册的应用对应的appId。
2.微信唤起失败?
检查WXEntryActivity的目录是否为{packageName}.wxapi,否则微信唤起失败。
3.android SDK提示:支付验证签名失败?
后端拿到签名参数后必须再次签名,务必让后端检查签名是否一样。
4.微信未登录,唤起微信后,将微信退到后台,又返回,页面还是加载中,拿不到微信回调?
目前该场景不会走wxEntryActivity里的onResp方法,考虑手动处理,在换起微信应用后开始计时,在5分钟内拿不到微信回调记为失败情况。