func fetchContents(for itemIdentifier: NSFileProviderItemIdentifier, version requestedVersion: NSFileProviderItemVersion?, request: NSFileProviderRequest, completionHandler: @escaping (URL?, NSFileProviderItem?, Error?) -> Void) -> Progress { os_log("fetchContents: Called with itemIdentifier = %{public}@, version = %{public}@]", log: OSLog.fileprovider, itemIdentifier.rawValue, requestedVersion.debugDescription) let progress = Progress(totalUnitCount: 1) let identifierComponents = itemIdentifier.rawValue.components(separatedBy: "/") assert(identifierComponents.count == 2, "identifierComponents != 2") let photoIdentifier = identifierComponents[0] let filename = identifierComponents[1] os_log("fetchContents: photoIdentifier = %{public}@, filename = %{public}@", log: OSLog.fileprovider, photoIdentifier, filename) let request = LibraryClient.shared.downloadRequest(identifier: photoIdentifier) let urlSession = URLSession(configuration: LibraryClient.shared.getConfigurationFile()) // Download the file to disk. let urlSessionDownloadTask = urlSession.downloadTask(with: request) { temporaryURL, response, error in if let error = error { os_log("fetchContents: Error: %{public}@", log: OSLog.fileprovider, error.localizedDescription) completionHandler(nil, nil, error) return } guard let httpStatusCode = HTTPUtils.getStatusCode(from: response) else { os_log("fetchContents: This is not supposed to happen. httpStatusCode was nil.") return } if (httpStatusCode != 200) { os_log("fetchContents: Download task for item identifier %{public}@ failed with http status code %ld", log: OSLog.fileprovider, itemIdentifier.rawValue, httpStatusCode) completionHandler(nil, nil, NSError.fileProviderErrorForNonExistentItem(withIdentifier: itemIdentifier)) return } os_log("fetchContents: Download task for item identifier %{public}@ succeeded with http status code %ld", log: OSLog.fileprovider, itemIdentifier.rawValue, httpStatusCode) // At this point, we know that the file download succeeded // Let's check the url value - the file is put somewhere in the /var/folders directory as .tmp file // Example file: // file:///var/folders/8z/b57tvxbj7_x9ckvjq_fb9k680000gp/T/com.foo.GiraffeApp.GiraffeFileProvider/CFNetworkDownload_sSqXW4.tmp if let url = temporaryURL { do { os_log("fetchContents: Temporary file URL for item identifier %{public}@ is %{public}@", itemIdentifier.rawValue, url.absoluteString) // We have to return a url AND a FileProviderItem here, otherwise, the app will crash and burn let fileProviderItems = FileProviderItemManager.shared.fileProviderItems assert(fileProviderItems.count > 0, "fileProviderItems is 0") var fileProviderItem: NSFileProviderItem? = nil for item in fileProviderItems { if item.itemIdentifier == itemIdentifier { fileProviderItem = item continue } } let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let rootPathToFile = documentDirectory.appendingPathComponent(filename) var mappedDataOrNil: Data? = nil mappedDataOrNil = try Data(contentsOf:url, options: Data.ReadingOptions.alwaysMapped) try mappedDataOrNil?.write(to: rootPathToFile) assert(fileProviderItem != nil, "fileProviderItem is nil") //completionHandler(temporaryURL, fileProviderItem, nil) completionHandler(rootPathToFile, fileProviderItem, nil) return } catch{ } } else { os_log("fetchContents: File URL for item identifier %{public}@ is nil", itemIdentifier.rawValue) } } // Add the download task's progress as a child to the overall progress. progress.addChild(urlSessionDownloadTask.progress, withPendingUnitCount: 1) // Start the download task. urlSessionDownloadTask.resume() return progress }