Expo深度链接跳转网站报404,需引导至已安装APP
Expo深度链接唤起APP解决方案
我遇到了Expo深度链接的问题:点击https://monkify.app相关链接时会跳转到网站并抛出404错误,因为该网站仅作为着陆页存在,没有对应路径的页面。我希望用户访问该网站链接时,能直接唤起设备上已安装的APP;若未安装APP,则停留在着陆页。
以下是我的现有代码:
App.js
import React, { useEffect, useState, useCallback, useMemo } from "react"; import { NavigationContainer } from "@react-navigation/native"; import RootNavigator from "./src/navigation/RootNavigation"; import AuthNavigator from "./src/navigation/AuthNavigator"; import Media from "./src/components/Media"; import * as Linking from "expo-linking"; import { AuthContext } from "./src/components/Context"; import AudioProvider from "./src/context/AudioProvider"; export default function App() { const linking = { prefixes: [Linking.createURL("/"), "https://monkify.app", "monkify.app://"], config: { screens: { Podcast: "Podcast/:id", Video: "Video/:id", }, }, }; return ( <AuthContext.Provider value={authContext}> <AudioProvider> <NavigationContainer linking={linking} onLayout={onLayoutRootView} onStateChange={(state) => { setCurrentRouteName(state?.routes[state?.index]?.name); }} > <RootNavigator /> </NavigationContainer> </AudioProvider> </AuthContext.Provider> ); }
App.json
{ "expo": { "name": "Monkify", "slug": "Monkify", "owner": "monkify", "scheme": "monkify.app", "version": "1.0.9", "orientation": "default", "icon": "./assets/Images/Logo.png", "userInterfaceStyle": "light", "plugins": [ "expo-apple-authentication", "expo-image-picker", "sentry-expo", [ "expo-notifications", { "icon": "./assets/Images/NotificationLogo.png", "color": "#ffffff" } ], [ "expo-build-properties", { "ios": { "useFrameworks": "static" } } ], [ "expo-screen-orientation", { "initialOrientation": "DEFAULT" } ] ], "updates": { "fallbackToCacheTimeout": 0, "enabled": false }, "assetBundlePatterns": [ "**/*" ], "ios": { "requireFullScreen": true, "supportsTablet": true, "bitcode": false, "bundleIdentifier": "Enter your bundle identifier here", "buildNumber": "32", "associatedDomains": [ "applinks:monkify.app" ], "infoPlist": { "UIBackgroundModes": [ "audio" ], "NSPhotoLibraryUsageDescription": "Monkify needs access to your photos to set your profile picture" } }, "android": { "package": "Enter your package name here", "versionCode": 19, "useNextNotificationsApi": true, "intentFilters": [ { "action": "VIEW", "autoVerify": true, "data": [ { "scheme": "https", "host": "monkify.app", "pathPrefix": "/" } ], "category": [ "BROWSABLE", "DEFAULT" ] } ], "permissions": [ "android.permission.RECORD_AUDIO" ] }, "extra": { "eas": { "projectId": "Enter your project id here" } } }, "web": { "favicon": "./assets/favicon.png" } }
RootNavigator.js
import * as React from "react"; import { useState, useEffect, useContext } from "react"; import Media from "../components/Media"; import AuthNavigator from "./AuthNavigator"; import AudioProvider from "../context/AudioProvider"; import { AuthContext } from "../components/Context"; import * as Linking from "expo-linking"; import { useNavigation } from "@react-navigation/native"; import { isEmptyVar } from "../helper/isEmpty"; const RootNavigator = () => { const { token } = useContext(AuthContext); const navigation = useNavigation(); const handleURL = async (event) => { const url = await Linking.getInitialURL(); if (!isEmptyVar(url) || !isEmptyVar(event)) { let { path, queryParams } = Linking.parse( !isEmptyVar(event) ? event.url : url ); if (path === "Podcast") { navigation.navigate("Podcast", { id: queryParams.id, }); } else if (path === "Video") { navigation.navigate("Video", { id: queryParams.id, }); } } }; useEffect(() => { handleURL(); }, []); useEffect(() => { let subscribe = Linking.addEventListener("url", handleURL); return () => { subscribe.remove(); }; }, []); return <AudioProvider>{token ? <Media /> : <AuthNavigator />}</AudioProvider>; }; export default RootNavigator;
一、网站端配置(核心解决404+唤起APP)
你的网站仅作为着陆页,没有对应子路径页面,需做以下配置:
配置平台验证文件
- iOS:在网站根目录放置
apple-app-site-association(无后缀)文件,内容替换为:
注:TeamID可在苹果开发者后台查看,BundleIdentifier需与App.json中配置一致。{ "applinks": { "apps": [], "details": [ { "appID": "你的TeamID.你的BundleIdentifier", "paths": ["*"] } ] } } - Android:在网站
.well-known目录下放置assetlinks.json文件,内容替换为:
注:SHA256指纹可通过[ { "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "你的AndroidPackageName", "sha256_cert_fingerprints": ["你的APP签名SHA256指纹"] } } ]expo credentials:manager命令查看。
- iOS:在网站根目录放置
添加网页唤起脚本
在网站所有页面(尤其是404页面)插入以下脚本,优先尝试唤起APP,失败则跳转回着陆页:(function() { const appUrl = "monkify://" + window.location.pathname + window.location.search; const timeout = 1000; const startTime = Date.now(); // 尝试唤起APP window.location.href = appUrl; // 唤起失败则跳转回着陆页 setTimeout(() => { if (Date.now() - startTime < timeout * 2) { window.location.href = "/"; } }, timeout); })();
二、Expo配置优化
修正Scheme字段
Scheme仅需填自定义协议前缀,去掉.app后缀:"scheme": "monkify"自定义协议变为
monkify://,https://monkify.app作为Universal Links使用。保持关联域名配置
iOS的associatedDomains和Android的intentFilters配置正确,无需修改。
三、React Navigation链接逻辑简化
React Navigation的linking配置可自动处理路由跳转,无需手动解析:
完善App.js的linking配置
确保路由名称与导航器内的屏幕名称完全匹配:const linking = { prefixes: ["https://monkify.app", "monkify://"], config: { screens: { Media: { screens: { Podcast: "Podcast/:id", Video: "Video/:id", }, }, }, }, };移除RootNavigator中的手动监听
删除handleURL函数及对应的useEffect,React Navigation会自动处理冷启动、后台唤起的链接跳转逻辑。
验证步骤
- 用EAS Build重新构建并发布APP
- 确认验证文件可通过网站域名访问(如
https://monkify.app/apple-app-site-association) - 测试链接:打开
https://monkify.app/Podcast/123,验证已安装APP时能否唤起并跳转对应页面,未安装时能否回到着陆页
内容的提问来源于stack exchange,提问作者Komal Parulekar
相关产品推荐
相关产品推荐

