Expo SDK 49项目在TestFlight中启动即崩溃求助
Expo项目TestFlight启动崩溃:"invalid host, js engine: hermes" 排查指南
开发环境运行正常的Expo SDK49项目,使用expo-router路由,部署到TestFlight后启动即崩溃,iOS控制台仅显示invalid host, js engine: hermes错误。此前多个测试版本正常,已尝试常见方案三周未解决。
iOS日志
*** Terminating app due to uncaught exception 'RCTFatalException: Unhandled JS Exception: Error: invalid host, js engine: hermes', reason: 'Unhandled JS Exception: Error: invalid host, js engine: hermes, stack: validate@154167:21 configure@153802:30 createClient@154133:27 anonymous@153583:58 loadModuleImplementation@206:13 guardedLoadModule@137:37 metroRequire@64:91 anonymous@153422:66 loadModuleImplementation@206:13 guardedLoadModule@137:37 metroRequire@64:91 anonymous@153411:65 loadModuleImplementation@206:13 guardedLoadModule@137:37 metroRequire@64:91 anonymous@142296:54 loadModuleImplementation@206:13 guardedLoadModule@137:37 metroRequire@64:91 anonymous@108132:26 loadModuleImplementation@206:13 guardedLoadModule@129:46 metroRequire@64:91 get@107915:26 metroContext@108106:14 loadRoute@74985:32 applyDefaultInitialRouteName@74887:31 fileNodeToRouteNode@74942:40 treeNodeToRouteNode@74973:32 anonymous@74843:32 getTreeNodesAsRouteNodes@74842:20 fileNodeToRouteNode@74931:40 treeNodeToRouteNode@74973:32<…>
package.json
{ "name": "popil", "version": "3.1.0", "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web", "test": "jest --watchAll", "debugger": "react-native-debugger" }, "jest": { "preset": "jest-expo" }, "dependencies": { "@expo/vector-icons": "^13.0.0", "@gorhom/bottom-sheet": "^4.4.7", "@react-native-async-storage/async-storage": "1.18.2", "@react-navigation/drawer": "^6.6.2", "@react-navigation/native": "^6.0.2", "@react-navigation/stack": "^6.3.17", "@reduxjs/toolkit": "^1.9.5", "axios": "^1.4.0", "babel-plugin-module-resolver": "^5.0.0", "dayjs": "^1.11.9", "expo": "^49.0.0", "expo-checkbox": "~2.4.0", "expo-constants": "~14.4.2", "expo-dev-client": "~2.4.12", "expo-device": "~5.4.0", "expo-font": "~11.4.0", "expo-image-picker": "~14.3.2", "expo-linear-gradient": "~12.3.0", "expo-linking": "~5.0.2", "expo-notifications": "~0.20.1", "expo-router": "^2.0.4", "expo-splash-screen": "~0.20.5", "expo-status-bar": "~1.6.0", "expo-updates": "~0.18.18", "expo-web-browser": "~12.3.2", "formik": "^2.4.2", "html-entities": "^2.4.0", "htmlparser2": "^9.0.0", "react": "18.2.0", "react-content-loader": "^6.2.1", "react-dom": "18.2.0", "react-native": "0.72.6", "react-native-collapsible-tab-view": "^6.2.1", "react-native-gesture-handler": "~2.12.0", "react-native-pager-view": "6.2.0", "react-native-paper": "^5.10.4", "react-native-parsed-text": "^0.0.22", "react-native-reanimated": "~3.3.0", "react-native-render-html": "^6.3.4", "react-native-safe-area-context": "4.6.3", "react-native-screens": "~3.22.0", "react-native-svg": "13.9.0", "react-native-svg-transformer": "^1.0.0", "react-native-toast-message": "^2.1.6", "react-native-web": "~0.19.6", "react-native-webview": "13.2.2", "react-redux": "^8.1.1", "reactotron-react-native": "^5.0.3", "redux": "^4.2.1", "redux-persist": "^6.0.0", "styled-components": "^6.0.0-rc.3", "yup": "^1.2.0", "expo-system-ui": "~2.4.0", "expo-navigation-bar": "~2.3.0" }, "devDependencies": { "@babel/core": "^7.20.0", "@types/react": "~18.2.14", "@types/react-native-snap-carousel": "^3.8.5", "@types/react-redux": "^7.1.25", "@types/styled-components": "^5.1.26", "jest": "^29.2.1", "jest-expo": "^49.0.0", "prettier": "^2.8.8", "react-test-renderer": "18.2.0", "reactotron-redux": "^3.1.3", "typescript": "^5.1.3" }, "private": true }
app.json
{ "expo": { "name": "Popil", "slug": "popil", "version": "3.1.0", "jsEngine": "hermes", "orientation": "portrait", "icon": "./src/assets/images/logo-ios.png", "scheme": "myapp", "userInterfaceStyle": "automatic", "splash": { "image": "./src/assets/images/splash.png", "resizeMode": "contain", "backgroundColor": "#18181f" }, "assetBundlePatterns": [ "**/*" ], "ios": { "supportsTablet": true, "bundleIdentifier": "com.popil.popil", "bitcode": "Debug" }, "android": { "versionCode": 12, "googleServicesFile": "./google-services.json", "adaptiveIcon": { "foregroundImage": "./src/assets/images/logo-android.png" }, "package": "popil.popil" }, "web": { "bundler": "metro", "favicon": "./src/assets/images/favicon.png" }, "plugins": [] } }
eas.json
{ "cli": { "version": ">= 5.1.0" }, "build": { "development": { "developmentClient": true, "distribution": "internal", "channel": "development" }, "preview": { "distribution": "internal", "android": { "buildType": "apk" }, "channel": "preview" }, "production": { "node": "18.17.1", "channel": "production", "prebuildCommand": "prebuild --npm" }, "development-simulator": { "developmentClient": true, "distribution": "internal", "ios": { "simulator": true } } }, "submit": { "production": {} } }
index.tsx
import '@expo/metro-runtime'; import { ExpoRoot } from 'expo-router'; import Head from 'expo-router/head'; import { renderRootComponent } from 'expo-router/src/renderRootComponent'; // @ts-ignore const ctx = require.context('./src/app', true, /.*/); export function App() { return ( // @ts-ignore <Head.Provider> <ExpoRoot context={ctx} /> </Head.Provider> ); } renderRootComponent(App);
排查方向与解决方案
1. 定位"invalid host"根源
从堆栈看,错误来自validate→configure→createClient流程,大概率是网络请求客户端(如axios)的baseURL配置问题:
- 检查生产环境API域名是否正确,是否存在空值、未替换的
localhost等开发环境占位符 - 验证环境变量是否在TestFlight构建中正确注入:
- 在
eas.json的production构建中添加env字段传递环境变量 - 确认
expo-constants获取的manifest.extra包含正确的API地址
- 在
2. Expo Router适配生产构建
- 检查
index.tsx的require.context路径(当前为./src/app)是否匹配项目文件结构,expo-router默认要求app目录在根目录或src下 - 升级expo-router到SDK49兼容的最新版本(当前2.0.4,建议升级到2.0.16+),修复已知生产构建路由问题
3. Hermes引擎构建配置
- 在
eas.json的production构建中显式指定Hermes引擎,确保生产构建生效:"production": { "node": "18.17.1", "channel": "production", "prebuildCommand": "prebuild --npm", "ios": { "jsEngine": "hermes" } } - 执行
eas build --clean清理构建缓存,避免缓存导致的代码不一致
4. 环境变量与请求客户端检查
- 确保所有依赖的环境变量(如API域名)未使用开发环境硬编码值,改用
Constants.expoConfig?.extra?.API_URL这类方式获取 - 检查axios实例创建代码,避免生产环境下baseURL为空或错误:
// 正确示例 const api = axios.create({ baseURL: Constants.expoConfig?.extra?.API_URL || '默认生产域名' });
5. 路由加载异常排查
堆栈显示错误发生在loadRoute阶段,需检查:
src/app下的路由文件是否存在本地文件路径错误,或依赖了仅开发环境存在的模块- 验证
assetBundlePatterns配置是否覆盖所有需要打包的资源,避免生产环境缺失资源导致崩溃
内容的提问来源于stack exchange,提问作者Berat
相关产品推荐
相关产品推荐

