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

Camera LensFacing验证失败,前置摄像头预览拍照异常求助

解决CameraX结合Compose调用前置摄像头的报错问题

问题现象

使用Jetpack CameraX结合Compose调用前置摄像头拍照时,出现以下问题:

  • 日志输出「Camera LensFacing verification failed, existing cameras」错误
  • 无法显示摄像头预览画面
  • 点击拍照按钮触发ImageCaptureException致命异常

报错原因分析

  1. CameraX依赖版本不兼容:camera-view使用了1.3.0-alpha03预览版,而camera-camera2和camera-lifecycle为1.2.1稳定版,版本差异导致初始化逻辑冲突
  2. 前置摄像头选择器匹配失败:默认CameraSelector.DEFAULT_FRONT_CAMERA在部分设备上无法正确识别前置摄像头
  3. 用例绑定逻辑缺陷:LaunchedEffect仅监听previewUseCase变化,可能导致绑定时机不对,且未处理摄像头初始化失败的情况
  4. 拍照逻辑无错误处理:调用takePicture时未捕获异常,导致未绑定摄像头时直接崩溃

修复方案

1. 统一CameraX依赖版本

修改build.gradle中的CameraX依赖,确保所有模块版本一致,使用稳定版:

// Camera
def camerax_version = "1.2.1"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_version" // 统一为1.2.1稳定版

2. 自定义前置摄像头选择器

替换默认选择器,明确指定前置摄像头,提升设备兼容性:

val frontCameraSelector = CameraSelector.Builder()
    .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
    .build()

3. 优化CameraCapture中的用例绑定逻辑

调整LaunchedEffect的触发条件,确保摄像头提供者初始化完成后再绑定用例,同时处理绑定失败的情况:

@ExperimentalPermissionsApi
@ExperimentalCoroutinesApi
@Composable
fun CameraCapture(
    modifier: Modifier = Modifier,
    onImageFile: (File) -> Unit = { }
) {
    val context = LocalContext.current
    val frontCameraSelector = remember {
        CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
            .build()
    }

    Permission(
        permission = Manifest.permission.CAMERA,
        rationale = "You said you wanted a picture, so I'm going to have to ask for permission.",
        permissionNotAvailableContent = {
            Column(modifier) {
                Text("O noes! No Camera!")
                Spacer(modifier = Modifier.height(8.dp))
                Button(
                    onClick = {
                        context.startActivity(
                            Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
                                data = Uri.fromParts("package", context.packageName, null)
                            }
                        )
                    }
                ) {
                    Text("Open Settings")
                }
            }
        }
    ) {
        Box(modifier = modifier) {
            val lifecycleOwner = LocalLifecycleOwner.current
            val coroutineScope = rememberCoroutineScope()
            var previewUseCase by remember { mutableStateOf<UseCase?>(null) }
            val imageCaptureUseCase = remember {
                ImageCapture.Builder()
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
                    .build()
            }

            CameraPreview(
                modifier = Modifier.fillMaxSize(),
                onUseCase = { useCase ->
                    previewUseCase = useCase
                }
            )

            Button(
                modifier = Modifier
                    .wrapContentSize()
                    .padding(16.dp)
                    .align(Alignment.BottomCenter),
                onClick = {
                    coroutineScope.launch {
                        try {
                            val file = File(context.externalCacheDir, "${System.currentTimeMillis()}.jpg")
                            imageCaptureUseCase.takePicture(
                                ImageCapture.OutputFileOptions.Builder(file).build(),
                                ContextCompat.getMainExecutor(context),
                                object : ImageCapture.OnImageSavedCallback {
                                    override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                                        onImageFile(file)
                                    }

                                    override fun onError(exception: ImageCaptureException) {
                                        Log.e("CameraCapture", "Take picture failed", exception)
                                    }
                                }
                            )
                        } catch (e: Exception) {
                            Log.e("CameraCapture", "Take picture error", e)
                        }
                    }
                }
            ) {
                Text("Click!")
            }

            // 监听previewUseCase和cameraProvider初始化完成
            LaunchedEffect(previewUseCase) {
                previewUseCase ?: return@LaunchedEffect
                val cameraProvider = try {
                    context.getCameraProvider()
                } catch (e: Exception) {
                    Log.e("CameraCapture", "Failed to get camera provider", e)
                    return@LaunchedEffect
                }

                try {
                    cameraProvider.unbindAll()
                    cameraProvider.bindToLifecycle(
                        lifecycleOwner, frontCameraSelector, previewUseCase, imageCaptureUseCase
                    )
                } catch (ex: Exception) {
                    Log.e("CameraCapture", "Failed to bind camera use cases", ex)
                }
            }
        }
    }
}

4. 完善拍照逻辑的错误处理

在拍照时添加异常捕获,避免崩溃(已包含在上述代码中)

验证结果

修复后:

  • 正常获取前置摄像头预览画面
  • 点击拍照按钮可成功捕获图片并显示
  • 无「Camera LensFacing verification failed」错误
  • 拍照时的异常被正确捕获,不会触发致命崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 08:30:50