Skip to main content

How to let users import videos using PhotosPicker

About 3 minSwiftSwiftUIArticle(s)bloghackingwithswift.comcrashcourseswiftswiftuixcodeappstore

How to let users import videos using PhotosPicker 관련

SwiftUI by Example

Back to Home

How to let users import videos using PhotosPicker | SwiftUI by Example

How to let users import videos using PhotosPicker

Updated for Xcode 15

New in iOS 16

SwiftUI's PhotosPicker allows users to select videos and bring them into our app, but in my experience it needs to be used in a fairly precise way to avoid problems.

I'll show you the code first, then explain why it takes as much work as it does:

import AVKit
import PhotosUI
import SwiftUI

struct Movie: Transferable {
    let url: URL

    static var transferRepresentation: some TransferRepresentation {
        FileRepresentation(contentType: .movie) { movie in
            SentTransferredFile(movie.url)
        } importing: { received in
            let copy = URL.documentsDirectory.appending(path: "movie.mp4")

            if FileManager.default.fileExists(atPath: copy.path()) {
                try FileManager.default.removeItem(at: copy)
            }

            try FileManager.default.copyItem(at: received.file, to: copy)
            return Self.init(url: copy)
        }
    }
}

struct ContentView: View {
    enum LoadState {
        case unknown, loading, loaded(Movie), failed
    }

    @State private var selectedItem: PhotosPickerItem?
    @State private var loadState = LoadState.unknown

    var body: some View {
        VStack {
            PhotosPicker("Select movie", selection: $selectedItem, matching: .videos)

            switch loadState {
            case .unknown:
                EmptyView()
            case .loading:
                ProgressView()
            case .loaded(let movie):
                VideoPlayer(player: AVPlayer(url: movie.url))
                    .scaledToFit()
                    .frame(width: 300, height: 300)
            case .failed:
                Text("Import failed")
            }
        }
        .onChange(of: selectedItem) { _ in
            Task {
                do {
                    loadState = .loading

                    if let movie = try await selectedItem?.loadTransferable(type: Movie.self) {
                        loadState = .loaded(movie)
                    } else {
                        loadState = .failed
                    }
                } catch {
                    loadState = .failed
                }
            }
        }
    }
}

Download this as an Xcode projectopen in new window

Yes, that's a lot, so let me break it down.

First, we need to import AVKit in order to have access to the VideoPlayer view, and we need PhotosUI to have access to the PhotosPicker view.

Second, the custom Movie struct is how we tell SwiftUI to import movie data. It can send data using Transferable by converting its URL into a SentTransferredFile, which means we can drag Movie instances out of an app, for example. It can also receive data using the importing closure: it copies the movie URL to our documents directory as “movie.mp4”, removing any existing file.

Third, importing a movie can take some time, so we need to make sure the user has some idea of our import state while the app runs. This is handled through an enum with four cases: unknown when the app starts, loading to show a progress spinner, loaded when we have a finished Movie to work with, and failed when the import failed for some reason.

Finally, in the onChange() modifier we ask the system to give us a Movie instance so we accept the URL and move it into the correct location for our app to use. This also takes care of setting the loadState property so our UI stays in sync.

Hopefully Apple can find a way to simplify this API in the future, but until then I'd certainly be keen to hear suggestions to make this code simpler!

Similar solutions…
Article(s) > How to let users select pictures using PhotosPicker

How to let users select pictures using PhotosPicker
How to let users share content using the system share sheet | SwiftUI by Example

How to let users share content using the system share sheet
How to let users delete rows from a list | SwiftUI by Example

How to let users delete rows from a list
How to let users pick options from a menu | SwiftUI by Example

How to let users pick options from a menu
How to let users find and replace text | SwiftUI by Example

How to let users find and replace text

이찬희 (MarkiiimarK)
Never Stop Learning.