React Native动态加载本地JSON音频文件播放失败求助
React Native 本地音频播放(支持安卓)问题解决
你遇到的错误根源是:Expo AV 在 React Native 环境中无法直接解析字符串形式的相对路径,它会把这个路径当成网络请求去访问,最终返回了 HTML 错误页面(所以 Content-Type 是 text/html),自然无法播放音频。以下是适配安卓的完整解决方案,包含播放/暂停功能:
1. 调整本地音频资源的引用方式
React Native 中本地资源必须通过 require() 引入,不能直接使用字符串路径。你可以按以下两种方式处理:
方式一:修改 JSON 文件(推荐)
把 JSON 中的音频路径改为仅存文件名:
"audio": "Lite Saturation - Nostalgia.mp3"
然后在代码中拼接路径并引入:
const audioSource = require(`./audio/${tune.audio}`);
方式二:路径映射表(不修改 JSON 时使用)
如果无法修改原 JSON,提前建立路径与资源的映射:
const audioMap = { "./audio/Lite Saturation - Nostalgia.mp3": require("./audio/Lite Saturation - Nostalgia.mp3"), // 其他音频文件按需添加 }; const audioSource = audioMap[tune.audio];
2. 完整播放/暂停实现(基于 Expo AV)
下面是支持播放、暂停、资源自动释放的代码:
import { useState, useEffect } from 'react'; import { Audio } from 'expo-av'; import { Button } from 'react-native'; const AudioPlayer = ({ tune }) => { const [sound, setSound] = useState(null); const [isPlaying, setIsPlaying] = useState(false); // 按实际情况选择上面的方式获取 audioSource const audioSource = require(`./audio/${tune.audio}`); const togglePlayPause = async () => { try { if (!sound) { // 初始化并播放音频 const newSound = new Audio.Sound(); await newSound.loadAsync(audioSource); await newSound.playAsync(); setSound(newSound); setIsPlaying(true); // 监听播放结束,自动重置状态 newSound.setOnPlaybackStatusUpdate(status => { if (status.didJustFinish) { setIsPlaying(false); setSound(null); } }); } else if (isPlaying) { // 暂停音频 await sound.pauseAsync(); setIsPlaying(false); } else { // 恢复播放 await sound.playAsync(); setIsPlaying(true); } } catch (error) { console.log("音频播放错误:", error); } }; // 组件卸载时释放音频资源,避免内存泄漏 useEffect(() => { return () => { if (sound) { sound.unloadAsync(); } }; }, [sound]); return ( <Button title={isPlaying ? "暂停" : "播放"} onPress={togglePlayPause} /> ); }; export default AudioPlayer;
3. 关键注意事项
- 资源打包配置:确保
metro.config.js支持 mp3 格式(Expo 项目默认已支持,自定义配置时需确认):// metro.config.js const { getDefaultConfig } = require('expo/metro-config'); const config = getDefaultConfig(__dirname); config.resolver.assetExts.push('mp3'); module.exports = config; - 安卓权限:Expo 项目无需额外配置;裸 React Native 项目需在
AndroidManifest.xml中添加:<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> - 动态路径限制:React Native 的 metro 打包器无法处理完全动态的路径(如
require(./audio/${randomName})),必须提前明确所有需要打包的音频资源。
内容的提问来源于stack exchange,提问作者Mila Oktay
相关产品推荐
相关产品推荐

