Reputation: 152
I'm having troubles with Paste opertaions into my containers in File Provider extension.
If I paste copied image or text into Files app -> My App -> any folder the file at fileURL can not be read (as a result can't be uploaded to my servers nor stored locally).
- (void)importDocumentAtURL:(NSURL *)fileURL
toParentItemIdentifier:(NSFileProviderItemIdentifier)parentItemIdentifier
completionHandler:(void (^)(NSFileProviderItem _Nullable importedDocumentItem, NSError * _Nullable error))completionHandler
{
NSError *readError = nil;
NSData *fileData = [NSData dataWithContentsOfURL:fileURL options:NSDataReadingMappedAlways error:&readError];
NSString *readErrorMessage = readError.localizedDescription;
NSURL *myFileURL = [NSFileProviderManager.defaultManager.documentStorageURL URLByAppendingPathComponent:@"temp.dat"];
NSError *copyError = nil;
BOOL copyResult = [_fileManager copyItemAtURL:fileURL toURL:myFileURL error:©Error];
NSString *copyErrorMessage = copyError.localizedDescription;
...
Both readErrorMessage and copyErrorMessage are:
The file “text.txt” couldn’t be opened because you don’t have permission to view it.
What am I doing wrong here?
Thanks.
UPD: This happens to any file copied from my container, iCloud container, as well as synthetic files produced from text/image/other data from system Clipboard.
Upvotes: 0
Views: 902
Reputation: 12144
Looks like you are working on a security-scoped URL.
According to Document Picker Programming Guide
Any app that accesses documents outside its sandbox must meet the following requirements:
Your app must perform all file read and write operations using file coordination.
If you display the contents of the document to the user, you must track the document’s state using a file presenter. If you’re only showing a list of files, a file presenter is not necessary.
Do not save any URLs accessed through open or move operations. Always open the document using a document picker, a metadata query, or a security-scoped bookmark to the URL.
These operations return security-scoped URLs. You must call startAccessingSecurityScopedResource before accessing the URL.
If startAccessingSecurityScopedResource returns YES, call stopAccessingSecurityScopedResource when you are done using the file.
If you are using a UIDocument subclass, it will automatically consume the security-scoped URLs for you. There’s no need to call startAccessingSecurityScopedResource or stopAccessingSecurityScopedResource. UIDocument also acts as a file presenter and automatically handles file coordination. For these reasons, using a UIDocument subclass is highly recommended for all files outside your app’s sandbox.
So you need to call startAccessingSecurityScopedResource before the file at this url is copied. Your code may become.
- (void)importDocumentAtURL:(NSURL *)fileURL
toParentItemIdentifier:(NSFileProviderItemIdentifier)parentItemIdentifier
completionHandler:(void (^)(NSFileProviderItem _Nullable importedDocumentItem, NSError * _Nullable error))completionHandler
{
NSError *readError = nil;
NSData *fileData = [NSData dataWithContentsOfURL:fileURL options:NSDataReadingMappedAlways error:&readError];
NSString *readErrorMessage = readError.localizedDescription;
NSURL *myFileURL = [NSFileProviderManager.defaultManager.documentStorageURL URLByAppendingPathComponent:@"temp.dat"];
// Call |startAccessingSecurityScopedResource| before working on the url
[fileURL startAccessingSecurityScopedResource];
NSError *copyError = nil;
BOOL copyResult = [_fileManager copyItemAtURL:fileURL toURL:myFileURL error:©Error];
NSString *copyErrorMessage = copyError.localizedDescription;
// ....
// Call |stopAccessingSecurityScopedResource| after everything is done.
[fileURL stopAccessingSecurityScopedResource];
}
Upvotes: 2