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

Android Kotlin最新相机权限适配及startActivityForResult过时问题解决

Android Kotlin 相机权限最新配置与 startActivityForResult 替代方案

一、最新相机相关权限配置

根据Android版本差异,权限申请逻辑需区分处理:

  • Android 13(API 33)及以上:
    • 拍照/录视频:需申请 CAMERA 权限;录视频额外需要 RECORD_AUDIO
    • 读取相册媒体:申请 READ_MEDIA_IMAGES(图片)、READ_MEDIA_VIDEO(视频),无需再申请READ_EXTERNAL_STORAGE
  • Android 12(API 32)及以下:
    • 拍照/录视频:CAMERA + RECORD_AUDIO(录视频时)
    • 读取相册:READ_EXTERNAL_STORAGE

权限申请可通过Activity Result API的RequestMultiplePermissions实现,示例代码:

// 根据系统版本动态生成需要申请的权限列表
private val requiredPermissions: Array<String>
    get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO)
    } else {
        arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_EXTERNAL_STORAGE)
    }

// 注册权限申请结果回调
private val requestPermissionsLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
    val allGranted = permissions.all { it.value }
    if (allGranted) {
        // 权限全部通过,执行对应操作
    } else {
        // 权限被拒绝,提示用户前往设置开启权限
    }
}

// 调用权限申请
fun requestPermissions() {
    requestPermissionsLauncher.launch(requiredPermissions)
}

二、替代 startActivityForResult 的实现方案

AndroidX提供的Activity Result API是官方推荐的替代方案,以下是拍照、录视频、选择相册媒体的具体实现:

1. 拍照功能

使用ActivityResultContracts.TakePicture,需先创建存储照片的文件Uri:

// 创建照片文件Uri(示例用应用外部存储目录)
private fun createImageFileUri(): Uri {
    val imageFileName = "JPEG_${System.currentTimeMillis()}_"
    val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
    val imageFile = File.createTempFile(imageFileName, ".jpg", storageDir)
    return FileProvider.getUriForFile(this, "${packageName}.fileprovider", imageFile)
}

// 注册拍照结果回调
private val takePictureLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
    if (success) {
        // 拍照成功,处理已保存的图片Uri(即createImageFileUri返回的Uri)
    } else {
        // 拍照失败或用户取消操作
    }
}

// 触发拍照
fun takePhoto() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
        val imageUri = createImageFileUri()
        takePictureLauncher.launch(imageUri)
    } else {
        requestPermissions()
    }
}

2. 录视频功能

使用ActivityResultContracts.CaptureVideo,同样需要创建视频文件Uri:

// 创建视频文件Uri
private fun createVideoFileUri(): Uri {
    val videoFileName = "MP4_${System.currentTimeMillis()}_"
    val storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES)
    val videoFile = File.createTempFile(videoFileName, ".mp4", storageDir)
    return FileProvider.getUriForFile(this, "${packageName}.fileprovider", videoFile)
}

// 注册录视频结果回调
private val captureVideoLauncher = registerForActivityResult(ActivityResultContracts.CaptureVideo()) { success ->
    if (success) {
        // 录视频成功,处理视频Uri
    } else {
        // 录视频失败或用户取消操作
    }
}

// 触发录视频
fun recordVideo() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED &&
        ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
        val videoUri = createVideoFileUri()
        captureVideoLauncher.launch(videoUri)
    } else {
        requestPermissions()
    }
}

3. 选择相册媒体

使用ActivityResultContracts.PickVisualMedia(Android 13+推荐)或GetContent兼容低版本:

// 注册选择单张媒体的回调(支持图片/视频)
private val pickMediaLauncher = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
    uri?.let {
        // 选中媒体成功,处理Uri
    } ?: run {
        // 用户取消选择
    }
}

// 触发选择相册媒体
fun pickMediaFromGallery() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        // Android 13+直接调用,已申请READ_MEDIA权限即可
        pickMediaLauncher.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))
    } else {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            // 低版本用GetContent
            val getContentLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
                uri?.let { /* 处理选中的媒体Uri */ }
            }
            getContentLauncher.launch("image/* video/*")
        } else {
            requestPermissions()
        }
    }
}

注意事项

  • 需要在AndroidManifest.xml中注册FileProvider,避免FileUriExposedException:
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
  • 在res/xml目录下创建file_paths.xml,配置文件访问路径:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="my_images" path="Pictures" />
    <external-files-path name="my_videos" path="Movies" />
</paths>

内容的提问来源于stack exchange,提问作者Shubham Sahu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 20:38:18