使用expo-av的React Native应用Android12接电话后录音无法恢复
修复Android 12下Expo 45录音应用通话后无声问题
问题根源
Android 12对音频焦点管理和后台音频处理机制做了严格限制,Expo 45内置的expo-av版本未完全适配该变化,导致通话结束后原录音实例无法重新获取音频焦点恢复采集,进而出现持续无声的情况。旧版Android系统的音频焦点逻辑更宽松,所以挂断后能自动恢复。
具体修复方案
1. 监听音频焦点变化,主动暂停/重启录音
利用expo-av的音频焦点监听,在通话触发焦点丢失时暂停录音,焦点恢复时重启录音实例(而非单纯恢复原实例),这是适配Android 12的核心操作:
import { Audio } from 'expo-av'; let currentRecording = null; let wasRecordingBeforeFocusLoss = false; // 初始化音频焦点监听 const setupAudioFocusHandler = () => { Audio.addAudioFocusListener((focusEvent) => { switch(focusEvent.type) { // 音频焦点恢复(通话结束) case Audio.AudioFocusLossType.Gain: if (wasRecordingBeforeFocusLoss) { restartRecording(); wasRecordingBeforeFocusLoss = false; } break; // 临时丢失焦点(通话开始) case Audio.AudioFocusLossType.LossTransient: case Audio.AudioFocusLossType.Loss: if (currentRecording) { pauseRecording(); wasRecordingBeforeFocusLoss = true; } break; } }); }; // 暂停当前录音 const pauseRecording = async () => { try { await currentRecording.pauseAsync(); } catch (err) { console.error('暂停录音失败:', err); // 暂停失败则直接停止实例 await currentRecording.stopAndUnloadAsync(); currentRecording = null; } }; // 重启录音(创建新实例) const restartRecording = async () => { // 清理旧实例 if (currentRecording) { await currentRecording.stopAndUnloadAsync(); currentRecording = null; } // 创建新录制实例并启动 const newRecording = new Audio.Recording(); try { await newRecording.prepareToRecordAsync(Audio.RecordingOptionsPresets.HIGH_QUALITY); await newRecording.startAsync(); currentRecording = newRecording; } catch (err) { console.error('重启录音失败:', err); } };
2. 补充Android 12所需权限
在app.json的Android配置中添加必要权限,确保应用能在后台处理录音和音频焦点:
{ "expo": { "android": { "permissions": [ "RECORD_AUDIO", "FOREGROUND_SERVICE" ] } } }
FOREGROUND_SERVICE:Android 12要求后台录音的应用必须以前台服务运行,避免被系统回收。RECORD_AUDIO:确保麦克风权限正常授予(需在运行时动态请求)。
3. 升级expo-av到Expo 45兼容的最新补丁版
Expo 45对应的expo-av版本为11.x,部分早期版本存在Android 12适配bug,可升级到该分支的最新版本(如11.2.3),执行命令:
expo install expo-av@11.2.3
查看补丁日志,确认是否包含Android 12音频焦点修复。
4. 优化录制配置
在prepareToRecordAsync中明确指定Android相关参数,确保录音实例优先级正确:
const recordingOptions = { ...Audio.RecordingOptionsPresets.HIGH_QUALITY, android: { audioSource: Audio.RECORDING_OPTION_ANDROID_AUDIO_SOURCE_MIC, audioEncoder: Audio.RECORDING_OPTION_ANDROID_AUDIO_ENCODER_AAC, outputFormat: Audio.RECORDING_OPTION_ANDROID_OUTPUT_FORMAT_MPEG_4, }, }; await newRecording.prepareToRecordAsync(recordingOptions);
关键注意事项
- Android 12下,原录音实例在焦点丢失后大概率无法复用,必须创建新实例才能恢复正常录音;
- 若需要拼接通话前后的录音片段,可在暂停时保存旧录音文件路径,结束后通过音频处理工具合并(如expo-av的音频拼接API)。
内容的提问来源于stack exchange,提问作者Grzegorz Brzęczyszczykiewicz
相关产品推荐
相关产品推荐

