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

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文件),调整配置并修改代码:

  1. 更新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;
  1. 修改读取函数逻辑:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 18:15:10