Frameworks • iOS • 14:33
Let people select photos and videos to use in your app without requiring full Photo Library access. Discover how the PHPicker API for iOS and Mac Catalyst ensures privacy while providing your app the features you need. PHPicker is the modern replacement for UIImagePickerController. In addition to its privacy-focused approach, the API also provides additional features for your app like search, multi-image selection, and the ability to zoom in or out on on the photo grid. We’ll show you how PHPicker can help most apps avoid asking for direct library access and how you can implement it to improve the overall experience for people interacting with your app.
Speakers: Tobias Conradi, Justin Jia
Downloads from Apple
Transcript
Hello and welcome to WWDC. Hello. My name is Tobias Conradi, and I'm an engineer on the Photos team. Together with my colleague, Justin, I will introduce you to the new Photos picker. First of all, let's answer this question: "What is PHPicker?" PHPicker is a system-provided picker which allows you to get access to photos and videos from the user's Photo Library. It has now built-in support for search just like the Photos app.
It supports fluid zooming in the grid and a very often requested feature, multi-select for third-party apps, where you can even review your selection in one app. In short, PHPicker is the best way for an app to access photo and video data from Photos. It comes in an all-new design you just saw, has a new, easy-to-use API, supports multi-selection, and apps can specify the selectable types.
Another very important feature is the privacy aspect of it. It has privacy built in by default. The app doesn't need direct access to the Photos Library to show the picker, and the picker won't prompt for access on behalf of your app. It provides the user-selected photos and videos only, which is a clear user intent of sharing the assets with your app.
You might wonder, "How do we achieve that?" Well, PHPicker runs out of process of the app. Even though it looks like PHPicker runs inside the app, it is really running in a separate process from the host app rendered on top of it, but the app can't access the picker directly and not even take screenshots of the picker content. Only what the user actually selects is passed back to the host app.
Now let's have a look at the different components of this API. First, there is PHPickerConfiguration, which is used to specify the multi-select limit, or with an optional PHPickerFilter to reduce the selectable types. The configuration is passed to a PHPickerController during its initialization. Set a delegate implemented in your app to get a response back.
Once your user confirms their selection, the picker creates an array of PHPickerResult objects which is then passed back to the delegate. Let's have a look how it works in code. As I already mentioned, you can use the configuration to specify the selection limit and filter down the visible item types. First, we initialize the configuration.
You can specify a selection limit for the picker, the default limit is one, and to allow unlimited selection, set the selection limit to zero. You can then specify a filter to restrict the types of selected items. For example, if you only want to show images, including live photos, use the "images" filter. You can even combine filters. In this example, the picker will only show videos and live photos but no images.
The PHPickerViewController is initialized with the configuration. First, let's create a configuration and then pass the configuration to the PickerViewController during initialization. Assign a delegate to the picker and present the picker. Please note that your app is responsible for presentation and dismissal of the picker. The picker doesn't manage presentation itself.
Once the user confirms their selection, the delegate method will be called. So first, let's dismiss the picker. Then you can ask result objects for an NSItemProvider. The item provider vends multiple different representations of the selected item. First ask the provider if it can load the type you want to load, and then actually load it. Then your app can do something with the image. Remember that the item provider API is async, and you should handle any errors occurring here.
Let me now hand over to my colleague, Justin, to show it to you in Xcode. Thanks, Tobias. Hello, everyone. My name is Justin. I'm an engineer on the Photos team. I'm here to show you how you can integrate PHPicker into your iOS application. We will build a simple photo preview app that can display user-selected photos on screen. Before we start, let's build and run to see what we have currently.
We have a UIImageView displaying a placeholder image. There's also a "plus" button, but tapping it doesn't do anything right now. So what does it take to complete this app? We're going to do it in two steps. First, we'll support previewing a single image. We want to present the picker when "plus" is tapped and display the selected image on the image view. Then we will add multi-image support.
In addition to what we have with single-selection, if more than one image is selected, a user can display the next selected image by simply tapping on the screen. Okay. Now that we understand what features we want to add, let's start building. The first thing I need to do is to present the picker. I already set up the UI so presentPicker method will be called when "plus" is tapped. We just need to implement this method. To actually present the picker, we will create the picker configuration object first.
Since we are only interested in images, we want to specify the images filter. We don't need to set a selection limit because the default selection limit is one. We will add multi-selection support later. Then we can initialize PHPickerViewController using the configuration object I just created. We want the presenting view controller to receive user selections, so we need to set delegate to "self." We are seeing this compiler error because our view controller didn't conform to the delegate protocol yet.
Let's add the conformance to fix the error. We only need to implement a single method: pickerDidFinishPicking. It will give us an array of PHPickerResult objects. If a user cancels the picker, that array will be empty. We should always dismiss the picker first. Then we can check if we receive any result.
And if the item provider can load images, we will retrieve the image and display it on screen. In your real app, you should also handle the error when the image can't be retrieved. All right. That's all we need to implement single-selection. Let's build and run to see what we have so far. Now, if I tap the "plus" button, the picker will be presented. And then if I select the image... it will be displayed on screen. It worked. It's that easy to use the new PHPicker API.
Great. Let's complete the app by adding multiple selection support. The first thing I need to do is to set selection limit to zero to enable unlimited selection. The great thing about the new async image-loading API is we don't need to load all images up front. We just need to keep a reference to all returned item providers and load images when necessary. So let's do that. Now we have an array to store all picker-returned item providers. We also created an iterator so we can know which selected image is currently displayed. We can create a method to display the next image.
You may notice that this is very similar to our previous single-selection implementation. The only difference is we use the iterator to get the current item provider. Like I mentioned earlier, whenever the screen is tapped, we want to display the next image. So we just need to override touchesEnded and call displayNextImage.
And lastly, we can update our delegate method. So we can delete single-selection first. We just need to save all item providers, create an iterator, and call displayNextImage to display the first image. That's all we need to implement multi-image preview. Let's run the app to see what we built.
I can tap the "plus" button. You may notice that the picker now has that slightly different UI. That's because the picker knows we're in multi-selection mode. We'll also show the staging area and also the "add" button on the top right corner. I can select a couple images... and tap "add." The first image is correctly displayed on-screen. It is as fast as single-selection mode because we don't need to load other images at all. And if I tap the screen, the next image will be displayed. Tap it again and again and again until I reach the end.
That's it for the demo. Now, back to slides. As seen in the demo, you don't need to prompt for Photos Library access to use PHPicker. Actually, for most apps that only want photo and video data, you don't need to use PhotoKit at all. But at the same time, we know that some PhotoKit-based apps want to get user-selected PHAssets from the picker. So let's talk about how you can do that. Before we dive into the API, let's reconsider what types of apps can benefit from using PhotoKit. For example, if your app supports non-destructive image editing or has Photos Library organization features... you need to use PhotoKit.
But please make sure you only request Photos Library access when necessary and handle the case where Photos Library access is denied by the user. Let's look at some code now. Using PHPicker with PhotoKit is very simple. You just need to initialize PHPickerConfiguration with a PHPhotoLibrary object. Then you can get asset identifiers in your delegate callback, and you can fetch PHAssets using asset identifiers you received through standard PhotoKit API.
In iOS 14, we also introduced a new feature called Limited Photos Library. If your app doesn't use PhotoKit, you don't need to worry about that. For apps asking for Photos Library access, we will show a third "Select Photos" option in the user prompt in addition to the existing "Allow Access" and "No Access" options. The new option will only allow your app to access a portion of PHAssets in a user's Photos Library. We believe it can enable users to better control their privacy.
If a user places your app under Limited Photos Library, there's a couple things you need to keep in mind. First, the picker will still show the entire Photos Library, and all photos and videos can be selected by the user. Second, no matter what users select in the picker, PHAssets you can access will not change.
If you want to request access to additional PHAssets, there's a separate API for you to do that. For more information, please refer to "Handle the Limited Photos Library in Your App" session. Now, back to Tobias to wrap up this session. Thank you, Justin. Let's talk about some best practices and summarize what you've just learned.
First, let's start with a deprecation reminder. AssetsLibrary has been deprecated years ago, and is still deprecated. If your app needs access to the Photos Library, please switch over to PhotoKit. AssetsLibrary will eventually go away. The other deprecation announcement today is about the Photos Library portion of UIImagePickerController. It is being deprecated, and we encourage you to adopt PHPickerViewController instead.
If your app needs access to images or videos, we really encourage you to adopt the new PHPicker instead of writing your own custom picker UI. It supports multi-select, search, and has a consistent UI with the main Photos app, so your users already know how to get to their images and videos. Also, please don't prompt for Photos Library access before showing the picker, and don't require the user to grant you access before showing the picker. There is no need to do any of this, and it doesn't help with your user's trust into your app.