Android开发中如何将MediaRecorder录制文件默认保存到系统Music文件夹
实现将录制音频保存到系统公共Music目录的方案
前置说明
Android 10(API 29)开始引入分区存储机制,公共目录的读写需要通过MediaStore API完成,不需要申请存储权限;Android 9及以下版本需要申请WRITE_EXTERNAL_STORAGE权限才能访问公共存储目录。
步骤1:配置AndroidManifest权限
<!-- 录音权限(所有版本都需要,且需要动态申请) --> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- Android 9及以下需要存储写入权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
步骤2:修改文件名与路径生成逻辑
替换原来的应用私有目录逻辑,分系统版本生成公共Music目录的存储路径/Uri:
// 全局变量,保存Android 10+的音频文件Uri private var savedAudioUri: Uri? = null // 全局变量,保存Android 9及以下的文件绝对路径 private var fileName: String? = null private fun confirmEditText(v: TextView, actionId: Int, event: KeyEvent?): Boolean { if (actionId == EditorInfo.IME_ACTION_DONE) { val inputName = v.text.toString().trim() if (inputName.isEmpty()) { Toast.makeText(this, "Empty File Name", Toast.LENGTH_LONG).show() } else { val fullFileName = "$inputName.wav" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android 10+ 向MediaStore插入音频记录,指定保存到Music目录 val values = ContentValues().apply { put(MediaStore.Audio.Media.DISPLAY_NAME, fullFileName) put(MediaStore.Audio.Media.TITLE, inputName) put(MediaStore.Audio.Media.MIME_TYPE, "audio/wav") put(MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC) put(MediaStore.Audio.Media.IS_PENDING, 1) // 录制中标记为待处理,避免其他应用访问 } savedAudioUri = contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values) } else { // Android 9及以下直接获取公共Music目录路径 val publicMusicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) if (!publicMusicDir.exists()) publicMusicDir.mkdirs() fileName = File(publicMusicDir, fullFileName).absolutePath } } } return false }
步骤3:修改MediaRecorder初始化逻辑
注意:你原有代码中setOutputFormat(AudioFormat.ENCODING_PCM_16BIT)是错误用法,ENCODING_PCM_16BIT是音频编码参数,不是输出格式常量,会导致初始化失败,下面给出修正后的代码:
try { mediaRecorder = MediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.UNPROCESSED) // 适配编码器设置输出格式,AMR_NB编码器对应THREE_GPP格式 setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP) setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB) // 设置输出目标 when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> { savedAudioUri?.let { uri -> contentResolver.openFileDescriptor(uri, "w")?.use { pfd -> setOutputFile(pfd.fileDescriptor) } } } else -> setOutputFile(fileName) } prepare() } } catch (e: Exception) { e.printStackTrace() // 初始化失败清理占位的音频记录 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { savedAudioUri?.let { contentResolver.delete(it, null, null) } } }
步骤4:新增录制完成后的收尾逻辑
private fun stopRecord() { mediaRecorder?.run { stop() release() } mediaRecorder = null // Android 10+ 取消待处理标记,使文件对其他应用可见 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { savedAudioUri?.let { uri -> val values = ContentValues().apply { put(MediaStore.Audio.Media.IS_PENDING, 0) } contentResolver.update(uri, values, null, null) } } }
注意事项
- 若你确实需要输出标准WAV格式文件,MediaRecorder原生不支持直接生成带WAV头的文件,建议改用AudioRecord录制原始PCM流,录制完成后手动写入WAV头再保存。
RECORD_AUDIO属于危险权限,必须在运行时向用户申请授权,确认用户同意后才能初始化MediaRecorder开始录制。
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

