React Native音效板开发中expo-av调用Audio.sound.createAsync报错无法播放音频
报错核心原因
你遇到的未处理Promise拒绝和state赋值时机无关,触发报错的根源有两点:
- API拼写错误导致属性访问失败
你代码中调用的Audio.sound.createAsync在expo-av的导出对象中不存在,正确的静态方法挂载在Audio.Sound.createAsync(注意Sound为大写S)。JS在执行时找不到Audio对象上的sound属性,直接抛出undefined类型的访问错误,这就是报错信息中提示evaluating '_expoAv.Audio.sound.createAsync'的直接原因——代码根本没有走到赋值、播放音频的步骤,在属性访问阶段就已经中断了。 - 未完成音频模块初始化
缺少对expo-av的播放模式配置,部分iOS/Android真机环境下就算修正拼写错误,也会因为没有获取音频播放权限抛出异步错误。
分步修复方案
- 修正API调用的大小写错误:将
Audio.sound.createAsync替换为Audio.Sound.createAsync - 补充组件挂载时的音频初始化逻辑,适配移动端的播放权限规则
- 将
sound状态的初始值从空字符串改为null,避免空字符串被判定为truthy导致卸载逻辑误执行 - 给所有异步音频操作补全try/catch块,捕获权限不足、资源加载失败等异常,避免未处理Promise打断应用运行
- 优化按钮绑定逻辑,给不同触控按钮传入对应的音效资源路径,实现不同按钮播放不同音效的效果
核心修复代码片段
import { StatusBar } from "expo-status-bar"; import React, { useState, useEffect } from "react"; import { StyleSheet, Text, View, TouchableOpacity } from "react-native"; import { Feather } from "@expo/vector-icons"; import { Audio } from "expo-av"; export default function App() { // 初始值改为null,替代原有的空字符串 const [sound, setSound] = useState(null); // 组件挂载时初始化音频播放模式 useEffect(() => { const setupAudio = async () => { await Audio.setAudioModeAsync({ playsInSilentModeIOS: true, // 支持静音模式下播放 staysActiveInBackground: false, shouldDuckAndroid: false, }); }; setupAudio(); }, []); // 给函数传入需要播放的音频资源路径,支持多按钮绑定不同音效 const playSound = async (audioResource) => { try { console.log("Loading Sound"); // 修正大写的Sound,替代原有的小写sound调用 const { sound: audioInstance } = await Audio.Sound.createAsync( audioResource, { shouldPlay: true } ); // 卸载上一个正在播放的音频实例,避免多音频叠加 if (sound) { await sound.unloadAsync(); } setSound(audioInstance); console.log("playing sound"); } catch (error) { console.log("音频播放异常:", error); } }; // 组件卸载时清理音频资源 useEffect(() => { return sound ? () => { console.log("unloading the sound"); sound.unloadAsync(); } : undefined; }, [sound]); return ( <View style={styles.container}> <Text>SoundGround</Text> <View style={{ flexDirection: "row" }}> <TouchableOpacity onPress={() => playSound(require("./assets/Ayo.mp3"))} > <Feather name="arrow-left" style={styles.iconStyle} /> </TouchableOpacity> {/* 右按钮可以绑定对应路径的其他音效资源 */} <TouchableOpacity onPress={() => playSound(require("./assets/你的另一个音效.mp3"))} > <Feather name="arrow-right" style={styles.iconStyle} /> </TouchableOpacity> </View> <StatusBar style="auto" /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center", }, iconStyle: { fontSize: 100, }, });
内容的提问来源于stack exchange,提问作者skumar
相关产品推荐
相关产品推荐

