Kebutuhan untuk membaca barcode atau QR code sudah jadi bagian tak terpisahkan dari aplikasi modern. Mulai dari aplikasi e-commerce, manajemen inventori, tiket digital, hingga sistem absensi, kemampuan memindai kode ini sangat esensial. Bagi developer Android, membuat fitur barcode scanner bukan lagi hal yang rumit berkat dukungan library dan API yang kuat dari Google.
Dalam panduan lengkap ini, kita akan belajar cara membuat aplikasi barcode scanner sederhana namun fungsional menggunakan Kotlin di Android. Kita akan memanfaatkan kombinasi powerful dari CameraX untuk akses kamera dan ML Kit Barcode Scanning API untuk mendeteksi dan mendekode barcode. Workflow ini adalah salah satu yang paling modern dan direkomendasikan karena efisiensi dan performanya yang sangat baik.
Sebagai seorang developer yang sering menghadapi kebutuhan integrasi fitur scanning, saya bisa bilang bahwa pendekatan ini sangat membantu menghemat waktu dan meminimalisir boilerplate code. Anda akan mendapatkan hasil yang cepat dan robust, bahkan untuk berbagai jenis barcode.
Prasyarat Sebelum Memulai
Sebelum kita terjun langsung ke kode, pastikan Anda memiliki prasyarat berikut:
- Android Studio: Versi terbaru terinstal di komputer Anda.
- Kotlin: Pemahaman dasar tentang bahasa pemrograman Kotlin.
- Konsep Dasar Android Development: Penggunaan Activity, Layout XML, dan Permissions.
- Perangkat Android Fisik atau Emulator: Untuk menguji aplikasi Anda. Emulator bisa digunakan, tetapi pengalaman terbaik adalah dengan perangkat fisik yang memiliki kamera.
Langkah 1: Siapkan Proyek Android Baru
Buka Android Studio dan buat proyek baru dengan langkah-langkah berikut:
- Pilih “New Project”.
- Pilih template “Empty Activity”.
- Klik “Next”.
- Konfigurasi proyek:
- Name:
BarcodeScannerApp - Package name:
com.tubianto.barcodescannerapp(atau sesuai preferensi Anda) - Language:
Kotlin - Minimum SDK version: Pilih API 21 atau lebih tinggi (disarankan 24+ untuk CameraX)
- Name:
- Klik “Finish”. Tunggu Android Studio selesai membangun proyek.
Langkah 2: Tambahkan Dependencies
Kita memerlukan beberapa library penting untuk barcode scanner kita: CameraX untuk mengelola kamera dan ML Kit Barcode Scanning untuk mendeteksi barcode. Buka file build.gradle.kts (Module :app) dan tambahkan dependencies berikut di bagian dependencies { ... }:
// CameraX
implementation("androidx.camera:camera-core:1.3.3")
implementation("androidx.camera:camera-camera2:1.3.3")
implementation("androidx.camera:camera-lifecycle:1.3.3")
implementation("androidx.camera:camera-video:1.3.3")
implementation("androidx.camera:camera-view:1.3.3")
implementation("androidx.camera:camera-extensions:1.3.3")
// ML Kit Barcode Scanning
implementation("com.google.mlkit:barcode-scanning:17.2.0")
// LifecycleScope (untuk coroutine di ViewModel/LifecycleOwner)
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
Sinkronkan proyek Anda dengan Gradle setelah menambahkan dependencies ini (klik “Sync Now” yang muncul di bagian atas file).
Langkah 3: Konfigurasi Permissions di AndroidManifest.xml
Agar aplikasi bisa mengakses kamera perangkat, kita perlu mendeklarasikan permission CAMERA. Buka file app/src/main/AndroidManifest.xml dan tambahkan baris berikut di dalam tag <manifest>, di atas tag <application>:
<uses-permission android:name="android.permission.CAMERA" />
Jika Anda berencana menyimpan hasil scan atau mengakses file lain, Anda mungkin perlu permission lain seperti WRITE_EXTERNAL_STORAGE, tetapi untuk scanner dasar, CAMERA sudah cukup.
Langkah 4: Rancang Layout Aplikasi (activity_main.xml)
Kita akan membuat layout yang sederhana: sebuah PreviewView untuk menampilkan feed kamera dan sebuah TextView untuk menampilkan hasil scan barcode. Buka file app/src/main/res/layout/activity_main.xml dan ubah isinya menjadi seperti ini:
<?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">
<androidx.camera.view.PreviewView
android:id="@+id/viewFinder"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/barcodeResultTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#80000000"
android:padding="16dp"
android:text="Arahkan kamera ke barcode..."
android:textColor="@android:color/white"
android:textSize="18sp"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
PreviewView akan menampilkan apa yang dilihat kamera secara real-time. TextView akan digunakan untuk menampilkan data barcode setelah berhasil dipindai.
Langkah 5: Implementasi Logic Barcode Scanner (MainActivity.kt)
Ini adalah bagian inti dari aplikasi kita. Kita akan menginisialisasi CameraX, meminta permission kamera, dan mengintegrasikannya dengan ML Kit untuk mendeteksi barcode. Buka file app/src/main/java/com/tubianto/barcodescannerapp/MainActivity.kt dan isi dengan kode berikut:
“`kotlin
package com.tubianto.barcodescannerapp
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import com.tubianto.barcodescannerapp.databinding.ActivityMainBinding
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
private lateinit var viewBinding: ActivityMainBinding
private lateinit var cameraExecutor: java.util.concurrent.ExecutorService
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
startCamera()
} else {
Toast.makeText(this, “Permission kamera ditolak.”, Toast.LENGTH_SHORT).show()
finish()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
cameraExecutor = Executors.newSingleThreadExecutor()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
startCamera()
} else {
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)
}
// Konfigurasi Barcode Scanner ML Kit
val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE,
Barcode.FORMAT_CODE_128,
Barcode.FORMAT_EAN_13,
Barcode.FORMAT_DATA_MATRIX // Anda bisa menambahkan format lain yang Anda butuhkan
)
.build()
val barcodeScanner = BarcodeScanning.getClient(options)
val imageAnalyzer = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) // Penting untuk performa
.build()
.also {
it.setAnalyzer(cameraExecutor, BarcodeAnalyzer(viewBinding.barcodeResultTextView) { barcodeResult ->
// Ketika barcode ditemukan, kita bisa update UI atau melakukan aksi lain
runOnUiThread {
viewBinding.barcodeResultTextView.text = “Hasil: $barcodeResult”
Toast.makeText(this, “Barcode Terdeteksi: $barcodeResult”, Toast.LENGTH_SHORT).show()
// Anda bisa menambahkan logika untuk menghentikan scanning atau navigasi ke layar lain
// Untuk demo ini, kita biarkan scanning terus berjalan
}
})
}
// Select back camera as a default
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
// Unbind any previous use cases
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageAnalyzer)
} catch(exc: Exception) {
Log.e(“MainActivity”, “Use case binding failed”, exc)
}
}, ContextCompat.getMainExecutor(this))
}
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
// Inner class untuk menganalisis gambar dan mendeteksi barcode
private class BarcodeAnalyzer(
private val resultTextView: android.widget.TextView,
private val onBarcodeDetected: (String) -> Unit
) : ImageAnalysis.Analyzer {
private val barcodeScanner = BarcodeScanning.getClient() // Menggunakan opsi default atau yang telah dikonfigurasi
@androidx.annotation.OptIn(androidx.camera.core.ExperimentalGetImage::class)
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image
if (mediaImage != null) {
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
barcodeScanner.process(image)
.addOnSuccessListener { barcodes ->
if (barcodes.isNotEmpty()) {
for (barcode in barcodes) {
val rawValue = barcode.rawValue
if (rawValue != null) {
Log.d(“BarcodeAnalyzer”, “Barcode detected: $rawValue”)
onBarcodeDetected(rawValue)
// Hanya memproses satu barcode per frame untuk efisiensi
break
}
}
} else {
// Tidak ada barcode terdeteksi, reset teks jika perlu
resultTextView.post {
resultTextView.text = “Arahkan kamera ke barcode…”
}
}
}
.addOnFailureListener { e ->
Log.e(“BarcodeAnalyzer”, “Barcode scanning failed”, e)
}
.addOnCompleteListener {
imageProxy.close() // Penting untuk menutup imageProxy
}
}
}
}
}
“`
Mari kita bedah beberapa bagian penting dari kode di atas:
requestPermissionLauncher: Digunakan untuk menangani permintaan izin kamera secara modern di Android.startCamera(): Fungsi ini menginisialisasi CameraX.Preview.Builder(): Untuk menampilkan feed kamera kePreviewView.BarcodeScannerOptions.Builder(): Anda bisa mengkonfigurasi jenis barcode apa saja yang ingin didukung oleh ML Kit. Semakin sedikit jenis yang Anda pilih, semakin cepat proses deteksinya.ImageAnalysis.Builder(): Ini adalah use case CameraX yang mengirimkan setiap frame dari kamera untuk dianalisis. StrategiSTRATEGY_KEEP_ONLY_LATESTsangat penting untuk performa agar tidak memproses frame yang sudah ketinggalan.BarcodeAnalyzer: Sebuah kelas kustom yang mengimplementasikanImageAnalysis.Analyzer. Ini adalah tempat di mana ML Kit Barcode Scanning API dipanggil untuk memproses gambar.
BarcodeAnalyzer:- Mendapatkan objek
InputImagedariImageProxy. - Memanggil
barcodeScanner.process(image)untuk mendeteksi barcode. - Menangani hasil deteksi di
addOnSuccessListenerdan error diaddOnFailureListener. - Sangat penting: Pastikan Anda memanggil
imageProxy.close()setelah selesai memproses gambar, jika tidak, Anda akan mengalami masalah memory leak atau kamera akan berhenti bekerja. runOnUiThread: Digunakan untuk mengupdate UI (TextView) karena operasi scan barcode berjalan di background thread.
- Mendapatkan objek
Langkah 6: Jalankan Aplikasi
Sambungkan perangkat Android fisik Anda ke komputer atau mulai emulator. Klik tombol “Run App” (ikon segitiga hijau) di Android Studio. Saat aplikasi berjalan pertama kali, ia akan meminta izin kamera. Izinkan, lalu arahkan kamera ke barcode atau QR code. Anda akan melihat hasilnya di bagian bawah layar.
Masalah yang Sering Terjadi
Meskipun kita sudah mengikuti langkah-langkah di atas, ada beberapa masalah umum yang mungkin Anda hadapi:
1. Aplikasi Crash Saat Meminta Izin Kamera
Gejala: Aplikasi menutup sendiri atau menunjukkan pesan error terkait izin.
Penyebab: Anda lupa menambahkan permission <uses-permission android:name="android.permission.CAMERA" /> di AndroidManifest.xml, atau min SDK version terlalu rendah untuk CameraX.
Solusi: Periksa kembali AndroidManifest.xml. Pastikan juga minSdkVersion di build.gradle.kts (Module:app) setidaknya API 21, meskipun API 24+ lebih direkomendasikan untuk CameraX yang stabil.
2. Kamera Tidak Muncul atau Layar Hitam
Gejala: PreviewView hanya menampilkan layar hitam, bukan feed kamera.
Penyebab: Kamera tidak berhasil diinisialisasi atau di-bind ke lifecycle. Bisa juga karena permission kamera tidak diberikan atau ada masalah dengan konfigurasi CameraX.
Solusi: Pastikan Anda telah memberikan izin kamera. Periksa logcat (Log.e("MainActivity", ...)) untuk pesan error terkait CameraX. Pastikan ProcessCameraProvider.getInstance(this) berhasil mendapatkan instance dan cameraProvider.bindToLifecycle() tidak melempar exception.
3. Barcode Tidak Terdeteksi atau Sangat Lambat
Gejala: Aplikasi menunjukkan “Arahkan kamera ke barcode…” meskipun sudah mengarah ke barcode, atau deteksi sangat lambat.
Penyebab:
- Kualitas gambar barcode buruk (buram, pencahayaan kurang, refleksi).
- Format barcode tidak termasuk dalam opsi
BarcodeScannerOptions. imageProxy.close()tidak dipanggil diBarcodeAnalyzer, menyebabkan tumpukan gambar dan memory leak.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)tidak digunakan atau salah konfigurasi.- Pemrosesan di
BarcodeAnalyzerterlalu berat atau berjalan di main thread.
Solusi:
- Pastikan kondisi pencahayaan dan fokus kamera baik.
- Periksa kembali
BarcodeScannerOptionsAnda; tambahkan format barcode yang Anda butuhkan. - Pastikan
imageProxy.close()dipanggil di bagianaddOnCompleteListener. - Gunakan
STRATEGY_KEEP_ONLY_LATESTuntukImageAnalysis. - Pastikan pemrosesan barcode dilakukan di
cameraExecutor, bukan main thread.
4. Aplikasi Mengalami OutOfMemoryError
Gejala: Aplikasi crash dengan pesan error java.lang.OutOfMemoryError.
Penyebab: Ini sering terjadi jika imageProxy.close() tidak dipanggil, menyebabkan sistem menyimpan terlalu banyak gambar dari kamera di memori.
Solusi: Seperti poin sebelumnya, pastikan imageProxy.close() selalu dipanggil di addOnCompleteListener di dalam BarcodeAnalyzer.
Pengalaman dan Pertimbangan Praktis
Sebagai praktisi yang sering mengimplementasikan fitur scanning, saya menemukan beberapa hal penting yang perlu diperhatikan:
1. Jenis Barcode yang Didukung
ML Kit mendukung banyak format barcode populer seperti QR Code, Code 39, Code 93, Code 128, EAN-8, EAN-13, ITF, UPC-A, UPC-E, Data Matrix, Aztec, dan PDF417. Namun, dalam praktiknya, tidak semua aplikasi butuh semua format. Mengurangi format di BarcodeScannerOptions bisa meningkatkan kecepatan deteksi. Untuk aplikasi umum, QR Code, EAN-13 (untuk produk), dan Code 128 (untuk aset/inventori) sudah cukup.
2. Performa dan Optimasi
Deteksi barcode secara real-time adalah operasi yang intensif. Meskipun ML Kit sangat efisien, ada beberapa hal yang bisa Anda lakukan:
- Strategi Backpressure: Selalu gunakan
ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST. Ini memastikan bahwa jika pemrosesan frame lambat, hanya frame terbaru yang akan dianalisis, menghindari antrean dan lag. - Executor Khusus: Gunakan
Executors.newSingleThreadExecutor()untukImageAnalysis. Jangan pernah memproses di main thread karena akan membuat UI lag. - Batasi Frekuensi Deteksi: Jika Anda hanya perlu mendeteksi satu barcode lalu berhenti, setelah terdeteksi, Anda bisa membatalkan
imageAnalyzeratau menghentikan CameraX sementara. Ini mengurangi penggunaan CPU dan baterai. - Pencahayaan: Pastikan pengguna memiliki pencahayaan yang cukup. Beberapa aplikasi menyertakan tombol untuk mengaktifkan lampu kilat (torch) kamera.
3. Pengalaman Pengguna (UX)
Antarmuka pengguna yang baik sangat krusial untuk fitur scanner:
- Feedback Visual: Berikan indikator visual seperti bingkai di sekitar barcode yang terdeteksi atau animasi.
- Feedback Haptik/Audio: Bunyikan suara atau berikan getaran singkat saat barcode berhasil dipindai. Ini memberikan konfirmasi instan kepada pengguna.
- Instruksi Jelas: Tampilkan teks instruksi seperti “Arahkan kamera ke barcode” atau “Pindai di area yang terang”.
- Tombol Manual Input: Sediakan opsi untuk memasukkan kode secara manual jika scanner gagal mendeteksi, terutama untuk barcode yang rusak atau sangat kecil.
4. Penggunaan pada Perangkat Lama
Pada perangkat Android yang lebih tua atau dengan spesifikasi rendah, performa deteksi mungkin sedikit menurun. Pastikan aplikasi Anda responsif dan berikan umpan balik jika deteksi membutuhkan waktu lebih lama. Uji pada berbagai jenis perangkat untuk mendapatkan pengalaman yang konsisten.
5. Integrasi Lebih Lanjut
Setelah barcode terdeteksi, data rawValue bisa sangat bervariasi. Anda mungkin perlu:
- Memvalidasi format data (misalnya, apakah itu URL, nomor produk, atau ID).
- Mengirim data ke server (misalnya, untuk lookup produk atau absensi).
- Menyimpan data secara lokal.
- Melakukan navigasi ke layar lain atau membuka browser jika itu adalah URL.
FAQ
Apa itu CameraX dan mengapa digunakan?
CameraX adalah Jetpack library yang memudahkan pengembangan aplikasi kamera di Android. Ia menyediakan API yang konsisten dan mudah digunakan di berbagai versi perangkat Android, menghilangkan kerumitan fragmentasi hardware kamera, dan mendukung lifecycle-aware components.
Apa itu ML Kit Barcode Scanning API?
ML Kit Barcode Scanning API adalah bagian dari Google ML Kit, yang menyediakan kemampuan deteksi dan dekode barcode yang cepat dan akurat. Ia dapat mengenali berbagai format barcode umum dan sangat efisien karena sebagian besar pemrosesannya berjalan di perangkat (on-device).
Bisakah saya memindai beberapa barcode sekaligus?
Ya, ML Kit secara default dapat mendeteksi beberapa barcode dalam satu frame. Anda bisa mengiterasi daftar barcodes yang diterima di onSuccessListener untuk memproses semuanya. Namun, untuk pengalaman pengguna yang lebih baik, seringkali kita hanya perlu fokus pada satu barcode utama, atau mendesain UI untuk memilih barcode mana yang ingin diproses jika ada beberapa.
Apakah fitur ini memerlukan koneksi internet?
Tidak, ML Kit Barcode Scanning API bekerja sepenuhnya di perangkat (on-device) dan tidak memerlukan koneksi internet. Ini membuatnya cepat dan andal bahkan di lokasi tanpa sinyal.
Bagaimana cara menambahkan fitur lampu kilat (torch) kamera?
Anda bisa mengakses kontrol lampu kilat melalui objek CameraControl yang didapatkan dari objek Camera yang di-bind oleh CameraX. Contohnya: cameraProvider.bindToLifecycle(...) akan mengembalikan objek Camera, dari sana Anda bisa mendapatkan camera.cameraControl.enableTorch(true/false).
Kesimpulan
Membangun barcode scanner di Android dengan Kotlin kini jauh lebih mudah dan powerful berkat kombinasi CameraX dan ML Kit Barcode Scanning API. Kedua library ini menyediakan fondasi yang solid untuk menghadirkan fitur scanning yang cepat, akurat, dan efisien ke aplikasi Anda.
Dari persiapan proyek, penambahan dependencies, hingga implementasi logika inti dan penanganan masalah, kita telah menelusuri setiap langkah yang diperlukan. Ingatlah selalu untuk memperhatikan aspek performa dan pengalaman pengguna agar aplikasi Anda tidak hanya berfungsi, tetapi juga nyaman digunakan. Sekarang, Anda punya dasar kuat untuk mengembangkan fitur scanner yang lebih kompleks dan terintegrasi dengan kebutuhan spesifik aplikasi Anda. Selamat mencoba dan terus eksplorasi!
TAGS: Kotlin, Android Development, Barcode Scanner, QR Code, CameraX, ML Kit, Tutorial, Mobile App, Developer Tools, Programming



