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
相关产品推荐
相关产品推荐

