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

API 29及以上版本下,如何使用Kotlin为MediaStore.ACTION_VIDEO_CAPTURE录制的视频设置预定义存储名称

如何在API 29+下为录制的视频指定预定义名称

在API 29及以上版本,Android引入了分区存储机制,WRITE_EXTERNAL_STORAGE权限不再生效,直接传入文件路径给MediaStore.EXTRA_OUTPUT肯定行不通——因为系统相机应用没有权限访问你指定的普通文件路径。正确的做法是通过MediaStore先在公共媒体库中创建一个带有自定义名称的条目,拿到对应的Content Uri,再把这个Uri传给相机Intent。

下面是完整的实现步骤和代码示例:

步骤1:准备视频存储元数据并插入MediaStore

首先,你需要定义视频的显示名称、存储路径(比如公共DCIM目录下的自定义子文件夹)、MIME类型等信息,然后通过ContentResolver插入到MediaStore.Video.Media.EXTERNAL_CONTENT_URI中,获取对应的Uri。

private fun createCustomVideoUri(displayName: String): Uri? {
    val videoDetails = ContentValues().apply {
        // 设置视频显示名称(就是你想要的预定义名称,记得加.mp4后缀)
        put(MediaStore.Video.Media.DISPLAY_NAME, displayName)
        // 设置MIME类型
        put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
        // 设置存储路径:比如放在DCIM下的MyVideos文件夹,也可以用其他公共目录
        put(
            MediaStore.Video.Media.RELATIVE_PATH,
            Environment.DIRECTORY_DCIM + "/MyVideos"
        )
        // 可选:添加时间戳属性
        put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000)
    }

    return contentResolver.insert(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        videoDetails
    )
}

步骤2:启动相机Intent并传入自定义Uri

接下来,调用createCustomVideoUri生成你想要的Uri,然后传给MediaStore.EXTRA_OUTPUT,再启动相机Intent:

// 定义你想要的预定义文件名,比如加时间戳保证唯一性
val customFileName = "my_recording_${System.currentTimeMillis()}.mp4"
val videoUri = createCustomVideoUri(customFileName) ?: run {
    // 创建Uri失败的错误处理
    Toast.makeText(this, "无法创建视频存储路径", Toast.LENGTH_SHORT).show()
    return
}

val intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE).apply {
    // 设置录制时长限制
    putExtra("android.intent.extra.durationLimit", 5)
    // 传入自定义的Uri
    putExtra(MediaStore.EXTRA_OUTPUT, videoUri)
    // 可选:设置视频质量,1为高质量,0为低质量
    putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
}

// 检查是否有相机应用可以处理该Intent
if (intent.resolveActivity(packageManager) != null) {
    // 旧版API用startActivityForResult
    startActivityForResult(intent, 222)
    // 推荐迁移到Activity Result API,代码更安全:
    // videoCaptureLauncher.launch(intent)
} else {
    Toast.makeText(this, "未找到可用的相机应用", Toast.LENGTH_SHORT).show()
}

步骤3:处理录制结果

如果用的是旧版startActivityForResult,在回调中判断录制状态:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 222) {
        if (resultCode == RESULT_OK) {
            Toast.makeText(this, "视频录制成功", Toast.LENGTH_SHORT).show()
            // 后续可以用videoUri处理视频,比如播放、编辑
        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(this, "录制已取消", Toast.LENGTH_SHORT).show()
            // 用户取消时,删除提前创建的空文件
            contentResolver.delete(videoUri, null, null)
        }
    }
}

如果是用Activity Result API(推荐),代码如下:

private val videoCaptureLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    if (result.resultCode == RESULT_OK) {
        Toast.makeText(this, "视频录制成功", Toast.LENGTH_SHORT).show()
    } else if (result.resultCode == RESULT_CANCELED) {
        Toast.makeText(this, "录制已取消", Toast.LENGTH_SHORT).show()
        contentResolver.delete(videoUri, null, null)
    }
}

关键注意事项

  • 权限要求:不需要WRITE_EXTERNAL_STORAGE,但必须申请CAMERA权限(如果录制带音频,还需要RECORD_AUDIO权限)。Android 13+中这些都是危险权限,需要动态申请。
  • 空文件清理:用户取消录制时,提前创建的空文件会留在存储中,记得在回调中删除。
  • 文件名唯一性:尽量通过时间戳、随机字符串保证文件名唯一,避免覆盖已存在的文件。
  • 存储位置:示例用的是DCIM/MyVideos,你也可以修改RELATIVE_PATH使用其他公共目录,比如Environment.DIRECTORY_MOVIES。

内容的提问来源于stack exchange,提问作者Emrick Liu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 06:17:30