fix: QR scanner crash — missing NSCameraUsageDescription in Info.plist

The app crashed immediately when tapping QR scan because the Info.plist
was missing the required NSCameraUsageDescription key. iOS kills the app
with EXC_BAD_INSTRUCTION when camera access is requested without it.

Also fixes:
- Flash toggle could SIGABRT if lockForConfiguration failed (try? + unconditional unlock)
- Camera setup now logs errors instead of silently failing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Schwifty 2026-03-22 21:45:10 +00:00
parent 1624e0e59d
commit f60c70f32a
2 changed files with 21 additions and 5 deletions

View file

@ -22,6 +22,8 @@
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSCameraUsageDescription</key>
<string>Payfrit Beacon needs camera access to scan QR codes on beacon labels for provisioning.</string>
<key>NSBluetoothAlwaysUsageDescription</key> <key>NSBluetoothAlwaysUsageDescription</key>
<string>Payfrit Beacon needs Bluetooth to detect and configure nearby beacons.</string> <string>Payfrit Beacon needs Bluetooth to detect and configure nearby beacons.</string>
<key>NSBluetoothPeripheralUsageDescription</key> <key>NSBluetoothPeripheralUsageDescription</key>

View file

@ -241,17 +241,31 @@ final class CameraPreviewUIView: UIView {
func setFlash(_ on: Bool) { func setFlash(_ on: Bool) {
guard let device = AVCaptureDevice.default(for: .video), guard let device = AVCaptureDevice.default(for: .video),
device.hasTorch else { return } device.hasTorch else { return }
try? device.lockForConfiguration() do {
device.torchMode = on ? .on : .off try device.lockForConfiguration()
device.unlockForConfiguration() device.torchMode = on ? .on : .off
device.unlockForConfiguration()
} catch {
NSLog("[QRScanner] Failed to set torch: \(error.localizedDescription)")
}
} }
private func setupCamera() { private func setupCamera() {
let session = AVCaptureSession() let session = AVCaptureSession()
session.sessionPreset = .high session.sessionPreset = .high
guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back), guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
let input = try? AVCaptureDeviceInput(device: device) else { return } NSLog("[QRScanner] ERROR: No back camera available")
return
}
let input: AVCaptureDeviceInput
do {
input = try AVCaptureDeviceInput(device: device)
} catch {
NSLog("[QRScanner] ERROR: Failed to create camera input: \(error.localizedDescription)")
return
}
if session.canAddInput(input) { if session.canAddInput(input) {
session.addInput(input) session.addInput(input)