文件提供程序扩展,importDocumentAtURL:: 无法读取给定 URL 处的文件(iOS 11.4.1)
File Provider Extension, importDocumentAtURL:: can't read file at given URL (iOS 11.4.1)
我在将操作粘贴到文件提供程序扩展中的容器时遇到问题。
如果我将复制的图像或文本粘贴到文件应用程序 -> 我的应用程序 -> 任何文件夹中,则无法读取位于 fileURL 的文件(因此无法上传到我的服务器,也无法在本地存储)。
- (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;
...
readErrorMessage 和 copyErrorMessage 都是:
无法打开文件“text.txt”,因为您没有查看它的权限。
我做错了什么?
谢谢。
更新: 从我的容器、iCloud 容器复制的任何文件,以及从系统剪贴板的 text/image/other 数据生成的合成文件都会发生这种情况。
看起来您正在开发安全范围的 URL。
根据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.
因此您需要在url 处的文件被复制之前调用startAccessingSecurityScopedResource。你的代码可能会变成。
- (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];
}
我在将操作粘贴到文件提供程序扩展中的容器时遇到问题。
如果我将复制的图像或文本粘贴到文件应用程序 -> 我的应用程序 -> 任何文件夹中,则无法读取位于 fileURL 的文件(因此无法上传到我的服务器,也无法在本地存储)。
- (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;
...
readErrorMessage 和 copyErrorMessage 都是:
无法打开文件“text.txt”,因为您没有查看它的权限。
我做错了什么?
谢谢。
更新: 从我的容器、iCloud 容器复制的任何文件,以及从系统剪贴板的 text/image/other 数据生成的合成文件都会发生这种情况。
看起来您正在开发安全范围的 URL。
根据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.
因此您需要在url 处的文件被复制之前调用startAccessingSecurityScopedResource。你的代码可能会变成。
- (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];
}