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

Expo React Native深度链接问题:跳转至错误页面

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配置匹配到了错误路由。

修复步骤

  1. 修正深度链接解析逻辑
    修改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.");
      }
    }
    
  2. 优化React Navigation的linking配置(可选)
    如果你希望依赖React Navigation的自动深度链接处理,可确保linking.config的路由层级正确,同时注释掉自定义的handleDeepLink逻辑,测试默认解析是否生效。

  3. 重新构建测试
    修改代码后,重启Expo开发服务器,或执行expo prebuild(裸工作流),再次测试深度链接是否正常跳转。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 05:30:54