Files
video/app/lib/services/pay_launcher.dart
T
2026-10-15 20:36:59 +08:00

140 lines
4.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:async';
import 'package:fluwx/fluwx.dart';
import 'package:tobias/tobias.dart';
import '../core/config/app_config.dart';
import 'payment_service.dart';
/// 支付宝/微信原生 SDK 调起封装(《03-接口文档》8.2 pay_params)
///
/// 服务端配置了商户密钥时 pay_params 为真实调起参数,此处调起原生 SDK;
/// 未配置(dev)时服务端返回 dev_mock 占位,调用方应以轮询兜底代替调起。
enum PayLaunchResult {
/// 渠道回调成功(仍需以服务端查单为准,避免客户端伪造)
success,
/// 用户主动取消
canceled,
/// 调起失败(未安装 App / 参数缺失 / SDK 报错)
failed,
/// pay_params 无有效调起参数(服务端未配置商户密钥)
unsupported,
}
class PayLauncher {
PayLauncher._();
static final _fluwx = Fluwx();
/// 微信调起等待回调的最长时间
static const _wechatTimeout = Duration(minutes: 5);
/// 支付宝调起:order_string 直接交给 SDK
static Future<PayLaunchResult> launchAlipay(RechargeOrderInfo order) async {
final orderString = order.payParams['order_string'] as String?;
if (orderString == null || orderString.isEmpty) {
return PayLaunchResult.unsupported;
}
try {
final result = await Tobias().pay(orderString);
return _mapAlipayStatus(result['resultStatus'] as String?);
} catch (_) {
return PayLaunchResult.failed;
}
}
/// 微信调起:registerApi → pay → 等待 SDK 回调
static Future<PayLaunchResult> launchWechat(RechargeOrderInfo order) async {
final params = order.payParams;
final appId = params['appid'] as String?;
final partnerId = params['partnerid'] as String?;
final prepayId = params['prepayid'] as String?;
final packageValue = params['package'] as String?;
final nonceStr = params['noncestr'] as String?;
final sign = params['sign'] as String?;
final timestamp = int.tryParse('${params['timestamp']}');
if (appId == null ||
appId.isEmpty ||
partnerId == null ||
partnerId.isEmpty ||
prepayId == null ||
prepayId.isEmpty ||
packageValue == null ||
packageValue.isEmpty ||
nonceStr == null ||
nonceStr.isEmpty ||
sign == null ||
sign.isEmpty ||
timestamp == null) {
return PayLaunchResult.unsupported;
}
final completer = Completer<PayLaunchResult>();
final cancelable = _fluwx.addSubscriber((response) {
if (response is WeChatPaymentResponse && !completer.isCompleted) {
completer.complete(_mapWechatErrCode(response.errCode));
}
});
try {
await _fluwx.registerApi(
appId: appId,
universalLink: AppConfig.wechatUniversalLink.isEmpty
? null
: AppConfig.wechatUniversalLink,
);
final sent = await _fluwx.pay(
which: Payment(
appId: appId,
partnerId: partnerId,
prepayId: prepayId,
packageValue: packageValue,
nonceStr: nonceStr,
timestamp: timestamp,
sign: sign,
),
);
if (!sent) return PayLaunchResult.failed;
return await completer.future.timeout(
_wechatTimeout,
onTimeout: () => PayLaunchResult.failed,
);
} catch (_) {
return PayLaunchResult.failed;
} finally {
cancelable.cancel();
}
}
/// 按支付方式分发(1支付宝 2微信)
static Future<PayLaunchResult> launch(RechargeOrderInfo order) {
return switch (order.payMethod) {
1 => launchAlipay(order),
2 => launchWechat(order),
_ => Future.value(PayLaunchResult.unsupported),
};
}
/// 支付宝 resultStatus:9000成功 6001用户取消 8000/8001处理中 其余失败
static PayLaunchResult _mapAlipayStatus(String? status) {
return switch (status) {
'9000' => PayLaunchResult.success,
'6001' => PayLaunchResult.canceled,
'8000' || '8001' => PayLaunchResult.success, // 处理中,交由服务端查单确认
_ => PayLaunchResult.failed,
};
}
/// 微信 errCode:0成功 -2用户取消 其余失败
static PayLaunchResult _mapWechatErrCode(int? errCode) {
return switch (errCode) {
0 => PayLaunchResult.success,
-2 => PayLaunchResult.canceled,
_ => PayLaunchResult.failed,
};
}
}