Streaming is available in most browsers,
and in the Developer app.
-
Build a great Lock Screen camera capture experience
Find out how the LockedCameraCapture API can help you bring your capture application's most useful information directly to the Lock Screen. Examine the API's features and functionality, learn how to get started creating a capture extension, and find out how that extension behaves when the device is locked.
Chapters
- 0:00 - Introduction
- 1:39 - Great capture experiences
- 3:33 - Lifecycle of a capture extension
- 4:49 - Running on a locked device
- 10:48 - Capturing from the Lock Screen
- 18:31 - Working with captures in your app
Resources
- Creating a camera experience for the Lock Screen
- Creating controls to perform actions across the system
- Forum: Photos & Camera
- Human Interface Guidelines: Controls
Related Videos
WWDC24
-
Download
Hi there, I’m Adam and I’m an engineer on the iOS System Experience team. Today, I am excited to show you how to build a great camera capture experience for the Lock Screen. I love how easy it is to capture a great moment with my iPhone. When I take my iPhone out of my pocket, without even needing to unlock it, I can launch into the camera from the Action button, Control Center, or the Lock Screen. Before you know it, I’ve snapped a great photo, like this photo I took today at Apple Park.
New in iOS 18, your camera experience can be made available to people right from their Lock Screen on both iPhone and iPad. This type of capture experience is enabled by a new framework we’re introducing in iOS 18: LockedCameraCapture framework. The LockedCameraCapture framework contains the building blocks to build a great camera capture experience that will run from the Lock Screen. One major component introduced by LockedCameraCapture so we can build this capture experience is a new extension type, the Locked Camera Capture Extension.
In this session, we’ll talk about what makes a great camera capture experience then we’ll take you through the lifecycle of a capture extension, Then we’ll talk about some important considerations for running on a locked device.
After that we’ll take a deeper dive into how you can capture great photos and videos from the Lock Screen. And finally, we’ll look at how you can incorporate content captured from the Lock Screen back into your application.
Let's start with a discussion of what makes a great capture experience. The Camera app on iOS provides a great capture experience on iPhone or iPad. I can quickly and easily access my camera from my Lock Screen even when my device is locked by pressing on the Camera control.
Pressing that control takes me directly to a viewfinder to start capturing photos.
I can press the volume up button to capture a photo or press and hold it to start recording a video.
Once I’ve taken a photo or video, I can tap the image well to view it.
My device still remains locked, and Camera maintains my privacy by only showing photos and videos I’ve captured while I had the camera presented. If I want deeper interactions with my content, my phone will request that I unlock my device and then allow me to continue.
To enable this type of experience for your app, you can create a new type of app extension, the Locked Camera Capture Extension.
An app extension is a separate target that gets embedded in your application. It lets you extend custom functionality and content beyond your app, making it available to people while they’re interacting with other apps or the system.
This new type of app extension runs from the Lock Screen so you can build a capture experience that allows people to get quick and easy access to snap a photo or record a video using the same familiar UI from your application, even when their device is locked.
Let's take a look at the lifecycle of this new extension. The first step of the lifecycle is launching the extension.
This extension can be launched from a control in control center. From a control assigned to the action button. Or from a control on the Lock Screen.
Once the extension is launched, someone can then start to capture great photo and video content which will use the same familiar UI from your app.
Capture extension can either directly add photo and video assets to a person’s Photo library, or the extension can store any data it needs to represent a capture to a provided directory on the file system.
After capturing some content, someone might want to do something more in depth with it, such as sharing it to a social network or applying a filter requiring image assets, to give it a styled look.
For these types of interactions, the extension can request to open its parent application, which will authenticate a person using the device.
This enables the ability to do a seamless transition from extension to app, bringing someone right to where the extension left off. Lastly, whether by transitioning to the application or if someone swiped up to return to the Lock Screen, the capture extension will be dismissed. When this happens, the system moves the captured content to a location that the parent application can access. When the app has runtime, it can incorporate the content captured while in the extension into its other content.
We’ll talk more in depth about this process later on in this video. Now that we know more about the lifecycle of a capture extension, lets cover some important considerations for running on a locked device. People around the world rely on iOS everyday to provide them a high degree of privacy.
When my device is locked, I can rest assured that my contacts, emails, photos, videos and much more are secure behind the Lock Screen, requiring me to unlock my device to access them. We’ve built LockedCameraCapture framework with an intentional focus on security and privacy, remaining conscious of protecting the contents of people's devices. Since this new extension type runs from the Lock Screen, a persons device may be locked while they are capturing photos or video in your capture experience. To ensure the privacy and security of a persons device, we’ve enforced a few restrictions for this new experience. Your extension should provide the same capture experience as in your application, and is expected to provide people with a camera viewfinder as soon as possible after launch. If your extension is not showing a camera viewfinder at launch, your extension will be terminated by the system.
We think capturing a photo or video with the hardware buttons of the phone is a great way to give people the quickest point and shoot experience possible. Therefore, your extension must use AVCaptureEventInteraction to handle events from the system hardware buttons.
Since your experience will be accessible while the device is locked, your capture extension will be restricted from using any network resources it cannot read from or write to any shared group container for your application, or other extensions, and cannot access any shared preferences for your application.
Rest assured you can still share an important state between your extension and application, we’ll go over how in a little while. First, let's take a look at how persisting data for captures works when in the extension.
We recommend using PhotoKit to save photo and video assets captured from your extension.
With PhotoKit, your extension can add captured photos and videos to someone's photo library, even when the device is locked.
PhotoKit is designed to protect the private photos and videos in the photo library when the device is locked. When reading the photo library on a locked device, only photos and videos written during the current capture session will be available to be read. If your device is unlocked and your extension has the proper permissions for the photo library, you will be able to read all photos and videos that someone has given you access to, not just those captured during the current capture session. PhotoKit also has great support for granular levels of photo library access, such as write only access and limited library support, allowing someone to select a set of photos to allow access to.
Your extension inherits Photos permissions from your app, so your extension should be prepared to handle any level of permissions for photo library access. If your extension needs additional permissions for Photos, you can transition into your application to request them. We’ll cover how to do that a bit later in this video. For more information on working with PhotoKit, you can check out these videos from previous WWDCs. Some capture experiences might need to save other data that PhotoKit does not support. LockedCameraCapture framework also supports saving any data you might need for captures taken in your extension. Let’s take a look at how this works.
These boxes represent the file system storage of photos and videos captured for your extension on the left, and your application on the right.
On launch, your extension will be provided a content path via the session object. In this example, as a person captures content, your extension can write data to a provided session content directory.
You may also use PhotoKit to ingest captured photos and videos, adding them directly to the photo library.
You might be tempted to store additional data anywhere else in the extension container. However, this is not recommended. At any time, someone can dismiss your extension.
Once your extension is dismissed, the provided session content directory is migrated to your application’s container and the extension’s container is erased to ensure security and to preserve the privacy of the device owner.
You will not be able to access the contents of any prior sessions from within the extension. Persist any data you wish to preserve past the given session in the provided session content directory. In the case of an unexpected termination, the system will still copy the contents of this directory, allowing you to attempt recovery of the data. If someone launches your extension again, it receives a new session object containing a new session content directory to write files to. Once again, the extension writes into the session content directory, and when someone dismisses the extension, the content is once again moved into the application’s container as a separate session content directory.
When your application has runtime, it can retrieve the captured contents and handle them appropriately, such as integrating them to sit alongside other captured content in your app. Once your application is done handling the contents of a single session directory, it can call to invalidate that directory, letting the system know that directory is safe to erase from the file system.
To reiterate: Someone can dismiss your extension at any time, and when that happens, only contents in the session content directory will be copied to your application’s container. You will not be able to access the container contents from a previous launch of the extension on the next launch of the extension, as data in the extension’s container will be erased. While we have mainly focused on behaviors for running while the device is locked, your extension will run from the Lock Screen regardless of the device’s locked state.
For both locked and unlocked cases the behaviors and restrictions will remain the same. Now that we’ve discussed the caveats of running on a locked device, let's talk about building our experience to capture content right from the Lock Screen. My colleague, Jon, and I have recently been working on an update to our app, ClownTown that lets Clowns add a profile for themselves, so they can connect with other Clowns in the area. I think adding the ability to take a photo for their profile would be a great feature.
I’ll use my updates to the ClownTown app as an example as we go through building our capture extension and the rest of the capture experience. To help you get started, Xcode provides a convenient template for the Locked Camera Capture Extension.
This template includes everything you need to build and run right away, including a camera viewfinder and shutter button.
In my example here, I define my extension, which conforms to LockedCameraCaptureExtension.
Then from within that struct, an extension scene is implemented for the body, and the scene returns my custom view content. Your UI for this extension should be focused on bringing people to a camera viewfinder to capture photos and videos. Your extension should also provide the same consistent capture experience people will get in your application, using the same familiar UI elements.
Your extension will inherit permissions for Camera and Photos access from your application. Your extension should be prepared to handle any level of permissions for both Camera or Photos. If your app cannot use the Camera due to permissions not having been granted, the system will request an unlock of a person's device and after a successful authentication, launch your app instead of your extension to handle that case. The initializer for the LockedCameraCaptureUIScene provides a single parameter, an instance of LockedCameraCaptureSession. Let's take a look at what this session object provides.
This session object serves a few important purposes.
The capture session provides a sessionContentURL.
This is a path to a directory in your extension’s container which you can use to persist any and all data for someone’s captured photos and videos, and any other related data you wish to preserve. You can also persist captured photos and videos directly to PhotoKit from your capture extension. You can write content to the photo library even if the device is locked, however when the device is locked, only photos and videos written during the current capture session will be available to be read.
When unlocked, your extension can read all of the photos it has permissions to read, including those outside of the current capture session. If you are finished using the data you’ve written to the directory sessionContentURL, for example, if you have saved the contents to PhotoKit, you can call invalidateSessionContent to erase the contents of that directory. You can continue to write to the directory after calling this function, but any content written there prior to the invalidate call will be erased.
The session also provides a function to request an open of your application. You should only call this function in reaction to a person interacting with your UI, such as when someone taps a button to share a photo via the share sheet. Since sharing content requires network access, and you cannot fulfill that request in the capture extension, you can call openApplication, which will prompt for an unlock of the device, and if successfully unlocked, then will open your application. We’ll take a closer look at how to use this function later in this video. When we discussed the lifecycle of your extension earlier, I mentioned that your extension is launched from a control in Control Center, from a control set to the action button, or a control on the Lock Screen. To allow someone to launch your capture experience, you will need to create a custom control. This control will be part of another extension, a widget extension which you can build with WidgetKit.
For this control to specifically launch your capture experience, you will need to implement a new type of system intent being introduced in iOS 18, the CameraCaptureIntent. Depending on conditions such as whether the device is at the Lock or Home Screen, the system will determine whether to launch your capture extension or your application with your CameraCaptureIntent. When your app or extension is launched with this intent, that is your cue to bring someone directly to your capture experience on launch. To allow this intent to launch your extension or your application, you must include your CameraCaptureIntent in all three targets: your widget extension, allowing the intent to be used by your control, your extension, and your application.
The Camera capture intent defines an app context. This context is shared between your application and extension, and can be written to from either.
You should use this context to store user preferences or any settings you want to share between your capture experience in your extension, and the capture experience in your application. For example, you might store data to represent app purchases made by a person in your application so they can also be used in your capture extension. To update the app context, call the updateAppContext function passing in the new app context you wish to persist. It's very important to note, the app context has a limited size. If a context is too large, it will not be persisted, which may impact the behavior of your capture experience, so be conscious of how much you write to the app context.
Here you can see my implementation of a CameraCaptureIntent.
You’ll notice I’ve defined my own type for the app context, ClownTownContext.
Here's what that context looks like. A clown may not always be ready to capture a great clown portrait since they’re not always in their makeup, so we have a button to automatically add some clown makeup for anyone, so they’re ready to snap the perfect clown profile photo anytime. Here, I’ve defined a single bool to represent that setting for whether we are adding clown makeup and a clown nose or not.
I’ve implemented the perform function for my intent, which you can see here.
Notice how I’m reading the context and using it to set up my interface state so my capture experience will always reflect the latest state in which a person used the app: with added clown makeup or not.
Here is a code snippet of my button code in my capture experience, which shows how I am handling the button press to turn on and off that clown makeup setting. When the action is triggered, I call to update the app context with this setting so it can be read from both my app and my extension. And finally, here is my control widget for ClownTown, which will be incorporated into my widget extension. You can see here I am passing an instance of my ClownTownCaptureIntent to the control as its action to perform.
To summarize, you will add a widget extension to your app and define your control. Along with that, you will also implement a camera capture intent to provide to your control, as well as including it in your app and extension targets. For more information on how to build a Control to launch your capture experience, you can check out my colleague Cliff’s video, "Creating your own Controls", and for more information on working with AppIntents, you can watch, "Bring your app’s core features to users with App Intents." One final requirement for your capture experience is that your extension and application should both include privacy usage descriptions for the Camera. This is a signal to the system that you intend to use the camera for capturing photos and video and allows the system to display that description to explain why your capture experience wishes to use the camera. Now that we’ve built a control to launch our capture experience, let's talk about how we work with captured content in our app.
While running your capture experience at the Lock Screen, someone might want to perform an action that requires privileges beyond what is available in the capture extension. For example, someone may wish to post their captured photos to a social network, which would require network access, or they may wish to use a feature that requires resources from your application's shared group container. To handle these types of interactions, your extension can call the openApplication function on LockedCameraCaptureSession, which we briefly covered earlier.
This function takes a single parameter of an NSUserActivity.
As a convenience, LockedCameraCapture also exposes a new NSUserActivity type, NSUserActivityType LockedCameraCapture. This new user activity type is intended to be used with the openApplication function, as a signal indicating to your application that it was launched from your capture extension. Calling the openApplication function will prompt someone to unlock their device if needed, and open your application which will receive a call to handle continuation of the NSUserActivity. This allows your application to bring a person right where they left off in your UI with a seamless transition.
For my ClownTown capture extension, I want to open the app when someone wants to update the profile photo, which will use the network to send it to a server. Here, when the user taps the appropriate button, I call to open the application with an NSUserActivity with our new type for LockedCameraCapture, and I pass some context in the userInfo to indicate that I want my application to continue the "update profile photo" flow. With the userInfo as well as the user activity type, my application has enough context to perform a transition that is seamless from my extension.
From within your application, you can use the LockedCameraCaptureManager to work with the content that has been captured from your capture extension. LockedCameraCaptureManager exposes a shared instance for you to use across your application as needed.
The manager exposes a sessionContentURLs property, which provides an array of URLs, each pointing to a directory of content captured in your capture extension. The manager also exposes an AsyncSequence of sessionContentUpdates. This sequence begins with the URLs representing the current session content directories, and continues with any added or removed session content directories. This can be used to asynchronously process the captured contents from your extension.
In some cases, when transitioning from the extension to the application, the most recently captured session content directory may become available shortly after your application launch.
It is recommended to use this async sequence to ensure you can process the session contents as soon as they are available.
Lastly, the manager exposes an invalidate function. This function is meant to be called after the session contents at the given URL have been handled, and you no longer need that session content. Calling this function will delete the session contents from the URL provided, so it is important to make sure you only call this once you are completely done working with those session contents.
You should note that when you invalidate the session content at a given URL, this will also result in a session content update for the removal of that session content directory. In my ClownTown app, I can use the sessionContentUpdates property to process the initial existing captured content, await new session contents, and process them in my application as they are received.
LockedCameraCapture provides all of the components you need to build a great capture experience and make it easily accessible at someone’s Lock Screen. You can transition into your app to complete key workflows that need additional access, while preserving the privacy and security that people expect when capturing photos and videos from the Lock Screen.
We can’t wait to see what you’ll build with it. Thanks for watching.
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.