处理应用程序:openURL:sourceApplication:在iOS应用程序中打开文件

时间:2018-11-29 11:07:48

标签: ios objective-c file-io ios11 icloud

我有一个使用某些已知的大文件格式的应用程序,并且自iOS4天以来一直支持iOS的“打开于...”功能。

直到最近运行良好,某些应用程序(例如iOS内置Mail应用程序)会通过在应用程序的〜/ Documents / Inbox目录中创建副本来打开该应用程序,

最近我已经意识到“打开...”不再适用于我的应用程序的事实,至少在文件通过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

您会看到两个有效的文件都将其数据复制到设备中的本地应用程序目录中。

如何打开这些文件?请注意,我提到该应用程序使用大文件是因为它使用大文件,因此我无法获得它们的内存副本,这不会有太大帮助,我需要获取文件路径以便可以进行内存映射并在适当的时间加载所需的内容。

我已经阅读了一些有关就地打开等内容,但是它不适用于我正在开发的应用程序类型,因为它不能在单个“元素”上运行,我提到的大文件只是其中之一可能的来源,因此像我所看到的有关就地开庭的内容不适用于我的情况。

是否有一种方法可以使应用程序直接访问这些文件,或者至少将它们复制到我的应用程序沙盒临时目录中,以便我可以直接在内存中映射它们?

干杯!

2 个答案:

答案 0 :(得分:1)

我就此事与苹果公司联系,因为这没有多大意义,文档中提到了使用方法,但您确实需要深入研究,而且由于在不同的非逻辑位置提到了它,因此并不完全清楚。

事实证明,在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:increment是一个自定义函数,可以简单地复制文件并对其进行递增(如果存在)以避免覆盖,但实际上可以是任何东西。

此处的关键方法是[NSURL startAccessingSecurityScopedResource]和[NSURL stopAccessingSecurityScopedResource],必须注意,它们必须成对调用(开始/停止),因为调用stop失败会导致问题,因此复制方法非常有效,特别是当这些文件将要进行内存映射时。 (我的情况是因为它们很大)

答案 1 :(得分:0)

Exaberri Tokugawa的答案帮助我找到了此解决方案,而无需复制文件:

CREATE OR REPLACE FUNCTION "public"."find_centroid"("argbase_x" int8, "argbase_y" int8, "arg_length" int)
  RETURNS TABLE("cent_x" float8, "cent_y" float8) AS $BODY$
    DECLARE
    edge_x int8;
    edge_y int8;
    bounds text;
BEGIN
    edge_x := "argbase_x" + 5;
    edge_y := "argbase_y" + 5; 
    bounds := CONCAT('((',"argbase_x"::text,',',"argbase_y"::text,'), 
    RETURN QUERY
    SELECT sum(location[0])/count("location") as cent_x, sum(location[1])/count("location") as cent_y 
from points
WHERE "location" <@ box(bounds);

END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100