<p>This post is about, how to implement Barcode scanning using Google<a href="https://developers.google.com/ml-kit/vision/barcode-scanning"><span style="color: #008000;"><strong> ML Kit&#8217;s Barcode Scanning API</strong></span> </a>and Jetpack <strong><span style="color: #008000;"><a style="color: #008000;" href="https://developer.android.com/training/camerax">CameraX</a></span></strong> with the help of simple application. </p> 
 
 
 
<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-block-buttons-is-layout-flex"> 
<div class="wp-block-button"><a class="wp-block-button__link has-white-color has-text-color has-background" style="background-color: #0e0340;" href="https://github.com/arunk7839/BarcodeScannerExp"><strong>DOWNLOAD CODE</strong></a></div> 
</div> 
 
 
 
<h4 class="wp-block-heading"> </h4> 
<p><amp-youtube layout="responsive" width="1200" height="675" data-videoid="uUlUrwAxqgU" title="Android Scanning Barcode/QR code using Google ML Kit and CameraX"><a placeholder href="https://youtu.be/uUlUrwAxqgU"><img src="https://i.ytimg.com/vi/uUlUrwAxqgU/hqdefault.jpg" layout="fill" object-fit="cover" alt="Android Scanning Barcode/QR code using Google ML Kit and CameraX"></a></amp-youtube></p> 
<h4><strong><span style="color: #000080;">CameraX</span></strong></h4> 
 
 
 
<p><span style="color: #008000;"><strong>CameraX</strong></span> is a Jetpack support library, built to help you make camera app development easier.</p> 
<p>It is based on <span style="color: #008000;"><strong>use cases </strong><span style="color: #008000;"><span style="color: #000000;">that is</span> <strong>lifecycle-aware</strong></span></span>. These use cases work across all devices running Android 5.0 (API level 21) or higher, ensuring that the same code works on most devices.</p> 
<p>CameraX introduces the following use cases:</p> 
<ul> 
<li><strong><span style="color: #0000ff;">Preview</span></strong>: get an image on the display.</li> 
<li><span style="color: #0000ff;"><strong>Image analysis:</strong></span> access a buffer seamlessly for use in your algorithms, such as to pass into ML Kit (we will use it to detect barcode).</li> 
<li><strong><span style="color: #0000ff;">Image capture</span></strong>: save high-quality images.</li> 
</ul> 
 
 
 
<h4 class="wp-block-heading"><strong><span style="color: #000080;">Google ML Kit</span></strong></h4> 
 
 
 
<p><strong><span style="color: #008000;">ML Kit</span></strong> is a cross-platform mobile SDK (Android and iOS) developed by Google that allows developers to easily access on-device mobile machine learning models.<br />All the ML Kit’s APIs run on-device, allowing real-time and offline capabilities.</p> 
 
 
 
<h4 class="wp-block-heading"><span style="color: #000080;"><strong>ML Kit’s Barcode Scanning API</strong></span></h4> 
 
 
 
<p>ML Kit&#8217;s barcode scanning API, allows you to recognize and decode barcodes.</p> 
 
 
 
<p><span style="color: #0000ff;"><strong>Key Feature</strong></span></p> 
 
 
 
<ul class="wp-block-list"> 
<li>It reads most standard formats including Codabar, Code 39, Code 93, EAN-8, EAN-13, QR code, PDF417, and more.</li> 
<li>Automatically Scan for all supported barcode formats.</li> 
<li>Barcodes are recognized and scanned regardless of their orientation(right-side-up, upside-down, or sideways).</li> 
<li>Barcode scanning happens on the device, and doesn&#8217;t require a network connection.</li> 
</ul> 
 
 
 
<p>There are two ways to integrate barcode scanning in your app:</p> 
 
 
 
<ul class="wp-block-list"> 
<li><strong><span style="color: #0000ff;">bundled model</span> </strong>: part of your application.</li> 
<li><strong><span style="color: #0000ff;">unbundled model</span></strong> : depends on Google Play Services.</li> 
</ul> 
 
 
 
 
 
