Flutter go_router Deeplink问题:如何在现有页面栈顶推入新路由?
解决GoRouter Deeplink页面栈与支付回调问题
1. 实现Deeplink在现有栈顶部推入新路由
GoRouter默认用go()方法处理Deeplink,会直接替换整个页面栈。要保留原有栈并在顶部推入新路由,需自定义Deeplink处理逻辑:
代码实现
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 获取应用启动时的初始Deeplink final initialUri = await getInitialUri(); runApp(MyApp(initialUri: initialUri)); } class MyApp extends StatelessWidget { final Uri? initialUri; const MyApp({super.key, this.initialUri}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: GoRouter( routes: [ GoRoute( path: '/', builder: (_, __) => HomePage(), routes: [ GoRoute(path: 'payment', builder: (_, __) => PaymentPage()), GoRoute(path: 'result', builder: (_, __) => ResultPage()), ], ), ], initialLocation: '/', // 处理启动时的Deeplink redirect: (context, state) { if (initialUri != null && state.location == '/') { // 延迟执行push,避免上下文未初始化完成 WidgetsBinding.instance.addPostFrameCallback((_) { context.push('${initialUri!.path}${initialUri!.query}'); }); } return null; }, // 监听前台运行时的Deeplink变化 refreshListenable: GoRouterRefreshStream(uriLinkStream), // 拦截默认导航行为,改用push onNavigate: (location) { if (location != '/' && GoRouter.of(context).location != location) { context.push(location); // 返回true阻止默认的go()行为 return true; } return false; }, ), ); } }
核心逻辑:启动时通过addPostFrameCallback执行push替代默认的go;前台收到Deeplink时,通过onNavigate拦截默认行为,强制使用push保留原有页面栈。
2. 无需导航,通过全局回调处理Deeplink(支付场景)
支付场景下,无需跳转新页面,只需将支付结果通知原支付页面。可通过事件总线实现全局回调:
步骤1:创建全局事件总线
class PaymentEventBus { static final PaymentEventBus _instance = PaymentEventBus._(); factory PaymentEventBus() => _instance; PaymentEventBus._(); final _streamController = StreamController<PaymentResult>.broadcast(); Stream<PaymentResult> get paymentResults => _streamController.stream; void sendResult(PaymentResult result) => _streamController.add(result); void dispose() => _streamController.close(); } class PaymentResult { final String orderId; final bool isSuccess; PaymentResult({required this.orderId, required this.isSuccess}); }
步骤2:处理Deeplink并发送事件
class DeeplinkHandler { static void handleUri(Uri uri) { if (uri.path == '/payment-callback') { final orderId = uri.queryParameters['order_id']; final isSuccess = uri.queryParameters['success'] == '1'; if (orderId != null) { PaymentEventBus().sendResult( PaymentResult(orderId: orderId, isSuccess: isSuccess!), ); } // 不执行导航,直接处理回调逻辑 return; } // 其他Deeplink执行正常导航 GoRouter.of(WidgetsBinding.instance.focusManager.primaryFocus!.context!).push(uri.toString()); } }
步骤3:在支付页面监听事件
class PaymentPage extends StatefulWidget { final String orderId; const PaymentPage({super.key, required this.orderId}); @override State<PaymentPage> createState() => _PaymentPageState(); } class _PaymentPageState extends State<PaymentPage> { late StreamSubscription<PaymentResult> _subscription; @override void initState() { super.initState(); // 监听支付结果事件 _subscription = PaymentEventBus().paymentResults.listen((result) { if (result.orderId == widget.orderId) { if (result.isSuccess) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('支付成功')), ); // 返回原页面 Navigator.pop(context); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('支付失败,请重试')), ); } } }); } @override void dispose() { _subscription.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('支付订单 ${widget.orderId}')), body: Center( child: ElevatedButton( onPressed: () { // 跳转到浏览器支付页面 launchUrl(Uri.parse('https://your-payment-gateway.com?order_id=${widget.orderId}')); }, child: const Text('前往支付'), ), ), ); } }
步骤4:全局监听Deeplink
在main中初始化监听:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 处理启动时的初始Deeplink final initialUri = await getInitialUri(); if (initialUri != null) DeeplinkHandler.handleUri(initialUri); // 监听前台运行时的Deeplink uriLinkStream.listen(DeeplinkHandler.handleUri); runApp(const MyApp()); }
3. 更新页面导航属性(如回调)
如果需要通过Deeplink更新现有页面的导航回调,逻辑和上述场景一致:
- 解析Deeplink中的参数(如回调标识、新跳转路径);
- 通过事件总线或状态管理将参数传递给目标页面;
- 目标页面接收参数后,更新内部的导航回调逻辑。
例如,在页面中维护Function? onPaymentDone变量,收到事件后直接更新该变量即可。
内容的提问来源于stack exchange,提问作者Kęstas Venslauskas
相关产品推荐
相关产品推荐

