Android 同时扫描多个二维码(非zxing)

3,414 阅读1分钟

基于google机器学习MlKit-barcode-scannin,androidx的CameraX进行开发

添加依赖

dependencies{
    ...
    implementation 'androidx.camera:camera-camera2:1.0.0'
    implementation 'androidx.camera:camera-lifecycle:1.0.0'
    implementation 'androidx.camera:camera-view:1.0.0-alpha24'
    implementation 'com.google.mlkit:barcode-scanning:16.1.2'
}

添加权限

    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-feature android:name="android.hardware.camera.any" />

布局


    <androidx.camera.view.PreviewView
        android:id="@+id/viewFinder"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
        

核心代码

解析器


class QRCodeAnalyzer(private val listener: (List<Barcode>) ->Unit) : ImageAnalysis.Analyzer {
    @SuppressLint("UnsafeExperimentalUsageError")
    override fun analyze(imageProxy: ImageProxy) {
        val mediaImage = imageProxy.image
        if (mediaImage != null) {
            val image =
                InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
            processImage(image = image, imageProxy = imageProxy)
        }

    }

    private val options = BarcodeScannerOptions.Builder()
         //设置扫码类型,支持同时设置多个
        .setBarcodeFormats(Barcode.FORMAT_QR_CODE)
        .build()
    private val scanner = BarcodeScanning.getClient(options)

    private fun processImage(image: InputImage, imageProxy: ImageProxy) {
        scanner.process(image)
            .addOnSuccessListener(listener)
            .addOnFailureListener {
                // Do nothing
            }
            .addOnCompleteListener {
                imageProxy.close()
            }
    }
}

初始化

// 解析数据 Executor
private val cameraExecutor by lazy {
    Executors.newSingleThreadExecutor()
}

private val viewFinder by lazy {
    requireView().findViewById<PreviewView>(R.id.viewFinder)!!
}

// 初始化相机和扫码
private fun startCamera() {
    val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())

    cameraProviderFuture.addListener({
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
        // Preview
        val preview = Preview.Builder()
            .build()
            .also {
                it.setSurfaceProvider(viewFinder.surfaceProvider)
            }

        // 默认选择后摄
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
        val imageAnalyzer = ImageAnalysis.Builder()
            .build()
            .also {
                it.setAnalyzer(cameraExecutor, QRCodeAnalyzer { luma ->
                    // 扫码结果,这里需根据项目做去重处理
                    Log.d(TAG, "Average luminosity: $luma")
                })
            }

        try {
            // Unbind use cases before rebinding
            cameraProvider.unbindAll()

            // Bind use cases to camera
            cameraProvider.bindToLifecycle(
                this, cameraSelector, preview, imageAnalyzer
            )

        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }

    }, ContextCompat.getMainExecutor(requireContext()))
}

简单说明

使用mlkit进行扫码本身就支持同时扫描多个码,所以不用过多处理。代码相对使用zxing简单很多,而且效率也非常高。

演示

这里用官方的代码进行了修改,添加了绘制结果框,并对结果进行了模拟上传,框颜色和当前上传状态有关。 WechatIMG341.jpeg