<h4 class="wp-block-heading"><span style="color: #000080;"><strong>Creating new project</strong></span></h4> 
 
 
 
<p>1 . Create a new project by going to <span style="color: #008000;"><b>File </b><span class="s1"><b>⇒</b></span></span><b><span style="color: #008000;"> New Android Project</span>,</b> select <span style="color: #008000;"><strong>Empty Activity</strong> ,</span> provide <span style="color: #008000;"><strong>app name</strong></span>, select language to <strong><span style="color: #008000;">kotlin</span> </strong>and then finally click on <span style="color: #0000ff;"><strong>finish</strong></span>.</p> 
 
 
 
<p>2 . Open the <span style="color: #008000;"><strong><span class="s1">build.gradle (Module: app)</span></strong></span> file and add the below dependencies inside the <strong><span style="color: #008000;">dependencies</span></strong> section:</p> 
<p><span style="color: #0000ff;"> <strong><span class="s1">build.gradle</span></strong></span></p> 
 
 
 
<pre class="wp-block-preformatted">dependencies { 
 var camerax_version = "1.0.2" 
 
<strong><span style="color: #008000;"> // ViewModel and LiveData 
</span></strong> implementation "androidx.lifecycle:lifecycle-livedata:2.4.0" 
 implementation "androidx.lifecycle:lifecycle-viewmodel:2.4.0" 
 
<strong><span style="color: #008000;"> // Use this dependency for bundled model 
</span></strong> implementation 'com.google.mlkit:barcode-scanning:17.0.0' 
 
<strong><span style="color: #008000;"> // CameraX library 
</span></strong> implementation("androidx.camera:camera-camera2:${camerax_version}") 
<strong><span style="color: #008000;"> // CameraX Lifecycle library 
</span></strong> implementation("androidx.camera:camera-lifecycle:${camerax_version}") 
<strong><span style="color: #008000;"> // CameraX View class 
</span></strong> implementation("androidx.camera:camera-view:1.0.0-alpha30") 
}</pre> 
 
 
 
<p>3 . Open your <span style="color: #008000;"><strong class="hn lp">AndroidManifest.xml</strong> </span>file and add camera permission and camera hardware feature above <strong><span style="color: #008000;"><;application>;</span></strong> tag.</p> 
 
 
 
<pre class="wp-block-preformatted"><;uses-feature android:name="android.hardware.camera"/>; 
<;uses-permission android:name="android.permission.CAMERA" />;</pre> 
 
 
 
<p>4. Add <span style="color: #008000;"><strong>PreviewView</strong></span> and a TextView (to show scanned data) to the main activity layout (activity_main.xml).</p> 
<p><strong><span style="color: #0000ff;">PreviewView</span></strong> : Custom View that displays the camera feed for CameraX’s <span style="color: #008000;"><strong>Preview</strong></span> use case. </p> 
 
 
 
<pre class="wp-block-preformatted"><;?xml version="1.0" encoding="utf-8"?>; 
<;androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 xmlns:app="http://schemas.android.com/apk/res-auto" 
 xmlns:tools="http://schemas.android.com/tools" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 tools:context=".MainActivity">; 
 
 <span style="color: #008000;"><strong><;androidx.camera.view.PreviewView 
 android:id="@+id/preview_view" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" />;</strong></span> 
 
 <;TextView 
 android:id="@+id/tvScannedData" 
 android:layout_width="match_parent" 
 android:layout_height="wrap_content" 
 android:layout_marginLeft="10dp" 
 android:layout_marginRight="10dp" 
 android:layout_marginBottom="50dp" 
 android:gravity="center" 
 android:textColor="@android:color/white" 
 android:textSize="20sp" 
 app:layout_constraintBottom_toBottomOf="parent" 
 app:layout_constraintEnd_toEndOf="parent" 
 app:layout_constraintHorizontal_bias="0.5" 
 app:layout_constraintStart_toStartOf="parent" />; 
 
<;/androidx.constraintlayout.widget.ConstraintLayout>;</pre> 
 
 
 
 
 
<p>5 . Now we need to check camera permission, here’s a code to check if camera permission was granted and request it.</p> 
 
 
 
