Расширение поставщика файлов, importDocumentAtURL:: невозможно прочитать файл по указанному URL (iOS 11.4.1)
У меня проблемы с вставкой операций в мои контейнеры в расширении File Provider.
Если я вставляю скопированное изображение или текст в приложение "Файлы" -> "Моё приложение" -> в любую папку, файл в 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" не может быть открыт, потому что у вас нет разрешения на его просмотр.
Что я здесь не так делаю?
Благодарю.
UPD: это происходит с любым файлом, скопированным из моего контейнера, контейнера iCloud, а также с синтетическими файлами, созданными из текста / изображения / других данных из системного буфера обмена.
1 ответ
Похоже, вы работаете над безопасным URL.
Согласно Руководству по программированию средства выбора документов
Любое приложение, которое обращается к документам вне своей песочницы, должно отвечать следующим требованиям:
Ваше приложение должно выполнять все операции чтения и записи файлов, используя координацию файлов.
Если вы отображаете содержимое документа пользователю, вы должны отслеживать состояние документа с помощью файлового предъявителя. Если вы показываете только список файлов, файл-презентатор не нужен.
Не сохраняйте URL-адреса, доступ к которым осуществляется с помощью операций открытия или перемещения. Всегда открывайте документ, используя средство выбора документа, запрос метаданных или закладку в области безопасности для URL-адреса.
- Эти операции возвращают URL-адреса безопасности. Вы должны вызвать startAccessingSecurityScopedResource перед доступом к URL.
- Если startAccessingSecurityScopedResource возвращает YES, вызовите stopAccessingSecurityScopedResource, когда вы закончите использовать файл.
- Если вы используете подкласс UIDocument, он автоматически использует URL-адреса безопасности. Нет необходимости вызывать startAccessingSecurityScopedResource или stopAccessingSecurityScopedResource. UIDocument также действует как средство представления файлов и автоматически управляет согласованием файлов. По этим причинам использование подкласса UIDocument настоятельно рекомендуется для всех файлов за пределами песочницы вашего приложения.
Поэтому вам нужно вызвать startAccessingSecurityScopedResource, прежде чем файл по этому URL будет скопирован. Ваш код может стать.
- (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];
}