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

如何使用ZXING与Jetpack Compose实现二维码扫描及现有代码问题修复

ZXING + Jetpack Compose 二维码扫描器实现方案

现有代码问题排查

  • 未绑定CaptureManager和相机视图的生命周期,缺少onResume/onPause/onDestroy对应回调,导致相机资源无法正常加载、出现泄露,预览不生效
  • 未适配动态相机权限申请,Android 6.0及以上系统未授权时相机无法启动
  • 同时调用capture.decode()和decodeContinuous导致解码逻辑冲突,回调重复触发
  • 直接在remember中初始化CompoundBarcodeView,配置变更(如屏幕旋转)时会丢失相机状态,context as Activity的强转也存在崩溃风险

前置配置

  1. 模块级build.gradle引入依赖:
dependencies {
    // ZXING 扫码核心库
    implementation 'com.google.zxing:core:3.5.1'
    // ZXING 安卓视图封装库
    implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
}
  1. AndroidManifest.xml添加权限声明:
<!-- 相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.any" android:required="false" />

完整实现代码

@Composable
fun AdminClubMembershipScanScreen(navController: NavHostController) {
    val context = LocalContext.current
    val activity = LocalContext.current as Activity
    val lifecycleOwner = LocalLifecycleOwner.current
    var scanFlag by remember { mutableStateOf(false) }
    var hasCameraPermission by remember { mutableStateOf(false) }

    // 相机权限申请器
    val cameraPermissionLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.RequestPermission(),
        onResult = { granted ->
            hasCameraPermission = granted
        }
    )

    // 进入页面先申请权限
    LaunchedEffect(key1 = Unit) {
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            hasCameraPermission = true
        } else {
            cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
        }
    }

    if (hasCameraPermission) {
        val compoundBarcodeView = remember {
            CompoundBarcodeView(context).apply {
                setStatusText("")
            }
        }

        val captureManager = remember {
            CaptureManager(activity, compoundBarcodeView).apply {
                initializeFromIntent(activity.intent, null)
                decode()
            }
        }

        // 绑定生命周期回调
        DisposableEffect(key1 = lifecycleOwner) {
            val observer = LifecycleEventObserver { _, event ->
                when (event) {
                    Lifecycle.Event.ON_RESUME -> {
                        compoundBarcodeView.resume()
                        captureManager.onResume()
                    }
                    Lifecycle.Event.ON_PAUSE -> {
                        compoundBarcodeView.pause()
                        captureManager.onPause()
                    }
                    Lifecycle.Event.ON_DESTROY -> {
                        captureManager.onDestroy()
                    }
                    else -> {}
                }
            }
            lifecycleOwner.lifecycle.addObserver(observer)

            // 扫码回调
            compoundBarcodeView.decodeContinuous { result ->
                if (scanFlag) return@decodeContinuous
                scanFlag = true
                result.text?.let { barCodeOrQr ->
                    // 此处处理扫码结果
                    // 处理完成后置为false即可重新扫描,可按需加延迟防抖
                    scanFlag = false
                }
            }

            onDispose {
                lifecycleOwner.lifecycle.removeObserver(observer)
            }
        }

        AndroidView(
            modifier = Modifier.fillMaxSize(),
            factory = { compoundBarcodeView }
        )
    } else {
        // 权限未授予时的提示页面
        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            Text(text = "请授予相机权限后使用扫码功能")
        }
    }
}

功能优化说明

  • 若需要识别一次后停止扫码,拿到结果后直接调用compoundBarcodeView.pause()即可,不需要依赖scanFlag控制
  • 若需要连续扫码,可在拿到结果后加1~2秒延迟再将scanFlag置为false,避免同一张二维码被重复识别
  • 可自定义CompoundBarcodeView的扫描框样式、提示文字等属性,适配设计需求

内容的提问来源于stack exchange,提问作者Kyu-Ho Hwang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:24:04