flutter实现在app内支付
2020-01-07 本文已影响0人
小小的开发人员
项目背景:
通过不断迭代,项目提供的服务愈发完善,开始做一些付费服务,需要做支付功能,方案是Android做微信支付,IOS在app store支付。
- 插件,详细使用见https://pub.dev/
import 'package:fluwx/fluwx.dart' as fluwx;
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
- app store支付
/// 关闭iOS支付连接
void closeIosConnection() async {
await FlutterInappPurchase?.instance?.endConnection;
}
/// 销毁之前的订单,否则无法多次购买
Future clearTransaction() async{
return FlutterInappPurchase.instance?.clearTransactionIOS();
}
/// iOS pay
void doIOSPay({
int productId,
VoidCallback onConnectAppStore,
VoidCallback onSuccess,
OnPayError onError,
}) async {
if (isPaying) return;
isPaying = true;
/// 需要去appStore创建iosProductId
HttpResult res = await Api.post('xxxx/xxxx/app-store',
params: {'productId': productId});
if (res.code != 200) {
isPaying = false;
return onError?.call(res.message);
}
List<IAPItem> _products = await FlutterInappPurchase.instance
.getProducts([res.data['iosProductId']]);
if (_products.length == 0) {
isPaying = false;
return onError?.call('没有找到相关产品,请联系客服');
}
/// 初始化连接
await FlutterInappPurchase.instance.initConnection;
/// 连接状态监听
FlutterInappPurchase.connectionUpdated.listen((connected) {
/// 调起苹果支付,这时候可以关闭toast
onConnectAppStore?.call();
});
/// appStore购买状态监听
FlutterInappPurchase.purchaseUpdated.listen((productItem) async {
if (productItem != null) {
/// 校验
HttpResult validateRes = await Api.put('/xxxx/xxxx/app-store',
params: {
'tradeNo': res.data['tradeNo'],
'receiptData': productItem.transactionReceipt
});
if (validateRes.code != 200) {
return onError?.call(res.message);
}
await clearTransaction();
/// 购买成功回调
onSuccess?.call();
}
isPaying = false;
});
/// 错误监听
FlutterInappPurchase.purchaseError.listen((purchaseError) async{
print('purchase-error: $purchaseError');
isPaying = false;
await clearTransaction();
await FlutterInappPurchase?.instance?.endConnection;
/// 购买错误回调
onError?.call('购买失败');
});
/// 发起支付请求,传递iosProductId
FlutterInappPurchase.instance.requestPurchase(res.data['iosProductId']);
}
- 微信支付
/// 发送android支付消息,调起微信支付面板
void invokeWechatPay(PayEvent payEvent) {
eventManager.eventBus.fire(payEvent);
}
/// 微信支付,添加订单到后台
void doWechatPay({
int productId,
VoidCallback onWechatPaying,
VoidCallback onPayResultChecking,
VoidCallback onSuccess,
OnPayError onError,
}) async {
if (isPaying) return;
isPaying = true;
/// 先检测是否已安装微信
bool _isWechatInstalled = await fluwx.isWeChatInstalled();
if (!_isWechatInstalled) {
isPaying = false;
return onError?.call('请安装微信完成支付或使用苹果手机支付');
}
HttpResult res = await Api.post('/xxx/orders',
params: {'productId': productId });
if (res.code != 200) {
isPaying = false;
return onError?.call(res.message);
}
var _data = res.data;
/// 再检测一遍appid是否一致
if (_data['appid'] != Config.WECHAT_APP_ID) {
isPaying = false;
return onError?.call('微信支付异常,请联系客服[id not match]');
}
/// 跳转微信登陆前通知关闭toast等
onWechatPaying?.call();
/// 每次支付前先尝试注销监听,避免重复回调
_wxPay?.cancel();
_wxPay = fluwx.responseFromPayment.listen((response) async {
isPaying = false;
/// 支付失败
if (response.errCode != 0) {
return onError?.call('微信支付失败');
}
onPayResultChecking?.call();
/// 微信返回支付成功后,查询支付接口确认后再返回(以便后台更新同步更新支付结果相关数据)
/// 调接口目的是为后台更新数据,不管接口调用是否成功
var orderId = _data['orderId'];
HttpResult res = await Api.get('/billing-api/orders/$orderId');
if (res.code != 200 || res.data['orderId'] != orderId) {
return onError?.call(res.message ?? '支付异常,未查询到订单。请联系客服');
}
onSuccess?.call();
});
/// 调起微信支付
fluwx
.payWithWeChat(
appId: _data['appid'].toString(),
partnerId: _data['partnerid'].toString(),
prepayId: _data['prepayid'].toString(),
packageValue: _data['package'].toString(),
nonceStr: _data['noncestr'].toString(),
timeStamp: _data['timestamp'],
sign: _data['sign'].toString(),
)
.then((result) {
print("pay then result: $result");
});
}
- 组件内调用
/// 根据平台调支付
void _doPay(context) async {
if (Platform.isIOS) {
/// 苹果支付
toast.show(context, '正在支付...', 99999);
myPay.doIOSPay(
productId: Config.unLockBookId,
onConnectAppStore: () {
toast.hide();
},
onError: (String error) {
toast.show(context, error);
},
onSuccess: () {});
} else {
/// 调起微信支付面板
PayEvent _payEvent = PayEvent(pageLesson,
productId: Config.unLockBookId,
title: '30 狐币',
originalPrice: '3',
price: '3',
discount: '0', callback: (bool isSuccess) {
_wechatPayCallback(isSuccess, context);
});
myPay.invokeWechatPay(_payEvent);
}
}
遇到的问题:
- app Store 多次支付时,会保留之前的订单,造成支付异常,需要对之前的订单及时地做销毁操作。
- 经过调试,我发现app store支付时,仍然会触发app生命didChangeAppLifecycleState方法,有一个跳转到第三方应用的过程,并不像显示的只是提示toast。
- 微信支付时,执行的顺序是,提交支付订单成功-> didChangeAppLifecycleState生命周期触发->微信支付成功回调,这里有一个Bug是,如果用户进入微信支付,并输入密码支付成功,但是却没有点击微信支付页面的返回商家或者是点击左上角的退出按钮,直接通过手机导航进行切换,这时候支付已然成功,却触发不了支付成功回调。
目前的处理方法大概是,支付完成后,会进入一个自己写的支付页面,在这个页面中判断支付是否成功,而不采用微信支付提供的回调,这是一种主流解决方法。也可以写入到didChangeAppLifecycleState生命周期中,在didChangeAppLifecycleState中仍然要做支付页面的判断逻辑。
/// 监听页面前后台切换,以便处理微信支付中途点击左上角返回App,导致fluwx监听不到回调事件
@override
void didChangeAppLifecycleState(AppLifecycleState state) async{
switch (state) {
case AppLifecycleState.resumed:
if (_rechargeProcess) {
_compareCoins(); /// 判断支付是否成功
}
break;
default:
break;
}
super.didChangeAppLifecycleState(state);
}