LockedCameraCapture - Lock Screen Camera Capture UI Question

After the session video, "Build a great Lock Screen camera capture experience", was unclear about the UI.

So do developers need to provide a whole new UI in the extension? The main UI cannot be repurposed?

Answered by Frameworks Engineer in 790448022

Hello!

You're welcome to use your existing UI in a Capture Extension. Make any source files you want to use available to both your app target and your capture extension target. Then you can embed the UI you want to use into your LockedCameraCaptureUIScene.

Just keep in mind that your existing UI may need modification in some important ways, such as transitioning the user to the app when they attempt to do something the extension cannot not support.

Accepted Answer

Hello!

You're welcome to use your existing UI in a Capture Extension. Make any source files you want to use available to both your app target and your capture extension target. Then you can embed the UI you want to use into your LockedCameraCaptureUIScene.

Just keep in mind that your existing UI may need modification in some important ways, such as transitioning the user to the app when they attempt to do something the extension cannot not support.

Thank you for the informative answer.

One last question on this: The UI code doesn't have to be in SwiftUI, correct?

Good question!

The LockedCameraCaptureUIScene does take in a SwiftUI view. However, you can use UIKit code by creating a wrapper that implements either UIViewControllerRepresentable or UIViewRepresentable.

There's an example of this in the documentation where the code wraps UIImagePickerController: https://developer.apple.com/documentation/lockedcameracapture/creating-a-camera-experience-for-the-lock-screen

Somehow related, I'm trying to build an example app to get familiar with this new extension. I followed the steps in the docs but I think I'm missing something.

I added the Control through a Widget Extension, and I see that the perform method is called in my Intent, however I'm missing the part where this perform method would open the UI to capture the photos.

This is my Intent:

struct MyAppCaptureIntent: CameraCaptureIntent {
    static var title: LocalizedStringResource = "MyAppCaptureIntent"

    typealias AppContext = MyAppContext
    static let description = IntentDescription("Capture photos with MyApp.")

    @MainActor
    func perform() async throws -> some IntentResult {
        let dialog = IntentDialog("Intent result")
        do {
            if let context = try await MyAppCaptureIntent.appContext {
                return .result()
            }
        } catch {
             // Handle error condition.
        }
        return .result()
    }
}

struct MyAppContext: Decodable, Encodable {
    var data = ContextData()
}

struct ContextData: IntentResult, Decodable, Encodable {
    var value: Never? {
        nil
    }
}

How do I connect this with my LockedCameraCaptureExtension?

To allow the system to launch your extension or application, your intent should be also included in your app and extension targets. The system is able to use the presence of the intent in your widget extension (passed to your control), as well as in both the app and capture extension to determine whether to launch your app or extension when your control’s action is performed.

It is included in the app target, the widget extension target and the locked screen camera extension target.

I am facing the exact same problem. My intent is included as a target in the widget extension, capture extension and main app. When I press on the control in control center or the lock screen, the main app opens and the intent's perform function is executed.

What am I missing?

For Julio:

The CameraCaptureIntent should be connected in two ways: it should be included in all three targets, and it should be given to your Control in the Widget Extension as the App Intent that needs to be run.

The perform block is for configuring your app if the system launches the app. This would likely be used for switching quickly to a camera UI.

For ashmitz-wbd:

The system may decide to open your app rather than the extension based on whether the device is locked and where the control is pressed.

If you press the control while the device is locked, you should get the capture extension in that context.

Thanks for the quick reply.

it should be given to your Control in the Widget Extension as the App Intent that needs to be run.

I think I'm doing this too. Here the code of my control:

struct LockedCameraWidgetExtensionControl: ControlWidget {
    var body: some ControlWidgetConfiguration {
        StaticControlConfiguration(
            kind: "com.Yuju.LockedCameraPlayground.LockedCameraWidgetExtension") {
                ControlWidgetButton(action: MyAppCaptureIntent()) {
                    Label("Capture", systemImage: "camera")
                }
        }
    }
}

And since we are here, this is my ViewFinder:

struct LockedCameraExtensionViewFinder: UIViewControllerRepresentable {
    let session: LockedCameraCaptureSession
    var sourceType: UIImagePickerController.SourceType = .camera

    init(session: LockedCameraCaptureSession) {
        self.session = session
    }
 
    func makeUIViewController(context: Self.Context) -> UIImagePickerController {
        let imagePicker = UIImagePickerController()
        imagePicker.sourceType = sourceType
        imagePicker.mediaTypes = [UTType.image.identifier, UTType.video.identifier]
        imagePicker.cameraDevice = .rear
 
        return imagePicker
    }
 
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: Self.Context) {
    }
}

Make sure you also have a Privacy - Camera Usage Description in both your app and capture extension's Info.plist.

Another thing worth noting, if your app does not have permission to use the camera (the user hasn't been prompted yet, or was denied), then the app will open, not the capture extension.

If you feel like you've covered all of the available ground and it's still not working, feel free to file a Feedback with your code and post the FB number here. We'll do our best to take a look quickly for you!

Yes, I covered that too. I made sure camera permissions where accepted by the user.

Feedback sent -> FB13889233

After using the code provided about I got the same experience that the control widget opens the app. When I tried adding it on the lock screen of the simulator it still opens the app.

Then I tried it on my iPhone. Placing the button in de control center will still open the app. But using it from the lockscreen opens the camera of included in de Locked Camera Capture Extension

hi @codeblocknl ! It doesn't open the camera for me when I place it in the locked screen. Did you use the code I posted in the feedback (FB13889233)? if so, did you modify anything?

LockedCameraCapture - Lock Screen Camera Capture UI Question
 
 
Q