iOS 13 - Camera hangs in VNDocumentCameraViewController

1.1k Views Asked by At

When using VisionKit's VNDocumentCameraViewController for scanning documents the camera hangs after some seconds. The scan is implemented in a ViewController, which is used in SwiftUI.

The implementation of a DocumentScannerViewController:

import UIKit
import VisionKit
import SwiftUI

final class DocumentScannerViewController: UIViewController, VNDocumentCameraViewControllerDelegate, UIViewControllerRepresentable {
    public typealias UIViewControllerType = DocumentScannerViewController

    public func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentScannerViewController>) -> DocumentScannerViewController {
        return DocumentScannerViewController()
    }

    public func updateUIViewController(_ uiViewController: DocumentScannerViewController, context: UIViewControllerRepresentableContext<DocumentScannerViewController>) {
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let scannerViewController = VNDocumentCameraViewController()
        scannerViewController.delegate = self as VNDocumentCameraViewControllerDelegate
        view.addSubview(scannerViewController.view)
    }

    func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
    }

    func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
    }

    func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {
    }
}

And the implementation of the ContentView:

import SwiftUI

struct ContentView: View {
    var body: some View {
        DocumentScannerViewController()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

The document scan camera launches and works for a short period of time. Then camera just stops moving.

Any idea what causes this behavior?

1

There are 1 best solutions below

0
On

Apple does provide a way to use ViewControllers inside SwiftUI view with UIViewControllerRepresentable which you have to implement this way.

First declare your View as follows:

import SwiftUI
import UIKit
import Vision
import VisionKit

struct ScanningVNDocumentView: UIViewControllerRepresentable  {

    // implement your custom init() in case ..

    typealias UIViewControllerType = VNDocumentCameraViewController

    func makeUIViewController(context: UIViewControllerRepresentableContext<ScanningVNDocumentView>) -> VNDocumentCameraViewController {
        let viewController = VNDocumentCameraViewController()
        viewController.delegate = context.coordinator
        return viewController
    }

    func updateUIViewController(_ uiViewController: VNDocumentCameraViewController, context: UIViewControllerRepresentableContext<ScanningVNDocumentView>) {

    }

    func makeCoordinator() -> Coordinator {
    //Coordinator is Apple bridge between SwiftUI and ViewController
        return Coordinator() `// this basically call init of the UIViewControllerRepresentable above`

    }

    final class Coordinator: NSObject, VNDocumentCameraViewControllerDelegate {
        @Environment(\.presentationMode) var presentationMode

        init() {

        }
        // implement VNDocumentCameraViewControllerDelegate methods where you can dismiss the ViewController
        func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
            print("user did press save with scanned docs numbers \(scan.pageCount) ")
        }

        func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
    print("Did press cancel")
         }


        func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {
            print("Document camera view controller did finish with error ", error)

        }
    }
}

You can now call your view this way:

var body: some View {
    ScanningVNDocumentView()
}