<pre class="wp-block-preformatted">class MainActivity : AppCompatActivity() { 
 override fun onCreate(savedInstanceState: Bundle?) { 
 super.onCreate(savedInstanceState) 
 setContentView(R.layout.activity_main) 
 
 if (isCameraPermissionGranted()) { 
<strong><span style="color: #008000;"> // startCamera 
</span></strong> } else { 
 ActivityCompat.requestPermissions( 
 this, 
 arrayOf(Manifest.permission.CAMERA), 
 PERMISSION_CAMERA_REQUEST 
 ) 
 } 
 } 
 
 override fun onRequestPermissionsResult( 
 requestCode: Int, 
 permissions: Array<;String>;, 
 grantResults: IntArray 
 ) { 
 if (requestCode == PERMISSION_CAMERA_REQUEST) { 
 if (isCameraPermissionGranted()) { 
<strong><span style="color: #008000;"> // start camera 
</span></strong> } else { 
 Log.e(TAG, "no camera permission") 
 } 
 } 
 super.onRequestPermissionsResult(requestCode, permissions, grantResults) 
 } 
 
 private fun isCameraPermissionGranted(): Boolean { 
 return ContextCompat.checkSelfPermission( 
 baseContext, 
 Manifest.permission.CAMERA 
 ) == PackageManager.PERMISSION_GRANTED 
 } 
 
 companion object { 
 private val TAG = MainActivity::class.java.simpleName 
 private const val PERMISSION_CAMERA_REQUEST = 1 
 } 
}</pre> 
 
 
 
<h4 class="wp-block-heading"><span style="color: #000080;"><strong>Getting ProcessCameraProvider from ViewModel </strong></span></h4> 
 
 
 
<p>6 . Create a new class <span style="color: #008000;"><strong>CameraXViewModel</strong></span> which extends <strong><span style="color: #008000;">AndroidViewModel</span></strong> and add the below code.</p>
<!-- WP QUADS Content Ad Plugin v. 2.0.98.1 -->
<div class="quads-location quads-ad2" id="quads-ad2" style="float:none;margin:0px;">

</div>
 
<p><span style="color: #0000ff;"><strong>CameraXViewModel.kt</strong></span></p> 
 
 
 
<pre class="wp-block-preformatted">class CameraXViewModel(application: Application) : AndroidViewModel(application) {<br /> 
 private var cameraProviderLiveData: MutableLiveData<;ProcessCameraProvider>;? = null 
 
 val processCameraProvider: LiveData<;ProcessCameraProvider>; 
 get() { 
 if (cameraProviderLiveData == null) { 
 cameraProviderLiveData = MutableLiveData() 
 val cameraProviderFuture = 
 ProcessCameraProvider.getInstance(getApplication()) 
 cameraProviderFuture.addListener( 
 Runnable { 
 try { 
 cameraProviderLiveData!!.setValue(cameraProviderFuture.get()) 
 } catch (e: ExecutionException) { 
 Log.e(TAG, "Unhandled exception", e) 
 } 
 }, 
 ContextCompat.getMainExecutor(getApplication()) 
 ) 
 } 
 return cameraProviderLiveData!! 
 } 
 
 companion object { 
 private const val TAG = "CameraXViewModel" 
 } 
}</pre> 
 
 
 
<ul> 
<li><span style="color: #0000ff;"><strong>processCameraProvider </strong></span>: a livedata instance of <span style="color: #008000;"><strong>ProcessCameraProvider</strong></span>. <span style="color: #000000;">ProcessCameraProvider</span> is used to bind the lifecycle of cameras to the lifecycle owner. This allows you to not worry about opening and closing the camera since CameraX is lifecycle aware.</li> 
</ul> 
 
 
 
