You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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('前往支付'),
        ),
      ),
    );
  }
}

在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更新现有页面的导航回调,逻辑和上述场景一致:

  1. 解析Deeplink中的参数(如回调标识、新跳转路径);
  2. 通过事件总线或状态管理将参数传递给目标页面;
  3. 目标页面接收参数后,更新内部的导航回调逻辑。

例如,在页面中维护Function? onPaymentDone变量,收到事件后直接更新该变量即可。


内容的提问来源于stack exchange,提问作者Kęstas Venslauskas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 14:55:56