You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 11:27:03