处理应用程序:Open URL:SourceApplication:在iOS应用程序中打开文件

2022-08-19 00:00:00 file-io objective-c ios icloud ios11

我有一个应用程序,它使用了一些已知的大文件格式,并支持"打开方式..."IOS自IOS4以来的功能。

直到最近还运行得很好,某些应用程序,比如iOS内置的Mail应用程序,会通过在我的应用程序内的~/Documents/Inbox目录中创建一个副本来打开应用程序,生活很好。

我最近意识到这样一个事实:"在……开放"不再适用于我的应用程序,至少当iCloud/Dropbox/GoogleDrive通过iOS11+内置文件应用程序从iCloud/Dropbox/GoogleDrive获取文件时,我想知道我是否遗漏了什么。

检查代码后,我开始认为我肯定遗漏了一些非常明显的东西,因为代码似乎正确地不打开文件,因为给定的路径无效或我的应用程序没有读取它们所需的权限。

这是我的代码:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)urlToOpen sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
    if([urlToOpen isFileURL])  // <<< this goes through
    {
        if([[NSFileManager defaultManager] isReadableFileAtPath:urlToOpen.path])
        {
            // <<< this doesn't
        }
   }
}

工作路径示例:

/private/var/mobile/Containers/Data/Application/F99A3EA4-457C-4043-AEB3-A9D961184360/Documents/plane.obj
/private/var/mobile/Containers/Data/Application/F99A3EA4-457C-4043-AEB3-A9D961184360/Documents/Inbox/cube.obj

不起作用的路径示例:

/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/somedir/somefile.ext
/private/var/mobile/Containers/Shared/AppGroup/A7FA40A0-2C7D-4FC1-BF21-A8E88B106FF9/File Provider Storage/7791941/local-storage/L3dzX3JhZmFfemFiYWxhL2Jhc2VvcmNfbWVzaC5vYmo=/somefile.ext

如您所见,两个正常工作的文件都已将其数据复制到设备中的本地应用程序目录中。

如何打开这些文件?请注意,我提到应用程序使用大文件,因为它使用大文件,所以我无法在内存中获取这些文件的副本,这不会有太大帮助,我需要获取文件路径,这样我才能在正确的时间执行内存映射并加载所需的内容。

我读过一些关于就地打开等的内容,但它并不适用于我正在开发的应用程序类型,因为它不是在单个"元素"上操作的。我提到的大文件只是可能的来源之一,因此我所看到的关于就地打开的情况不适用于我的情况。

有没有办法让应用程序能够直接访问这些文件,或者至少将它们复制到我的应用程序沙盒临时目录中,以便我可以直接对它们进行内存映射?

干杯!


解决方案

我就这件事联系了苹果,因为它没有太大的意义,文档中提到了要使用的方法,但你真的需要深入挖掘,这并不是完全显而易见的,因为它在不同的非逻辑位置提到。

事实证明,AppDelegate中提供的NSURL是受保护的,您最安全的选择是读取它们或将它们复制到本地驱动器。

我得到的结果是:

NSString* urlPath = url.path;
if(![[NSFileManager defaultManager] isReadableFileAtPath:urlPath])
{
    if([url startAccessingSecurityScopedResource])
    {
        NSString* docsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString* destPath = [NSString stringWithFormat:@"%@/%@", docsPath, [url.path lastPathComponent]];
        urlPath = [FileHandler copyFileAtPath:url.path toPath:destPath increment:YES];
        [url stopAccessingSecurityScopedResource];
    }
}

其中,CopyFileAtPath:toPath:Increate是一个自定义函数,它只是复制文件并在文件存在时递增以避免覆盖,但可以是任何实际的文件。

这里的关键方法是[NSURL startAccessingSecurityScopedResource]和[NSURL stopAccessingSecurityScopedResource],需要注意的是,它们必须成对调用(Start/Stop),因为调用Stop失败可能会导致问题,因此复制方法非常有效,特别是当这些文件要进行内存映射时。(我的箱子很大)

相关文章