<ul> 
<li><span style="color: #0000ff;"><strong>cameraProviderFuture.addListener()</strong></span>: Adds a listener to the <strong><span style="color: #008000;">cameraProviderFuture</span></strong>. It takes <span style="color: #0000ff;"><strong><span class="s2">Runnable</span></strong></span> as one argument ( set cameraProviderLiveData value get from cameraProviderFuture ) and <span style="color: #0000ff;"><strong><a style="color: #0000ff;" href="https://developer.android.com/reference/kotlin/androidx/core/content/ContextCompat"><span class="s3">ContextCompat</span></a><span class="s3">.getMainExecutor()</span></strong></span> as the second argument ( returns an <strong><a href="https://developer.android.com/reference/java/util/concurrent/Executor"><span class="s3">Executor</span></a></strong> that runs on the main thread).</li> 
</ul> 
 
 
 
<p>7 . Now in MainActivity, to observe the livedata instance of <strong>ProcessCameraProvider </strong>defined in CameraXViewModel add the below code:</p> 
 
 
 
<pre class="wp-block-preformatted">private var previewView: PreviewView? = null 
private var cameraProvider: ProcessCameraProvider? = null 
private var cameraSelector: CameraSelector? = null 
 
previewView = findViewById(R.id.preview_view) 
cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build() 
ViewModelProvider( 
this, ViewModelProvider.AndroidViewModelFactory.getInstance(application) 
).get(CameraXViewModel::class.java) 
.processCameraProvider 
.observe(this) { provider: ProcessCameraProvider? ->; 
 cameraProvider = provider 
 if (isCameraPermissionGranted()) { 
 <strong><span style="color: #0000ff;">bindPreviewUseCase() 
 bindAnalyseUseCase()</span></strong> 
 } else { 
 ActivityCompat.requestPermissions( 
 this, 
 arrayOf(Manifest.permission.CAMERA), 
 PERMISSION_CAMERA_REQUEST 
 ) 
 } 
}</pre> 
 
 
 
<h4 class="wp-block-heading"><strong><span style="color: #000080;">Implement Preview Use Case</span></strong></h4> 
 
 
 
 
 
<p>8 . Create new function <span style="color: #008000;"><strong>bindPreviewUseCase() </strong><span style="color: #000000;">to implement preview use case. </span></span>Inside <span style="color: #008000;"><strong>bindPreviewUseCase() </strong></span>block, make sure nothing is bound to your cameraProvider, and then bind your cameraSelector and preview object to the ProcessCameraProvider instance. </p> 
 
 
 
<pre class="wp-block-preformatted">private fun bindPreviewUseCase() { 
 
 if (previewUseCase != null) { 
 cameraProvider!!.unbind(previewUseCase) 
 } 
 
 previewUseCase = Preview.Builder() 
 .setTargetRotation(previewView!!.display.rotation) 
 .build()<br /><br /><strong><span style="color: #008000;">//Attach the PreviewView surface provider to the preview use case. 
</span></strong> previewUseCase!!.setSurfaceProvider(previewView!!.surfaceProvider) 
 
 try { 
 cameraProvider!!.bindToLifecycle( 
 this, 
 cameraSelector!!, 
 previewUseCase 
 ) 
 } catch (illegalStateException: IllegalStateException) { 
 Log.e(TAG, illegalStateException.message ?: "IllegalStateException") 
 } catch (illegalArgumentException: IllegalArgumentException) { 
 Log.e(TAG, illegalArgumentException.message ?: "IllegalArgumentException") 
 } 
}</pre> 
 
 
 
<h4 class="wp-block-heading"><strong><span style="color: #000080;">Implement ImageAnalysis Use Case</span></strong></h4> 
 
 
 
<p>9 . Create new function <span style="color: #008000;"><strong>bindAnalyseUseCase()</strong></span> to implement analyze use case. Inside <span style="color: #008000;"><strong>bindAnalyseUseCase() </strong><span style="color: #000000;">block</span><strong>,</strong></span> create BarcodeScanner instance , instantiate ImageAnalysis instance and setAnalyzer.</p> 
 
 
 
