2026年Expo开发声音播放App的最新方法,以及如何实现后台播放
1. 技术栈与依赖
本指南基于 Expo SDK 54 + React Native 0.81,使用以下核心库:
| 库 | 用途 |
|---|---|
| expo-audio | 音频文件播放(mp3等) |
| expo-speech | 语音合成播放(TTS) |
安装方式:
npx expo install expo-audio expo-speech
2. 最简单的实现(非Hook方式)
如果不使用React Hook,可以直接创建Player实例:
import { Audio } from 'expo-audio';
const player = new Audio.Player();
await player.loadAsync(require('./sound.mp3'));
player.setIsLoopingAsync(true);
await player.playAsync();
核心API:
loadAsync(source)- 加载音频playAsync()/pauseAsync()/stopAsync()- 播放控制setIsLoopingAsync(true)- 循环播放setVolumeAsync(0.5)- 设置音量
注意:非Hook方式需要手动管理生命周期,在组件卸载时调用 player.unloadAsync() 释放资源。
3. 推荐方式:Hook实现
Expo提供了两个Hook,简化了状态管理和自动清理:
import { useAudioPlayer, useAudioPlayerStatus } from 'expo-audio';
const player = useAudioPlayer(require('./sound.mp3'));
const status = useAudioPlayerStatus(player);
优势:
- 自动订阅播放状态
- 组件卸载时自动清理
- 状态变化触发组件重渲染
4. 音频文件播放
4.1 加载音频
支持多种音频源格式:
// 本地文件
const player = useAudioPlayer(require('./audio.mp3'));
// URL远程音频
const player = useAudioPlayer({ uri: 'https://example.com/audio.mp3' });
4.2 播放控制
// 播放
player.play();
// 暂停
player.pause();
// 停止(回到开头)
player.stop();
// 跳转进度
player.seekTo(60000); // 毫秒,60秒
4.3 循环播放
player.loop = true; // 开启循环
4.4 音量控制
player.volume = 0.5; // 0.0 ~ 1.0
4.5 获取播放状态
const status = useAudioPlayerStatus(player);
if (status?.isPlaying) { /* 正在播放 */ }
if (status?.isBuffering) { /* 缓冲中 */ }
const position = status?.positionMillis; // 当前进度(毫秒)
const duration = status?.durationMillis; // 总时长
5. 语音合成播放
使用 expo-speech 实现TTS:
import * as Speech from 'expo-speech';
Speech.speak('你好,这是语音合成');
5.1 参数配置
Speech.speak('语音内容', {
language: 'zh-CN', // 语言:zh-CN, en-US, ja-JP等
rate: 0.5, // 语速:0.0 ~ 1.0
pitch: 1.0, // 音调:0.0 ~ 2.0
volume: 0.5, // 音量:0.0 ~ 1.0
});
5.2 回调控制
Speech.speak('内容', {
onDone: () => console.log('播放完成'),
onStopped: () => console.log('被停止'),
onError: (e) => console.error('错误', e),
});
5.3 停止播放
Speech.stop(); // 立即停止当前所有语音
6. 后台播放配置(重点)
实现后台播放需要在平台配置和运行时设置两个层面进行配置。
6.1 平台配置
iOS配置(关键)
在 app.json 中添加:
{
"expo": {
"ios": {
"infoPlist": {
"UIBackgroundModes": ["audio"]
}
}
}
}
作用:声明App需要后台音频能力,使系统允许音频在App进入后台时继续播放。
Android配置(简要)
{
"expo": {
"android": {
"permissions": [
"android.permission.FOREGROUND_SERVICE",
"android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK",
"android.permission.WAKE_LOCK"
]
}
}
}
6.2 运行时Audio Mode设置
在App启动时(通常在根Layout或专门初始化文件中)调用:
import { setAudioModeAsync } from 'expo-audio';
await setAudioModeAsync({
allowsRecording: false,
playsInSilentMode: true,
shouldPlayInBackground: true, // 关键:允许后台播放
interruptionMode: 'doNotMix', // 不与其他音频混音
});
参数说明:
| 参数 | 说明 |
|---|---|
shouldPlayInBackground | 必须设为 true,否则App进入后台时音频会停止 |
playsInSilentMode | 静音模式下是否继续播放(iOS) |
interruptionMode | 来电等中断时的处理策略 |
6.3 锁屏Controls与通知栏
让音频在锁屏界面显示播放控制,并支持快捷操作。
6.3.1 启用锁屏控件
player.setActiveForLockScreen(true, {
title: '歌曲标题',
artist: '艺术家',
artwork: require('./cover.png'), // 可选:专辑封面
});
参数说明:
title- 显示标题artist- 艺术家名称artwork- 封面图片(本地require或URL)
6.3.2 更新播放信息
播放过程中可动态更新:
player.updatePlaybackUI({
title: '新标题',
artist: '新艺术家',
});
6.3.3 清除锁屏控件
player.clearLockScreenControls();
6.3.4 锁屏控制事件监听
监听用户在锁屏界面的操作:
player.addOnPlaybackStatusUpdate((status) => {
if (status?.isLoaded) {
// 可根据需要处理
}
});
注意:锁屏控件的底层实现依赖于iOS的
MPNowPlayingInfoCenter和MPRemoteCommandCenter。