0

我在将操作粘贴到文件提供程序扩展中的容器时遇到问题。

如果我将复制的图像或文本粘贴到文件应用程序 -> 我的应用程序 -> 任何文件夹中,则无法读取 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 容器复制的任何文件以及从系统剪贴板中的文本/图像/其他数据生成的合成文件都会发生这种情况。

4

1 回答 1

2

看起来您正在处理安全范围的 URL。

根据文档选择器编程指南

任何访问其沙盒外文档的应用程序都必须满足以下要求:

  • 您的应用程序必须使用文件协调执行所有文件读取和写入操作。

  • 如果您向用户显示文档的内容,则必须使用文件展示器跟踪文档的状态。如果您只显示文件列表,则不需要文件演示器。

  • 不要保存通过打开或移动操作访问的任何 URL。始终使用文档选择器、元数据查询或 URL 的安全范围书签打开文档。

  • 这些操作返回安全范围的 URL。您必须在访问 URL 之前调用startAccessingSecurityScopedResource 。

  • 如果startAccessingSecurityScopedResource返回 YES,请在使用完文件后调用stopAccessingSecurityScopedResource 。

  • 如果您使用的是 UIDocument 子类,它将自动为您使用安全范围的 URL。无需调用startAccessingSecurityScopedResourcestopAccessingSecurityScopedResource。UIDocument 还充当文件呈现器并自动处理文件协调。由于这些原因,强烈建议对应用沙箱之外的所有文件使用 UIDocument 子类。

因此,您需要在复制此 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:&copyError];
  NSString *copyErrorMessage = copyError.localizedDescription;

  // ....
  // Call |stopAccessingSecurityScopedResource| after everything is done.
  [fileURL stopAccessingSecurityScopedResource];
}
于 2018-09-11T02:27:18.420 回答