Расширение поставщика файлов, importDocumentAtURL :: невозможно прочитать файл по заданному URL-адресу (iOS 11.4.1) - PullRequest
0 голосов
/ 06 сентября 2018

У меня проблемы с вставкой операций в мои контейнеры с расширением 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:&copyError];
    NSString *copyErrorMessage = copyError.localizedDescription;

    ...

И readErrorMessage, и copyErrorMessage:

Файл «text.txt» не может быть открыт, поскольку у вас нет разрешения на его просмотр.

Что я здесь не так делаю?

Спасибо.

UPD: Это происходит с любым файлом, скопированным из моего контейнера, контейнера iCloud, а также с синтетическими файлами, созданными из текста / изображения / других данных из системного буфера обмена.

1 Ответ

0 голосов
/ 11 сентября 2018

Похоже, вы работаете с 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:&copyError];
  NSString *copyErrorMessage = copyError.localizedDescription;

  // ....
  // Call |stopAccessingSecurityScopedResource| after everything is done.
  [fileURL stopAccessingSecurityScopedResource];
}
...