react-native-audio-recorder-player调用stopRecorder()安卓真机崩溃排查与解决
问题分析与解决方案
我之前也碰到过类似的Android真机录制崩溃问题,结合你的代码和环境配置,梳理出几个核心原因及对应的解决办法:
1. 存储路径硬编码+编码格式不匹配
你的Android路径用了sdcard/audio-${new Date().getTime()}.mp3,这里有两个明显的问题:
- 路径兼容性差:不同Android设备的外部存储路径并不统一,直接写
sdcard/在部分机型上会触发找不到路径的错误;而且Android 10+的Scoped Storage机制限制了直接访问根目录,容易引发权限或IO异常。 - 编码与容器格式不兼容:你设置的编码是
AudioEncoderAndroidType.AAC,但输出文件后缀是.mp3——AAC编码的音频和MP3容器格式不匹配,Android的MediaRecorder在停止录制时很可能因为格式解析错误直接崩溃。
解决办法:
- 改用标准存储路径,推荐借助
react-native-fs库获取兼容的目录:import RNFS from 'react-native-fs'; const path = Platform.select({ ios: `audio-${new Date().getTime()}.m4a`, android: `${RNFS.ExternalDirectoryPath}/audio-${new Date().getTime()}.m4a` }); - 保持编码和后缀一致:AAC编码对应
.m4a或.aac后缀;如果一定要用MP3,需要将AudioEncoderAndroid改为AudioEncoderAndroidType.MPEG_4(注意:部分Android设备可能不支持MP3编码)。
2. 监听器移除方式错误
你调用audioRecorderPlayer.removeRecordBackListener()时没有传入监听器的引用ID,这个库的addRecordBackListener会返回一个唯一监听ID,直接调用无参的移除方法可能无法正确清理监听器,进而引发内存泄漏或录制停止时的崩溃。
解决办法:
用useRef保存监听器ID,移除时精准传入:
import { useRef } from 'react'; // 组件内定义引用 const recordListenerRef = useRef(null); // 启动录制函数 async function handleRecord() { try { // ... 权限校验、路径配置、audioSet逻辑 ... const result = await audioRecorderPlayer.startRecorder(path, audioSet); setRecord(true); // 保存监听器ID recordListenerRef.current = audioRecorderPlayer.addRecordBackListener(e => { // 可留空,但建议不要直接return,比如打印下进度便于调试 // console.log('录制进度:', e.current_position); return; }); } catch (err) { console.error('启动录制失败:', err); } } // 停止录制函数 async function onStopRecord() { try { // 先移除监听器再停止录制 if (recordListenerRef.current) { audioRecorderPlayer.removeRecordBackListener(recordListenerRef.current); recordListenerRef.current = null; } const result = await audioRecorderPlayer.stopRecorder(); setRecord(false); setFiles([ ...files, { uri: result, type: "audio/m4a", name: `audio-${new Date().getTime()}.m4a` } ]); }catch(error){ Alert.alert( "Erro", error.message || JSON.stringify(error) ); } }
3. 库版本兼容性问题
你使用的react-native-audio-recorder-player@2.6.0-rc3是候选发布版本,本身可能存在未修复的bug;再加上你的React Native版本是0.63.3(相对老旧),两者的兼容性适配可能存在漏洞,这在Android真机上更容易暴露。
解决办法:
- 升级到该库的正式稳定版,比如
2.6.0正式版(查看库的Release Notes确认适配RN0.63.x); - 如果升级后问题依旧,可尝试降级到
2.5.x版本,这个版本适配旧RN版本的稳定性更好。
4. 权限申请不完整
虽然你调用了getPermissions(),但可能没覆盖Android全版本的权限要求:
- 确保
AndroidManifest.xml中添加了必要权限:<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> - 针对Android 10+,要确保动态权限申请逻辑正确获取到了存储权限,避免因权限不足导致录制停止时的IO异常。
建议先从路径和格式匹配入手调试,这是最常见的崩溃诱因,再依次排查监听器、库版本和权限问题,应该能解决Android真机上的崩溃问题。
内容的提问来源于stack exchange,提问作者AlecsanderFarias




