Go_router无法匹配带Fragment(#)的深层链接,如何解决?
解决Flutter中Supabase密码重置链接(带Fragment)与GoRouter的路由匹配问题
针对你遇到的Supabase生成的密码重置链接包含#片段导致GoRouter无法匹配/passwordReset路由的问题,以下是几种可行的解决方案:
方案1:确保深层链接的URI正确解析(外部链接场景)
如果是从邮件、浏览器打开的外部深层链接,问题可能出在系统对URI的解析上——#被错误识别为路径的一部分,而非Fragment。需要在Android和iOS端配置正确的链接处理规则:
Android配置(AndroidManifest.xml)
在对应Activity的intent-filter中,确保pathPrefix仅匹配路径部分,让系统正确分离Fragment:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="你的APP自定义Scheme" android:host="你的域名" android:pathPrefix="/passwordReset" /> </intent-filter>
iOS配置(Info.plist)
在CFBundleURLTypes中配置正确的URL Scheme,确保系统正确解析Fragment:
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>你的APP自定义Scheme</string> </array> <key>CFBundleURLName</key> <string>你的域名</string> </dict> </array>
方案2:通过GoRouter的Redirect强制匹配路由
如果URI解析正常但GoRouter仍无法匹配,可修改redirect逻辑,强制将带Fragment的请求路由到目标页面:
GoRouter router = GoRouter( routes: [ GoRoute( path: '/', builder: (context, _) => const PasswordResetLinkPage(title: 'Password Reset Link')), GoRoute( path: '/passwordReset', builder: (context, state) { // 提取Fragment中的认证参数 final fragmentParams = Uri.splitQueryString(state.uri.fragment); final accessToken = fragmentParams['access_token']; // 将参数传递给密码重置页面使用 return PasswordResetFormPage(accessToken: accessToken); } ) ], redirect: (context, state) { // 匹配所有以/passwordReset开头的路径(含Fragment) if (state.uri.path.startsWith('/passwordReset')) { return '/passwordReset'; } return null; }, );
方案3:手动处理深层链接导航
在应用入口处手动捕获并解析深层链接,再导航到目标页面:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 获取初始深层链接(需依赖uni_links等包) final initialLink = await getInitialLink(); Map<String, String>? resetParams; if (initialLink != null) { final uri = Uri.parse(initialLink); if (uri.path == '/passwordReset' && uri.fragment.isNotEmpty) { resetParams = Uri.splitQueryString(uri.fragment); } } runApp(MyApp(resetParams: resetParams)); }
后续在MyApp或路由中,将resetParams传递给PasswordResetFormPage即可。
验证示例代码
在你的测试代码中,调用context.go('/passwordReset/#access_token=qwerty')本应直接匹配/passwordReset路由(GoRouter默认忽略Fragment)。若未生效,建议升级GoRouter到最新版本,或在目标页面添加Fragment参数打印验证:
class PasswordResetFormPage extends StatelessWidget{ const PasswordResetFormPage({super.key}) : super(); @override Widget build(BuildContext context){ final state = GoRouterState.of(context); print('Fragment参数:${state.uri.fragment}'); // 应输出access_token=qwerty return Scaffold( appBar: AppBar(title: const Text('Provide new password')), body: const Column(children: [TextField(), TextField()]) ); } }
内容的提问来源于stack exchange,提问作者Michał Fatyga
相关产品推荐
相关产品推荐

