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

Flutter Deeplink路由异常:Routemaster与AppLinks问题排查

Deeplink配置失效问题排查与修复

问题描述

  • 初始症状:nl.fittestbody.Gainz:// 可正常工作,但 nl.fittestbody.Gainz://login 抛出错误并显示NotFound页面
  • 后续更新:nl.fittestbody.Gainz:// 也无法正常工作,抛出以下错误:
Couldn't get a Routemaster object from the given context.
'package:routemaster/routemaster.dart':
Failed assertion: line 141 pos 7: 'widget != null'
  • 技术栈:使用routemaster和app_links包,已禁用iOS info.plist和Android Manifest中的原生Deeplink配置

核心问题分析

  1. 上下文无效:在initState中监听uriLinkStream时,传递的context不包含Routemaster上下文——此时MaterialApp.router尚未完成构建,RoutemasterDelegate还未挂载到上下文树,调用Routemaster.of(context)会获取不到实例。
  2. 路由匹配逻辑错误:nl.fittestbody.Gainz://login的uri.host是login,但现有路由配置中没有/login路径,触发onUnknownRoute显示NotFound页面。

修复步骤

1. 修复上下文获取问题

改用全局Key获取Routemaster上下文,避免依赖未初始化的BuildContext:

在Gainz类中定义全局导航Key:

class Gainz extends ConsumerStatefulWidget {
  const Gainz({super.key});
  static final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

  @override
  ConsumerState<Gainz> createState() => _GainzState();
}

关联到MaterialApp.router:

MaterialApp.router(
  navigatorKey: Gainz.navigatorKey,
  // 其他原有配置不变
)

修改DeepLinkService,通过全局Key获取有效上下文:

class DeepLinkService {
  static void handleDeepLink(Uri uri) {
    final context = Gainz.navigatorKey.currentContext;
    if (context == null) return;
    
    final routemaster = Routemaster.of(context);
    
    if (uri.host == 'login') {
      routemaster.replace('/');
      final accessToken = uri.queryParameters['access_token'];
      if (accessToken != null) {
        Supabase.instance.client.auth.setSession(accessToken);
      }
    } else if (uri.host == 'email-verified') {
      routemaster.replace('/');
      return;
    } else {
      if (uri.host.isNotEmpty) {
        routemaster.replace('/${uri.host}');
      } else {
        routemaster.replace('/');
      }
    }
  }
}

更新监听逻辑,不再传递BuildContext:

_linkSubscription = _appLinks.uriLinkStream.listen((Uri uri) {
  WidgetsBinding.instance.addPostFrameCallback((_) {
    DeepLinkService.handleDeepLink(uri);
  });
});

如果需要直接响应/login路由,在登录/未登录路由中添加对应路径:

// 未登录状态路由
final loggedOutRoute = RouteMap(routes: {
  '/': (_) => const MaterialPage(child: AuthScreen()),
  '/login': (_) => const MaterialPage(child: AuthScreen()),
});

// 登录状态路由
final loggedInRoute = RouteMap(
  onUnknownRoute: (path) => const MaterialPage(child: NotFoundPage()),
  routes: {
    '/': (_) => const MaterialPage(child: HomeScreen()),
    '/login': (_) => const MaterialPage(child: AuthScreen()),
    '/new-exercise': (_) => const MaterialPage(child: ExerciseUpdateScreen()),
    // 其他原有路由
  },
);

3. 确保路由构建时机稳定

修改routesBuilder,在内部实时获取auth状态,避免外部状态过期导致上下文异常:

routerDelegate: RoutemasterDelegate(
  routesBuilder: (context) {
    final authState = ref.watch(authStateChangeProvider);
    return authState.when(
      data: (data) => data.session != null ? loggedInRoute : loggedOutRoute,
      error: (_, __) => loggedOutRoute,
      loading: () => RouteMap(routes: {
        '/': (_) => const Loader(),
      }),
    );
  },
),

额外验证步骤

  • 用命令行触发Deeplink测试,避免系统缓存问题:
    • Android:adb shell am start -W -a android.intent.action.VIEW -d "nl.fittestbody.Gainz://login"
    • iOS:xcrun simctl openurl booted "nl.fittestbody.Gainz://login"

内容的提问来源于stack exchange,提问作者Wesley

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 18:34:55