Реализация сканирования QR-кодов через камеру мобильного приложения
DataScannerViewController в iOS 16+ сделал реализацию QR-сканера тривиальной задачей — примерно 20 строк кода. На Android ML Kit справляется аналогично. Основная работа — UX вокруг сканера: подсветка, анимация, обработка ошибок доступа к камере.
iOS: два пути
DataScannerViewController (iOS 16+)
guard DataScannerViewController.isSupported,
DataScannerViewController.isAvailable else { return }
let scanner = DataScannerViewController(
recognizedDataTypes: [.barcode(symbologies: [.qr])],
qualityLevel: .balanced,
recognizesMultipleItems: false,
isHighlightingEnabled: true
)
scanner.delegate = self
try? scanner.startScanning()
present(scanner, animated: true)
recognizesMultipleItems: false — останавливается на первом найденном коде. isHighlightingEnabled рисует рамку вокруг кода автоматически.
Делегат:
func dataScanner(_ dataScanner: DataScannerViewController,
didAdd addedItems: [RecognizedItem],
allItems: [RecognizedItem]) {
guard case let .barcode(barcode) = addedItems.first,
let payload = barcode.payloadStringValue else { return }
dataScanner.stopScanning()
handleQR(payload)
}
AVFoundation (iOS 14-15)
Для поддержки iOS 14-15 — AVCaptureMetadataOutput с metadataObjectTypes = [.qr]. Подробная реализация такая же, как для штрих-кодов.
Android: ML Kit в 10 строк
val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(Barcode.FORMAT_QR_CODE)
.build()
val scanner = BarcodeScanning.getClient(options)
Через CameraX ImageAnalysis — тот же подход, что и для общего сканирования штрих-кодов. Указание конкретного формата FORMAT_QR_CODE ускоряет распознавание примерно вдвое по сравнению с FORMAT_ALL_FORMATS.
Что реально требует времени: UI вокруг сканера
Оверлей с прицелом. Стандартный паттерн — полупрозрачный оверлей с прозрачным прямоугольником в центре. На iOS: CAShapeLayer с evenOdd fill rule или SwiftUI Canvas. На Android: кастомный View с PorterDuff.Mode.CLEAR.
Анимация сканирующей линии. Пользователи ожидают движущуюся линию — без неё непонятно, идёт ли процесс. Простая CABasicAnimation на iOS или ObjectAnimator на Android.
Вспышка. Переключение фонарика: на iOS AVCaptureDevice.torchMode = .on, на Android CameraControl.enableTorch(true).
Разрешение камеры. Если пользователь отклонил запрос, стандартный флоу: AVCaptureDevice.authorizationStatus(for: .video) == .denied → кнопка «Открыть настройки» → UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!). На Android — ActivityCompat.shouldShowRequestPermissionRationale() для объяснения, почему нужно разрешение.
Срок реализации: 1 день (базовая функция) — 2 дня (с кастомным UI и обработкой всех edge cases). Стоимость рассчитывается индивидуально.







