Kamerazugriff via SwiftUI – Teil 3

Funktionsfähigkeit prüfen

Die in Teil 1 und Teil 2 dieser Artikelreihe erzeugte TSCameraView ist bereits weit fortgeschritten. Über sie lässt sich auf die Kamera eines iPhone zugreifen, ein Bild aufnehmen sowie jenes Bild weiter verarbeiten.

In diesem Artikel stelle ich euch eine kleine aber feine Optimierung vor, die den Einsatz von TSCameraView weiter verbessert. Eine neue Type Property namens canCaptureImages prüft, ob die Hardware-Voraussetzungen zur Aufnahme von Fotos auf dem zugrundeliegenden Endgerät erfüllt sind. Solch eine Prüfung war früher vor allen Dingen in Bezug auf den iPod touch spannend, der nicht immer eine Kamera besaß. Griff eine App nun auf die Kamera zu, führte das auf solchen Geräten ohne Kamera unweigerlich zum Absturz, entsprechend musste ein passender Check her. Doch auch für den Simulator ist solch eine Information auch heute noch spannend, um bestimmte Funktionen, mit denen der Simulator sowieso nicht umgehen kann, gar nicht erst zugänglich zu machen. Denn auch aus dem Simulator heraus führt ein Zugriff auf die Kamera zum Absturz.

Zurück also zur canCaptureImages-Type Property. Die prüft zunächst über den UIImagePickerController, ob überhaupt eine Kamera zur Aufnahme zur Verfügung steht. Falls ja, erfolgt eine zweite Prüfung, ob sich mit dieser Kamera Bilder aufnehmen lassen (sicher ist sicher). Sind beide Bedingungen erfüllt, liefert canCaptureImages das Ergebnis true zurück, andernfalls false.

Das nachfolgende Listing zeigt die vollständige Implementierung von TSCameraView nach dem Hinzufügen der neuen canCaptureImages-Type Property.

struct TSCameraView: UIViewControllerRepresentable {
    // Ergänzen der neuen `canCaptureImages`-Type Property
    static var canCaptureImages: Bool {
        guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
            return false
        }
        if let availableMediaTypes = UIImagePickerController.availableMediaTypes(for: .camera), availableMediaTypes.contains(UTType.image.identifier) {
            return true
        }
        return false
    }
    
    @Binding var photo: UIImage?
    
    @Binding var showsCameraView: Bool
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIViewController(context: Context) -> UIImagePickerController {
        let imagePickerController = UIImagePickerController()
        imagePickerController.delegate = context.coordinator
        imagePickerController.mediaTypes = [UTType.image.identifier]
        imagePickerController.sourceType = .camera
        return imagePickerController
    }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
    
    class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        var parent: TSCameraView
        
        init(_ cameraView: TSCameraView) {
            parent = cameraView
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let image = info[.originalImage] as? UIImage {
                parent.photo = image
            }
            parent.showsCameraView = false
        }
        
        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            parent.showsCameraView = false
        }
    }
}

Setzen wir abschließend diese neue Property noch in der Praxis ein. Dazu ergänze ich in der bisherigen ContentView einen disabled(_:)-Modifier für jenen Button, über den die Kamera eingeblendet wird. Dieser Modifier prüft den Wert von canCaptureImages. Ist er false, wird der Button deaktiviert. Das sorgt dafür, dass er sich aus dem Simulator heraus nicht länger betätigen lässt.

struct ContentView: View {
    @State private var photo: UIImage?
    
    @State private var showCameraView = false
    
    var body: some View {
        VStack {
            if let photo = self.photo {
                Image(uiImage: photo)
                    .resizable()
                    .scaledToFit()
            }
            Spacer()
            Button("Show camera") {
                showCameraView = true
            }
            // Einsatz des disabled(_:)-Modifiers
            .disabled(!TSCameraView.canCaptureImages)
        }
        .sheet(isPresented: $showCameraView) {
            TSCameraView(photo: $photo, showsCameraView: $showCameraView)
        }
    }
}

Durch diese kleine Änderung wird die TSCameraView robuster. Auch wenn es heute quasi keine Geräte mehr ohne Kamera gibt, lässt sich durch eine Prüfung via canCaptureImages sicherstellen, dass alle geforderten Voraussetzungen zur Aufnahme von Bildern auch tatsächlich erfüllt sind.

Euer Thomas


Kommentare

2 Antworten zu „Kamerazugriff via SwiftUI – Teil 3“

  1. Danke. supi erklärt. Wirklich hilfreich.
    Kann ich die Einstellungen der genutzen Camera über Deinen Code programmieren?
    Ich möchte das Gitter und die Wasserwaage standardmäßig nutzen.
    Beste Grüße
    Franz

    1. Hallo Franz, vielen Dank für dein Feedback! Deine Frage kann ich leider nicht aus dem Stand beantworten. Mir ist soweit nicht bekannt, dass sich die Gitter und Wasserwaage programmatisch über einen UIImagePickerController steuern lassen, ich kenne das nur als zentrale Einstellmöglichkeit in den Settings der Kamera. Wenn ich diesbezüglich aber noch etwas herausfinde teile ich das gerne mit. 🙂

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert