Expo应用打包读取JSON文件失败,请求排查解决
Expo打包文件运行时读取失败排查与解决方案
配置现状
- 已安装
expo-asset和expo-file-system依赖 - 在
assets/data/recipe.json路径下创建目标JSON文件 metro.config.js配置:
const { getDefaultConfig } = require('expo/metro-config'); /** @type {import('expo/metro-config').MetroConfig} */ const config = getDefaultConfig(__dirname); config.resolver.assetExts.push('json'); module.exports = config;
app.json配置片段:
{ ... "plugins": [ "expo-router", [ "expo-splash-screen", { "image": "./assets/images/splash-icon.png", "imageWidth": 200, "resizeMode": "contain", "backgroundColor": "#ffffff" } ], "expo-asset" ], ..... }
代码实现
在service.ts中编写的读取函数,用于React组件调用:
private async getBundledRecipe(): Promise<StorageRecipe> { try { const nodeRequire = require("../assets/data/recipe.json"); const asset = Asset.fromModule(nodeRequire); await asset.downloadAsync(); const payload = await FileSystem.readAsStringAsync(asset.localUri!); return JSON.parse(payload) as StorageRecipe; } catch (error) { console.error("error when calling getBundledRecipe()", error); throw error; } }
错误信息
- 使用原路径时:
error when calling getBundledRecipe() [Error: Module "[object Object]" is missing from the asset registry] [Component Stack] - 修改路径为
./assets/data/recipe.json时:error when calling getBundledRecipe() [Error: Module "undefined" is missing from the asset registry] [Component Stack](验证原路径的正确性)
问题分析
将json加入assetExts后,require返回的是Asset对象而非普通JSON内容,但Asset.fromModule传入该对象时出现注册表匹配异常。本质是对Expo Asset系统的使用逻辑有误,同时Metro配置未正确区分JSON的解析优先级(默认JSON会被当作代码模块解析,而非静态资源)。
解决方案
方案1:直接导入JSON(纯JSON场景最优)
若仅需读取JSON内容,无需将其作为Asset处理,移除Metro中assetExts.push('json')的配置,直接通过import导入:
import recipeData from '../assets/data/recipe.json'; private getBundledRecipe(): StorageRecipe { return recipeData as StorageRecipe; }
该方式打包时JSON会直接嵌入代码,运行时无需异步读取,效率最高。
方案2:正确使用Asset系统(需本地URI场景)
如果必须通过Asset系统获取本地URI(比如后续处理MP3文件),调整配置并修改代码:
- 更新
metro.config.js,确保JSON被识别为静态资源:
const { getDefaultConfig } = require('expo/metro-config'); const config = getDefaultConfig(__dirname); // 将JSON从代码模块扩展名中移除,加入静态资源扩展名 config.resolver.sourceExts = config.resolver.sourceExts.filter(ext => ext !== 'json'); config.resolver.assetExts.push('json'); module.exports = config;
- 修改读取函数逻辑:
import { Asset } from 'expo-asset'; import * as FileSystem from 'expo-file-system'; private async getBundledRecipe(): Promise<StorageRecipe> { try { const assetModule = require('../assets/data/recipe.json'); const asset = Asset.fromModule(assetModule); // 开发环境需下载资源,生产环境已打包至本地 if (!asset.localUri) { await asset.downloadAsync(); } const payload = await FileSystem.readAsStringAsync(asset.localUri!); return JSON.parse(payload) as StorageRecipe; } catch (error) { console.error("读取打包JSON失败", error); throw error; } }
后续MP3文件处理
对于MP3等媒体文件,直接沿用方案2的配置即可,示例代码:
private async getBundledAudio(): Promise<string> { const audioAsset = Asset.fromModule(require('../assets/audio/demo.mp3')); if (!audioAsset.localUri) { await audioAsset.downloadAsync(); } return audioAsset.localUri!; }
内容的提问来源于stack exchange,提问作者blessed01
相关产品推荐
相关产品推荐

