Expo React Native深度链接问题:跳转至错误页面
myapp://updatepassword/:token跳转到错误页面 我用Expo开发React Native应用,配置深度链接后,点击myapp://updatepassword/:token这类链接,本该跳转到UpdatePasswordScreen,结果却重定向到了PasswordResetScreen。反复检查了app.json和app.js的配置,也重新构建过应用,UpdatePasswordScreen也已经正确加入导航栈,但问题还是没解决。
已尝试操作
- 在
app.json和app.js中配置深度链接 - 使用
myapp://updatepassword/<token>格式的URL测试深度链接
预期结果
应用导航至UpdatePasswordScreen,并携带正确的token参数
实际结果
应用重定向至PasswordResetScreen
代码示例
app.json
{ "expo": { "scheme": "myapp", "android": { "intentFilters": [ { "action": "VIEW", "data": { "scheme": "myapp", "host": "updatepassword" }, "category": [ "BROWSABLE", "DEFAULT" ] } ] } } }
App.js
import { NavigationContainer } from "@react-navigation/native"; import * as Linking from "expo-linking"; import React, { useEffect, useRef } from "react"; import { Text } from "react-native"; import FlashMessage from "react-native-flash-message"; import { AuthProvider } from "./src/context/authContext"; import MainDrawerNavigation from "./src/navigation/DrawerNavigation/MainDrawerNavigation"; const prefix = Linking.createURL("myapp://"); const expoPrefix = "exp://192.168.1.101:8081"; const App = () => { const navigationRef = useRef(null); const linking = { prefixes: [prefix, expoPrefix], config: { screens: { Auth: { screens: { Login: "login", PasswordReset: "passwordReset", Signup: "signup", UpdatePassword: "updatepassword/:token", }, }, Decouvrir: { screens: { Discoveries: "discoveries", Detail: "detail/:id", }, }, }, }, }; function handleDeepLink(event) { const { url } = event; const parsed = Linking.parse(url); console.log("handleDeepLink", url); console.log("Parsed path:", parsed.path); console.log("Parsed query params:", parsed.queryParams); if (parsed.path && parsed.path.startsWith("updatepassword")) { const token = parsed.path.split("/").pop(); navigationRef.current?.reset({ index: 0, routes: [{ name: "UpdatePassword", params: { token } }], }); console.log("Navigating to UpdatePassword screen with token:", token); } else { console.log("Path does not match updatepassword pattern."); } } useEffect(() => { const handleInitialURL = async () => { const url = await Linking.getInitialURL(); if (url) { console.log("Initial URL:", url); handleDeepLink({ url }); } }; Linking.addEventListener("url", handleDeepLink); handleInitialURL(); // Comment out removeEventListener if not supported return () => { // Linking.removeEventListener("url", handleDeepLink); }; }, []); return ( <NavigationContainer linking={linking} ref={navigationRef} fallback={<Text>Loading...</Text>} > <AuthProvider> <MainDrawerNavigation /> <FlashMessage position="bottom" /> </AuthProvider> </NavigationContainer> ); }; export default App;
控制台日志
handleDeepLink myapp://updatepassword/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFuZ2UucGluY2hvbkBnbWFpbC5jb20iLCJwc2V1ZG8iOiJBbmdlbG91IiwiZXhwIjoxNzIyODYwMzQ1LCJpYXQiOjE3MjI4NTY3NDV9.jIoW-hvLVTGEcAS41496097JkDwuc9VIQ060guol060 c2V1ZG8iOiJBbmdlbG91IiwiZXhwIjoxNzIyODYwMzQ1LCJpYXQiOjE3MjI4NTY3NDV9.jIoW-hvLVTGEcAS41496097JkDwuc9VIQ060guol060 LOG Parsed path: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFuZ2UucGluY2hvbkBnbWFpbC5jb20iLCJwc2V1ZG8iOiJBbmdlbG91IiwiZXhwIjoxNzIyODYwMzQ1LCJpYXQiOjE3MjI4NTY3NDV9.jIoW-hvLVTGEcAS41496097JkDwuc9VIQ060guol060 LOG Parsed query params: {} LOG Path does not match updatepassword pattern.
问题根源与修复方案
问题根源
从控制台日志能看到,parsed.path直接返回了token字符串,而非updatepassword/<token>。这是因为你的URL格式是myapp://updatepassword/<token>,其中updatepassword是host,不是path的一部分,所以Linking.parse(url)解析后,parsed.host才是updatepassword,parsed.path仅包含host后的token内容。原代码判断path.startsWith("updatepassword")自然不成立,导致跳转逻辑未触发,反而让React Navigation默认的linking配置匹配到了错误路由。
修复步骤
修正深度链接解析逻辑
修改handleDeepLink函数,改为判断parsed.host,同时调整路由跳转的层级(UpdatePasswordScreen属于Auth栈下的页面,需指定完整路由):function handleDeepLink(event) { const { url } = event; const parsed = Linking.parse(url); console.log("handleDeepLink", url); console.log("Parsed host:", parsed.host); console.log("Parsed path:", parsed.path); console.log("Parsed query params:", parsed.queryParams); if (parsed.host === "updatepassword") { // 去掉path开头的/,拿到纯净的token const token = parsed.path.slice(1); navigationRef.current?.reset({ index: 0, routes: [{ name: "Auth", screen: "UpdatePassword", params: { token } }], }); console.log("Navigating to UpdatePassword screen with token:", token); } else { console.log("Host does not match updatepassword pattern."); } }优化React Navigation的linking配置(可选)
如果你希望依赖React Navigation的自动深度链接处理,可确保linking.config的路由层级正确,同时注释掉自定义的handleDeepLink逻辑,测试默认解析是否生效。重新构建测试
修改代码后,重启Expo开发服务器,或执行expo prebuild(裸工作流),再次测试深度链接是否正常跳转。
内容的提问来源于stack exchange,提问作者angelou

