周期扣款
droplet-js opened this issue · comments
周期扣款
支付后签约
和普通支付一个流程
先签约后代扣
后端设置 return_url: ${your app scheme}://${custom host}/alipay/page_sign/return_url
Future<bool> _showAlipayPageSignAlert(BuildContext context, {required String url}) async {
final dynamic result = await showCupertinoDialog(
context: context,
builder: (BuildContext context) {
return WillPopScope(
child: CupertinoAlertDialog(
content: SizedBox(
height: 40,
child: Stack(
children: <Widget>[
Visibility(
visible: false,
maintainState: true,
maintainAnimation: true,
maintainSize: true,
maintainInteractivity: false,
child: AlipayPageSignSlientExec(url: url),
),
Center(
child: CupertinoActivityIndicator(radius: 12),
),
],
),
),
),
onWillPop: () => Future<bool>.value(false),
);
},
barrierDismissible: false,
);
return result is bool && result;
}
// 先签约后扣费
// https://opendocs.alipay.com/open/00a05b?pathHash=4f048b01#%E6%97%A0%E7%BA%BF%E7%AB%AF%E5%94%A4%E8%B5%B7%E7%AD%BE%E7%BA%A6%E8%AF%B4%E6%98%8E
// url 后端处理
// [encodeURIComponent](https://blog.csdn.net/KokJuis/article/details/84140514)
// final String signParams = url.replace("https://openapi.alipay.com/gateway.do?","");
// url = "alipays://platformapi/startapp?appId=60000157&appClearTop=false&startMultApp=YES&sign_params="+ encodeURIComponent(signParams)
// url 客户端处理
// final String signParams = url.replaceAll('https://openapi.alipay.com/gateway.do?', '');
// url = 'alipays://platformapi/startapp?appId=60000157&appClearTop=false&startMultApp=YES&sign_params=${Uri.encodeQueryComponent(signParams)}';
class AlipayPageSignSlientExec extends StatefulWidget {
const AlipayPageSignSlientExec({
super.key,
required this.url,
});
final String url;
@override
State<StatefulWidget> createState() {
return _AlipayPageSignSlientExecState();
}
}
class _AlipayPageSignSlientExecState extends State<AlipayPageSignSlientExec> with WidgetsBindingObserver {
Route<dynamic>? _route;
late final StreamSubscription<String> _linkClickSubs;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_linkClickSubs = LinkKitPlatform.instance.linkClickStream().listen((String event) {
_evalDeepLink(context, event);
});
launchUrlString(widget.url, mode: LaunchMode.externalApplication);
}
// ${your app scheme}://${custom host}/alipay/page_sign/return_url?msg=Success&charset=utf-8&code=10000&method=alipay.user.agreement.page.sign.return
Future<void> _evalDeepLink(BuildContext context, String url) async {
final Uri uri = Uri.parse(url);
if (uri.path == '/alipay/page_sign/return_url') {
if (kDebugMode) {
print('Alipay Page Sign: $url');
}
if (uri.queryParameters['code'] == '10000') {
if (_route?.isActive ?? false) {
Navigator.of(context).pop(true);
}
} else {
if (_route?.isActive ?? false) {
Navigator.of(context).pop(false);
}
}
}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_clearSubscription();
}
}
Future<void> _clearSubscription() async {
await Future<void>.delayed(const Duration(seconds: 1));// 取消事件不走 deep link 回调,只能在 resumed 里取消(这会与 deep link 回调冲突,故作延迟)
if (_route?.isActive ?? false) {
// ignore: use_build_context_synchronously
Navigator.of(context).pop(false);
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_route ??= ModalRoute.of(context);
}
@override
void dispose() {
_linkClickSubs.cancel();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox();
}
}