【问题标题】:File Provider Extension, importDocumentAtURL:: can't read file at given URL (iOS 11.4.1)文件提供程序扩展,importDocumentAtURL:: 无法读取给定 URL 的文件 (iOS 11.4.1)
【发布时间】:2018-09-06 07:30:16
【问题描述】:

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

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

【问题讨论】:

    标签: ios objective-c fileprovider-extension


    【解决方案1】:

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

    根据Document Picker Programming Guide

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

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

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

    • 不要保存通过打开或移动操作访问的任何 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];
    }
    

    【讨论】:

    • 就是这样。非常感谢。但请将您的代码更改更正为 [fileURL start|stop AccessingSecurityScopedResource];
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 2019-09-14
    • 2013-07-25
    相关资源
    最近更新 更多