<pre class="wp-block-preformatted">private fun bindAnalyseUseCase() { 
 <strong><span style="color: #008000;"> // Note that if you know which format of barcode your app is dealing with, </span></strong><br /><strong><span style="color: #008000;"> // detection will be faster</span> </strong> 
 val options = BarcodeScannerOptions.Builder() 
 .setBarcodeFormats(Barcode.FORMAT_ALL_FORMATS).build() 
 
 val barcodeScanner: BarcodeScanner = BarcodeScanning.getClient(options)<br /> 
 analysisUseCase = ImageAnalysis.Builder() 
 .setTargetRotation(previewView!!.display.rotation) 
 .build() 
 
 // Initialize our background executor 
 val cameraExecutor = Executors.newSingleThreadExecutor() 
 
 analysisUseCase?.setAnalyzer( 
 cameraExecutor, 
 ImageAnalysis.Analyzer { imageProxy ->; 
 processImageProxy(barcodeScanner, imageProxy) 
 } 
 ) 
 
 try { 
 cameraProvider!!.bindToLifecycle( 
 this, 
 cameraSelector!!, 
 analysisUseCase 
 ) 
 } catch (illegalStateException: IllegalStateException) { 
 Log.e(TAG, illegalStateException.message ?: "IllegalStateException") 
 } catch (illegalArgumentException: IllegalArgumentException) { 
 Log.e(TAG, illegalArgumentException.message ?: "IllegalArgumentException") 
 } 
}</pre> 
 
 
 
<p>10 . Create a new function <strong><span style="color: #008000;">processImageProxy()</span></strong>. In processImageProxy(), to recognize barcodes in an image, create an InputImage object. Then, pass the InputImage object to the BarcodeScanner&#8217;s process method.</p> 
 
 
 
<pre class="wp-block-preformatted">private fun processImageProxy( 
 barcodeScanner: BarcodeScanner, 
 imageProxy: ImageProxy 
) { 
 val inputImage = 
 InputImage.fromMediaImage(imageProxy.image!!, imageProxy.imageInfo.rotationDegrees) 
 
 barcodeScanner.process(inputImage) 
 .addOnSuccessListener { barcodes ->; 
 barcodes.forEach { barcode ->; 
 val bounds = barcode.boundingBox 
 val corners = barcode.cornerPoints 
 
 val rawValue = barcode.rawValue 
 
 tvScannedData.text = barcode.rawValue 
 
 val valueType = barcode.valueType 
 when (valueType) { 
 Barcode.TYPE_WIFI ->; { 
 val ssid = barcode.wifi!!.ssid 
 val password = barcode.wifi!!.password 
 val type = barcode.wifi!!.encryptionType 
 tvScannedData.text = 
 "ssid: " + ssid + "\npassword: " + password + "\ntype: " + type 
 } 
 Barcode.TYPE_URL ->; { 
 val title = barcode.url!!.title 
 val url = barcode.url!!.url 
 
 tvScannedData.text = "Title: " + title + "\nURL: " + url 
 } 
 } 
 } 
 } 
 .addOnFailureListener { 
 Log.e(TAG, it.message ?: it.toString()) 
 } 
 .addOnCompleteListener { 
 <strong><span style="color: #008000;">//Once the image being analyzed </span></strong><br /><strong><span style="color: #008000;"> //closed it by calling ImageProxy.close()</span></strong> 
 imageProxy.close() 
 } 
}</pre> 
 
 
 
<p>11 . If the barcode recognition operation succeeds, a list of Barcode objects will be passed to the success listener. Each Barcode object represents a barcode that was detected in the image. For each barcode, you can get its bounding coordinates in the input image, as well as the raw data encoded by the barcode. Also, if the barcode scanner was able to determine the type of data encoded by the barcode, you can get an object containing parsed data.</p> 
<p>When you run the app it will look like this:</p> 
<p><img class="alignnone wp-image-2927" src="https://c1ctech.com/wp-content/uploads/2021/11/Screenshot_20211108-122623_Permission-controller-498x1024.jpg" alt="" width="362" height="745" /> <img class="alignnone wp-image-2926" src="https://c1ctech.com/wp-content/uploads/2021/11/Screenshot_20211108-124224_BarcodeScannerExp-498x1024.jpg" alt="" width="363" height="744" /></p> 
<p> ;</p> 


