Barcodes scannen unter Android: Ein Schritt-für-Schritt Tutorial
Melden
Dieses Tutorial zeigt dir, wie du eine moderne Android-App erstellst, die Barcodes und QR-Codes scannen kann. Wir verwenden dafür Google ML Kit (für die Erkennung) und CameraX (für den Kamera-Zugriff), da dies aktuell der performanteste und einfachste Weg ist.
1. Projekt vorbereiten (Dependencies)
Öffne deine build.gradle (Module: app) Datei und füge die notwendigen Bibliotheken für ML Kit und CameraX hinzu:
dependencies {
// CameraX Core Bibliotheken
def camerax_version = "1.3.0"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-view:${camerax_version}"
// Google ML Kit Barcode Scanning
implementation 'com.google.mlkit:barcode-scanning:17.2.0'
}
2. Berechtigungen in der AndroidManifest.xml
Damit die App auf die Kamera zugreifen darf, musst du die Erlaubnis im Manifest eintragen:
<uses-permission android:name="android.permission.CAMERA" />
<!-- Optional: Sorgt dafür, dass die App im Store nur für Geräte mit Kamera sichtbar ist -->
<uses-feature android:name="android.hardware.camera" android:required="true" />
3. Das Layout erstellen (activity_main.xml)
Wir benötigen eine PreviewView, um das Kamerabild anzuzeigen:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
4. Den Barcode-Analyzer erstellen
Wir erstellen eine interne Klasse (oder eine separate Datei), die jedes Kamerabild analysiert.
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.common.InputImage
class BarcodeAnalyzer(private val onBarcodeDetected: (String) -> Unit) : ImageAnalysis.Analyzer {
private val scanner = BarcodeScanning.getClient()
@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)
scanner.process(image)
.addOnSuccessListener { barcodes ->
for (barcode in barcodes) {
barcode.rawValue?.let { value ->
onBarcodeDetected(value)
}
}
}
.addOnCompleteListener {
// Wichtig: ImageProxy schließen, um das nächste Frame zu verarbeiten
imageProxy.close()
}
}
}
}
5. Kamera in der Activity starten
In der MainActivity verknüpfen wir alles. Wir prüfen die Berechtigungen und starten den Kamera-Stream.
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.deineapp.databinding.ActivityMainBinding
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
private lateinit var cameraExecutor: ExecutorService
private lateinit var previewView: androidx.camera.view.PreviewView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
previewView = findViewById(R.id.previewView)
cameraExecutor = Executors.newSingleThreadExecutor()
if (allPermissionsGranted()) {
startCamera()
} else {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 10)
}
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview Setup
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(previewView.surfaceProvider)
}
// Analyzer Setup
val imageAnalyzer = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
.also {
it.setAnalyzer(cameraExecutor, BarcodeAnalyzer { barcodeValue ->
// Hier wird das Ergebnis verarbeitet
runOnUiThread {
Toast.makeText(this, "Scan: $barcodeValue", Toast.LENGTH_SHORT).show()
}
})
}
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalyzer)
} catch (exc: Exception) {
// Fehler beim Starten der Kamera
}
}, ContextCompat.getMainExecutor(this))
}
private fun allPermissionsGranted() = ContextCompat.checkSelfPermission(
baseContext, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
}
So funktioniert es:
- CameraX liefert einen kontinuierlichen Stream von Bildern der Rückkamera.
- Die Methode
setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)sorgt dafür, dass die App flüssig läuft, indem sie nur das aktuellste Bild analysiert und Frames überspringt, wenn der Prozessor zu langsam ist. - ML Kit erkennt im Hintergrund den Barcode-Typ (QR, EAN, UPC etc.) und liefert den Textwert zurück.
- Wichtig:
imageProxy.close()muss nach jeder Analyse aufgerufen werden, da die Kamera sonst keine neuen Bilder mehr liefert.
Tipps für die Praxis:
- Vibration: Nutze den
Vibrator-Service, um dem Nutzer haptisches Feedback bei einem erfolgreichen Scan zu geben. - Einmaliges Scannen: Implementiere eine Variable (z.B.
isScanning = true), damit nicht 30-mal pro Sekunde derselbe Barcode erkannt und ein Toast angezeigt wird. - Fokus: CameraX kümmert sich in der Standardeinstellung automatisch um den Autofokus.