I've file provider implementation where, in some cases, we must force download items, so they get materialized in local cache.
I've used requestdownloadforitem based on following documentation
https://developer.apple.com/documentation/fileprovider/nsfileprovidermanager/requestdownloadforitem(withidentifier:requestedrange:)
I'm calling this within Extension code, but this does not trigger the download.
How can I force file provider to download a file?
cheers,
File Provider
RSS for tagAllow other apps to access the documents and directories stored and managed by your containing app using File Provider.
Posts under File Provider tag
76 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
I am developing a file provider extension on Mac.
I noticed when attempting to delete an enumerated folder with didDeleteItems, passing only the top-level folder's ID is not enough to delete the item. It seems we need to pass all items underneath as well to this function for the folder to be removed.
Is there a way around this? The way our application is designed makes it challenging to do this and we would prefer being able to remove the folder by utilizing the item ID only.
If not, how could we obtain the particular items underneath that should be passed in to the function?
In the context of a NSFileProviderReplicatedExtension I would like to only see the "Move to Bin" Finder action when files have been materlialised ( isDownloaded fileprovider attribute )
I thought it might be possible to get the isDownloaded attribute in my NSFileProviderItemProtocol class capabilities method but that doesn't seem to be the case.
Possible ?
A have the application with iOS and Mac Catalyst versions and I need to make a cloud client for the app's documents. FileProvider would be the great choice for this feature, but I can't believe it doesn't support Mac Catalyst.
At this moment I'm almost certain that NSFileProviderReplicatedExtension does not support Mac catalyst officially. And if it so, It would be great to hear the exact status and future plans if any.
Unofficially, I managed to run it.
I switched the extension's target Supported Destination from Mac Catalyst to Mac and it started to compile. This move seems legit to me.
But domain also had to be created, and this part was a way trickier. I've added new bundle to host app(iOS and catalyst), but with supported platform - macOS in build settings. There I created an NSObject subclass DomainManager which calls NSFileProviderManager's addDomain method in its createDomainIfNeeded(), which is also exposed in public extension to NSObject - a kind of "informal protocol"
The catalyst app creates bundle by name and loads principal class (DomainManager), but as NSObject reference, and then calls createDomainIfNeeded() method on it.
The location defined by domain appears in Finder sidebar, and the dataless item "a file" appears in this location, as defined by stub implementation in the extension enumerator method. This means file system instantiated the extension instance under Mac catalyst and called the protocol method on it. I.e. it seem to work.
But the question is whether this solution is stable and legit for the App Store distribution. Or is it pandora box with unforeseeable consequences for user data? Thanks in advance.
I've implemented a file provider for macos, and it works well. Now I'm trying to add partial download support in my implementation. however, it doesn't seem to work.
As per documentation, I've implemented
protocol NSFileProviderPartialContentFetching
and its method
func fetchPartialContents(for: NSFileProviderItemIdentifier, version: NSFileProviderItemVersion, request: NSFileProviderRequest, minimalRange: NSRange, aligningTo: Int, options: NSFileProviderFetchContentsOptions, completionHandler: (URL?, NSFileProviderItem?, NSRange, NSFileProviderMaterializationFlags, (any Error)?) -> Void) -> Progress
Now, I'm testing my implementation, and I open a movie from my File Provider using VLC. I see that
fetchPartialContents get a hit. I download requested range, and return it through completionHandler. However VLC gives a read error.
here is my implementation of fetchPartialContents:
private func align(range: NSRange, to alignment: Int) -> NSRange {
let start = range.location - (range.location % alignment)
let end = range.location + range.length
let alignedEnd = ((end + alignment - 1) / alignment) * alignment
let alignedLength = alignedEnd - start
return NSRange(location: start, length: alignedLength)
}
unc fetchPartialContents(for itemIdentifier: NSFileProviderItemIdentifier, version requestedVersion: NSFileProviderItemVersion, request: NSFileProviderRequest, minimalRange requestedRange: NSRange, aligningTo alignment: Int, options: NSFileProviderFetchContentsOptions = [], completionHandler: @escaping (URL?, NSFileProviderItem?, NSRange, NSFileProviderMaterializationFlags, (any Error)?) -> Void) -> Progress {
let alignedRange = align(range: requestedRange, to: alignment)
let progress = Progress(totalUnitCount: 100)
let data = downloadData(for: alignedRange)
progress.completedUnitCount = 100;
tempFileHandle = try FileHandle(forWritingTo: tempFileURL)
tempFileHandle.seek(toFileOffset: UInt64(alignedRange.location))
tempFileHandle.write(data!)
tempFileHandle.closeFile()
let item = FileProviderItem(identifier: itemIdentifier,)
completionHandler(tempFileURL, item, alignedRange, [], nil)
} catch {
completionHandler(nil, nil, alignedRange, [], error)
}
}
I beleive I'm doing everhting correctly & as per documentation, but certainly there is something is wrong. Can someone help me about it?
cheers,
Using NSFileManager's getFileProviderServicesForItemAtURL method, I can list services made available by a file provider for a given item from an app unrelated to the file provider, obtain a handle to the proxy object and cast that object to the target protocol. However, attempts to invoke the protocol yield:
"The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction."
The documentation for the supportedServiceSourcesForItemIdentifier method implemented by the extension suggests only the app containing the extension can exercise the service but the documentation for getFileProviderServicesForItemAtURL does not. Should I be able to access a service from a file provider extension from an unrelated app? If so, how can the sandbox restriction be addressed?
I am currently developing an app based on a file provider extension and intermittently encounter the error: No valid file provider found with identifier.
Usually, I can mount (addDomain) successfully after building the app, but occasionally this error appears and then disappears after 10-15 minutes
I see these errors from log stream:
2024-07-28 01:01:46.644401+0530 0x1abf0 Default 0x0 6654 0 fileproviderd: (FileProviderDaemon) [com.apple.FileProvider:default] [WARNING] No provider found with identifier (null) for calling bundle <private> on second attempt.
2024-07-28 01:01:47.099043+0530 0x1aac7 Error 0x0 6926 0 mdbulkimport: (FileProvider) [com.apple.FileProvider:default] [ERROR] Cannot query for providers. Error: NSError: Cocoa 4099 "<private>"
2024-07-28 01:01:47.099203+0530 0x1aac7 Error 0x0 6926 0 mdbulkimport: (FileProvider) [com.apple.FileProvider:default] [ERROR] received an error when listing providers, attempting again: Error Domain=NSCocoaErrorDomain Code=4099 UserInfo={NSDebugDescription=<private>} (count: 3)
2024-07-28 01:01:47.100009+0530 0x1aac7 Error 0x0 6926 0 mdbulkimport: (FileProvider) [com.apple.FileProvider:default] [ERROR] Cannot query for providers. Error: NSError: Cocoa 4099 "<private>"
2024-07-28 01:01:47.100141+0530 0x1aac7 Error 0x0 6926 0 mdbulkimport: (FileProvider) [com.apple.FileProvider:default] [ERROR] received an error when listing providers, attempting again: Error Domain=NSCocoaErrorDomain Code=4099 UserInfo={NSDebugDescription=<private>} (count: 2)
2024-07-28 01:01:47.100898+0530 0x1aac7 Error 0x0 6926 0 mdbulkimport: (FileProvider) [com.apple.FileProvider:default] [ERROR] Cannot query for providers. Error: NSError: Cocoa 4099 "<private>"
2024-07-28 01:01:47.101112+0530 0x1aac7 Error 0x0 6926 0 mdbulkimport: (FileProvider) [com.apple.FileProvider:default] [ERROR] received an error when listing providers, attempting again: Error Domain=NSCocoaErrorDomain Code=4099 UserInfo={NSDebugDescription=<private>} (count: 1)
2024-07-28 01:01:47.101951+0530 0x1aac7 Error 0x0 6926 0 mdbulkimport: (FileProvider) [com.apple.FileProvider:default] [ERROR] Cannot query for providers. Error: NSError: Cocoa 4099 "<private>"
2024-07-28 01:01:47.102510+0530 0x1aac7 Error 0x0 6926 0 mdbulkimport: (FileProvider) [com.apple.FileProvider:default] [ERROR] can't get the list of providers: NSError: Cocoa 4099 "<private>"
When the issue occurs, the following command does not list my provider:
fileproviderctl dump
Any help would be greatly appreciated. Thanks!
In NSFileProviderItemProtocol I am able to use the extendedAttributes property call to add my custom extended attributes to my NSFileProviderReplicatedExtension extension files.
Given that the Finder uses com.apple.metadata:kMDItemFinderComment extended attribute for file comments I thought it would be possible to populate my files with useful comments provided by the third part API.
Unfortunately I seems to be unable to do so as if com.apple.metadata.... fields were inaccessible from the FP extension.
Is there any way to achieve this ?
I'm developing an iOS app.
Through a .fileImporter I get access to a directory URL which might be provided by an external service like Dropbox (using a FileProvider).
As the user picked the URL I have full access to it.
I want to get the contents of the directory:
FileManager.default.contentsOfDirectory(
at: url,
includingPropertiesForKeys: keys,
options: [.skipsHiddenFiles]
)
Unfortunately I only get whatever files the system is currently aware of, which in case of external providers is often not much.
If the user opens the Apple Files app and navigates to the folder then the system gets the content from the external provider and back in my app contentsOfDirectory would show everything.
What can I do to get a list of the URLs?
Can I somehow trigger the system to update from the external provider? Or is there another way of handling this situation?
We are trying to access and copy some files [e.g., video file] from another PC on local network using SMB protocol.
We found some third party libraries like AMSMB2 for this.
But we want to try to use Apple inbuilt features like File management mentioned in - https://developer.apple.com/videos/play/wwdc2019/719/
We could able to select file from SMB server using document picker in app manually. Also we got its url in debug which gets generated under "Shared" section in files app.
The URL I get from document picker is -> /private/var/mobile/Library/LiveFiles/com.apple.filesystems.smbclientd/asd0QUsers/testuser/iOS/SMB_ShareFolder
Now we want to avoid manual selection of file to user.We want directly open "/private/var/mobile/Library/LiveFiles/com.apple.filesystems.smbclientd/asd0QUsers/testuser/iOS/SMB_ShareFolder" path as soon as document picker opens. So that user can directly select file. But it is not working. It opens normal files app and all folders.
Getting below error -
Access Shared URL directly using documentPicker "Error - CFURLResourceIsReachable failed because it was passed a URL which has no scheme"
Sharing the code which I tried to open this shared folder directly :
let url = URL (string: "/private/var/mobile/Library/LiveFiles/com.apple.filesystems.smbclientd/asd0QUsers/Pranjali/iOS/SMB_ShareFolder")
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.folder])
documentPicker.delegate = self
documentPicker.allowsMultipleSelection = false
documentPicker.modalPresentationStyle = .custom
documentPicker.definesPresentationContext = true
documentPicker.directoryURL = url!
documentPicker.transitioningDelegate = customTransitioningDelegate
present(documentPicker, animated: true, completion: nil)
I get error in console - CFURLResourceIsReachable failed because it was passed a URL which has no scheme 2024-07-05 17:49:38.501059+0530 VideoImportPOC[1327:336989] [DocumentManager] revealDocumentAtURL encountered an error: Error Domain=NSCocoaErrorDomain Code=262 "The file couldn’t be opened because the specified URL type isn’t supported."
Can you please provide inputs if it is possible to access files directly in this way? or any other suggestions.
We are trying to access and copy some files [e.g., video file] from another PC on local network using SMB protocol.
We found some third party libraries like AMSMB2 for this.
But we want to try to use Apple inbuilt features like File management mentioned in - https://developer.apple.com/videos/play/wwdc2019/719/
We could able to select file from SMB server using document picker in app manually. Also we got its url in debug which gets generated under "Shared" section in files app.
The URL I get from document picker is -> /private/var/mobile/Library/LiveFiles/com.apple.filesystems.smbclientd/asd0QUsers/testuser/iOS/SMB_ShareFolder
Now we want to avoid manual selection of file to user.
We want directly open "/private/var/mobile/Library/LiveFiles/com.apple.filesystems.smbclientd/asd0QUsers/testuser/iOS/SMB_ShareFolder" path
as soon as document picker opens. So that user can directly select file. But it is not working. It opens normal files app and all folders.
Getting below error -
Access Shared URL directly using documentPicker "Error - CFURLResourceIsReachable failed because it was passed a URL which has no scheme"
Sharing the code which I tried to open this shared folder directly :
let url = URL (string: "/private/var/mobile/Library/LiveFiles/com.apple.filesystems.smbclientd/asd0QUsers/TestUser/iOS/SMB_ShareFolder")
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.folder])
documentPicker.delegate = self
documentPicker.allowsMultipleSelection = false
documentPicker.modalPresentationStyle = .custom
documentPicker.definesPresentationContext = true
documentPicker.directoryURL = url!
documentPicker.transitioningDelegate = customTransitioningDelegate
present(documentPicker, animated: true, completion: nil)
I get error in console - CFURLResourceIsReachable failed because it was passed a URL which has no scheme
2024-07-05 17:49:38.501059+0530 VideoImportPOC[1327:336989] [DocumentManager] revealDocumentAtURL encountered an error: Error Domain=NSCocoaErrorDomain Code=262
"The file couldn’t be opened because the specified URL type isn’t supported."
Can you please provide inputs if it is possible access files directly in this way? or any other suggestions.
like 1
What’s New in File Management and Quick Look - WWDC19 - Videos - Apple Developer
Your iOS app can now access files stored on external devices via USB and SMB. Understand best practices for creating a document-based app...
I need to disallow folder renaming on my NSFileProviderReplicatedExtension extension as my foreign API system changes the asset id when a folder gets renamed and I can't retrieve or compute the new ID.
For this reason I disable .allowsRenaming on folders for this volume but the Finder will still trigger the two step create "untitled folder" / rename when creating new folders.
I can see that existing folders can't be renamed on the volume so the capability seems properly managed by my extension.
Is there a way to prevent the creation of the "untitled folder" folder when creating new folders in Finder on a folder with renaming disabled ?
Currently, there must be a request for access to documents with xcode, but we do not request access.
Added NSDocumentDirectoryUsageDescription to info.
import SwiftUI
import AVFoundation
import UniformTypeIdentifiers
struct ContentView: View {
@State private var audioPlayer: AVAudioPlayer?
@State private var isPlaying = false
@State private var currentFileName: String = "No file selected"
@State private var showingDocumentPicker = false
@State private var songList: [String] = UserDefaults.standard.stringArray(forKey: "SavedSongs") ?? []
@State private var currentSongIndex: Int = 0
var body: some View {
VStack {
Text(currentFileName)
.font(.headline)
.padding()
List {
ForEach(songList, id: \.self) { song in
HStack {
Text(song)
.onTapGesture {
loadAndPlaySong(named: song)
}
Spacer()
Button(action: {
removeSong(named: song)
}) {
Image(systemName: "trash")
.foregroundColor(.red)
}
}
}
}
.listStyle(PlainListStyle())
HStack(spacing: 10) {
Button(action: {
showingDocumentPicker = true
}) {
Text("Load")
.font(.system(size: 12))
.frame(width: 50, height: 25)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(5)
}
.padding(.bottom, 20)
}
.padding()
.sheet(isPresented: $showingDocumentPicker) {
DocumentPicker(audioPlayer: $audioPlayer, currentFileName: $currentFileName, songList: $songList)
}
.onAppear {
if !songList.isEmpty {
loadAndPlaySong(named: songList[currentSongIndex])
}
}
}
func playSong() {
audioPlayer?.play()
isPlaying = true
}
func pauseSong() {
audioPlayer?.pause()
isPlaying = false
}
func stopSong() {
audioPlayer?.stop()
audioPlayer?.currentTime = 0
isPlaying = false
}
func nextSong() {
currentSongIndex = (currentSongIndex + 1) % songList.count
loadAndPlaySong(named: songList[currentSongIndex])
}
func previousSong() {
currentSongIndex = (currentSongIndex - 1 + songList.count) % songList.count
loadAndPlaySong(named: songList[currentSongIndex])
}
func loadAndPlaySong(named songName: String) {
guard let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileURL = documentsURL.appendingPathComponent(songName)
do {
audioPlayer = try AVAudioPlayer(contentsOf: fileURL)
audioPlayer?.prepareToPlay()
currentFileName = songName
playSong()
} catch {
print("Error loading file: \(error.localizedDescription)")
}
}
func removeSong(named songName: String) {
songList.removeAll { $0 == songName }
UserDefaults.standard.set(songList, forKey: "SavedSongs")
}
}
struct DocumentPicker: UIViewControllerRepresentable {
@Binding var audioPlayer: AVAudioPlayer?
@Binding var currentFileName: String
@Binding var songList: [String]
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.audio])
documentPicker.delegate = context.coordinator
return documentPicker
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}
class Coordinator: NSObject, UIDocumentPickerDelegate {
let parent: DocumentPicker
init(_ parent: DocumentPicker) {
self.parent = parent
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard let url = urls.first else { return }
do {
if url.startAccessingSecurityScopedResource() {
defer { url.stopAccessingSecurityScopedResource() }
let fileName = url.lastPathComponent
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let destinationURL = documentsURL.appendingPathComponent(fileName)
if FileManager.default.fileExists(atPath: destinationURL.path) {
try FileManager.default.removeItem(at: destinationURL)
}
try FileManager.default.copyItem(at: url, to: destinationURL)
parent.audioPlayer = try AVAudioPlayer(contentsOf: destinationURL)
parent.audioPlayer?.prepareToPlay()
parent.currentFileName = fileName
if !parent.songList.contains(fileName) {
parent.songList.append(fileName)
UserDefaults.standard.set(parent.songList, forKey: "SavedSongs")
}
} else {
print("I can't get file access.")
}
} catch {
print("An error occurred while loading the file: \(error.localizedDescription)")
}
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
}
}
}
My company has developed a desktop-Mac FileProvider extension which presents a user with shared encrypted folders; it's working well except for one issue. While we can handle moving an encrypted folder, there seems to be no way to detect that an encrypted folder has been copied or duplicated.
Is there any equivalent to the Windows shell extension copy-hook handler, which can allow NSReplicatedFileProviderExtension (or some other portion of the system) to detect that a folder is being copied?
Is it possible to notify my fileprovider extension to pre-load folders recursively from a given starting point ?
I am currently doing this externally from user space with a thread that crawls through the folder tree but wondering if there is a better way.
I am developing a Mac File Provider Extension. When testing installation from-scratch, The File Provider Name does appear on the side bar. However, the text '[App Name] encountered an unexpected error. Items may be out of date .....Try Again' appears at the top of the Finder window when opening the File Provider's Domain. Along with this text, there is a persistent 'Loading...' that is displayed in the middle of the Finder view. The File Provider seems to immediately get in a bad state.
This does not happen at all during development.
I am also noticing some logs in console that indicate some sort of issue. These 3 seem to be relevant. Any ideas or insight what could be going on?
create-item(propagated:<root dbver:0 domver:<nil>>) why:itemChangedRemotely|diskImport sched:default.1717009685.233681#1717009069.3164978 error:<NSError: Cocoa 4101 "Couldn’t communicate with a helper application." Underlying={NSError: NSFileProviderInternalErrorDomain 7 "A connection to the extension “REMOVED ID” could not be made." Underlying={NSError: com.apple.extensionKit.errorDomain 2 "The operation couldn’t be completed. (com.apple.extensionKit.errorDomain error 2.)" UserInfo={(omitted)}}}}}>> → <requested:<p:root n:"i{31}e" dir child:0 m:rwxS ct:1717009068.969699 mt:1717009068.969699>> [duration 33ms44µs]
Failed to create extensionProcess for extension 'REMOVED ID' error: Error Domain=com.apple.extensionKit.errorDomain Code=2 "(null)" UserInfo={NSUnderlyingError=0x7fa0ce9d28b0 {Error Domain=com.apple.extensionKit.errorDomain Code=2 "(null)" UserInfo={NSUnderlyingError=0x7fa0ce9d2ad0 {Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x7fa0ce9d33e0 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo=0x7fa0ce9d2900 (not displayed)}}}}}}
Launch failed with error: Error Domain=com.apple.extensionKit.errorDomain Code=2 "(null)" UserInfo={NSUnderlyingError=0x7fa0ce9d2ad0 {Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x7fa0ce9d33e0 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}}}
I want to traverse my local Google Drive folder to calculate the size of all the files on my drive.
I'm not interested in files or directories that are not present locally.
I use getattrlistbulk for traversing and it takes way too much time. I think it is because FileProvider tries to download metadata for the directories that are not yet materialised.
Is there a way to skip non-materialised directories?
When upgrading to macOS 14.5, the FileProvider extension is consistently restarted by the system. This issue was not encountered with macOS 14.0, where the FileProvider extension typically remained uninterrupted.
Additionally, I observed that when adding multiple domains using the same process, only one FileProvider extension would operate in 14.0, whereas in 14.5, a separate extension runs for each domain.
I haven't found any release notes mentioning this change. Is this behavior intended?
I also have filled a feedback FB13810567.
I am developing a FileProvider extension on Mac. I was wondering what the most reliable way to evict a document as soon as possible after createItem is called for the respective item.
Our use-case for this is as follows:
Users can 'bulk-import' items into a FileProvider folder, and we want our application to immediately evict the item as soon as possible once the item's content is uploaded to the server. This is to save space on the user's machine.
So, what is the best way to accomplish immediate eviction after item creation?
I've tried calling evictItem from within the createItem function itself, but that yields many errors and can cause slowness.
I am developing a File Provider on Mac. I am marking some items within the domain as 'shared' via the NSFileProviderItemProtocol. However, the text 'Folder shared on iCloud by me' appears in Finder when these items are marked as shared.
Is this correct? My provider has nothing to do with iCloud, which is, of course, the cloud developed by Apple. Is there a way to change this text or remove it?
I've attached an image that shows the problem.