Jetpack Compose中ActivityResultContracts.TakePicture始终返回false求助
问题根源
你传入cameraLauncher.launch()的是Uri.EMPTY,ActivityResultContracts.TakePicture要求必须传入可被相机应用写入的有效Uri,空Uri会导致拍照后无法保存照片,最终回调返回false。
解决步骤
1. 配置FileProvider(Android 7.0+必做)
因为Android 7.0及以上禁止直接使用file://格式的Uri,必须通过FileProvider生成安全的内容Uri:
- 在
AndroidManifest.xml的<application>标签内注册FileProvider:
<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"> <!-- 指向应用外部私有存储的Pictures目录 --> <external-files-path name="camera_photos" path="Pictures" /> </paths>
2. 修改Composable代码,生成有效Uri
替换原来的空Uri初始化,动态生成可写入的图片Uri:
@OptIn(ExperimentalPermissionsApi::class) @Composable fun SomeScreen(context: Context = LocalContext.current) { // 生成用于保存照片的有效Uri,用remember避免重组时重复创建 val photoUri by remember { mutableStateOf(createCameraPhotoUri(context)) } val cameraLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.TakePicture(), onResult = { success -> if (success) { println("success") println("photo uri: $photoUri") } else println("result failed") } ) val cameraPermissionState = rememberPermissionState( permission = Manifest.permission.CAMERA, onPermissionResult = { granted -> if (granted) cameraLauncher.launch(photoUri) else print("camera permission is denied") } ) Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Button(onClick = cameraPermissionState::launchPermissionRequest) { Text(text = "Take a photo with Camera") } } } // 生成相机拍照用的Uri工具方法 private fun createCameraPhotoUri(context: Context): Uri { val imageFileName = "PHOTO_${System.currentTimeMillis()}.jpg" // 应用私有外部存储目录,无需额外存储权限(Android 10+) val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) val imageFile = File(storageDir, imageFileName) return FileProvider.getUriForFile( context, "${context.packageName}.fileprovider", // 与Manifest中authorities一致 imageFile ) }
3. 额外注意事项
- 若目标设备是Android 9及以下,还需要在
AndroidManifest.xml中添加WRITE_EXTERNAL_STORAGE权限,并在代码中动态请求该权限; - 确保
file_paths.xml的路径配置正确,上述示例使用的是应用私有外部存储,不会涉及公共存储的权限问题。
内容的提问来源于stack exchange,提问作者Assis
相关产品推荐
相关产品推荐

