UIDocumentInteractionController,但没有文件扩展名但UTI

问题描述:

如何将文件发送到不同的应用程序,以了解应用程序支持哪个UTI?可以说文件没有文件扩展名,但我碰巧知道文件的UTI。UIDocumentInteractionController,但没有文件扩展名但UTI

我试过如下:

// target is a NSURL with the location of the extension less file on the system 
// knownUTI is a NSString containing the UTI of the file 
    UIDocumentInteractionController* dic = [UIDocumentInteractionController interactionControllerWithURL:target]; 
    [dic retain]; 

    dic.delegate = self; 
    dic.UTI = knownUTI; 
    [dic presentOpenInMenuFromRect:CGRectZero inView:superController.view animated:YES] 

它显示了支持的应用程序,但是,如果我选择它,它不会切换应用程序。委托调用

- (void)documentInteractionController:(UIDocumentInteractionController *)controller willBeginSendingToApplication:(NSString *)application 

- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application 

,不会被调用的应用程序就不会切换。

目标应用出口其UTI在以下几点:

<key>CFBundleDocumentTypes</key> 
    <array> 
     <dict> 
      <key>CFBundleTypeIconFiles</key> 
      <array/> 
      <key>CFBundleTypeName</key> 
      <string>Migration DocType</string> 
      <key>CFBundleTypeRol</key> 
      <string>Shell</string> 
      <key>LSHandlerRank</key> 
      <string>Owner</string> 
      <key>LSItemContentTypes</key> 
      <array> 
       <string>com.mycomp.customstring</string> 
      </array> 
     </dict> 
    </array> 

... 

<key>UTExportedTypeDeclarations</key> 
    <array> 
     <dict> 
      <key>UTTypeConformsTo</key> 
      <array> 
       <string>public.data</string> 
      </array> 
      <key>UTTypeDescription</key> 
      <string>My custom UTI</string> 
      <key>UTTypeIdentifier</key> 
      <string>com.mycomp.customstring</string> 
     </dict> 
    </array> 

由于这没有工作,我也尝试添加自定义扩展。但是,它不会以这种方式工作。将自定义扩展名添加到文件时,我将其交给DocumentInteractionController,它可以工作。但是,应用程序列表显示了所有其他支持相同文件扩展名的应用程序,无论UTI I型电源如何。

说我宣布在2级不同的应用2个尿路感染:

App1 with UTI1: com.mycomp.a with extension .abc 
App2 with UTI2: com.mycomp.b with extension .abc 

当文件递给了DocumentInteractionController,以及UTI设置为com.mycomp.a它也将显示应用2作为一种可能的应用程序能够处理的文件。

我通过以下方式定义的尿路感染扩展名为:

<key>UTExportedTypeDeclarations</key> 
    <array> 
     <dict> 
      <key>UTTypeConformsTo</key> 
      <array> 
       <string>public.data</string> 
      </array> 
      <key>UTTypeDescription</key> 
      <string>My UTI Type</string> 
      <key>UTTypeIdentifier</key> 
      <string>com.mycomp.a</string> 
      <key>UTTypeTagSpecification</key> 
      <dict> 
       <key>public.filename-extension</key> 
       <string>abc</string> 
       <key>public.mime-type</key> 
       <string>application/abc</string> 
      </dict> 
     </dict> 
    </array> 

我会很感激你的帮忙,我有点卡住。 所以,再次提出这样的问题:如何将文件发送到已知UTI的应用程序,这些应用程序可以不带扩展名,也不具有与其他文件相同的扩展名,而其他文件我不想在DocumentInteractionController中显示应用程序。

谢谢

我找到了解决这个问题的办法。不过,我认为这不太好。

在测试过程中,我发现当离开文件扩展名时,UIDocumentInteractionController将根据我指定的UTI显示应用程序。将文件发送到目标应用程序时,不会发生任何事情。我的结论是我需要一个文件扩展名来完成最终的发送。

我的方法是在将文件发送到目标应用程序之前修改URL属性,并为其提供相同的文件,但具有目标应用程序接受的文件扩展名。尽管如此,我的应用程序刚刚崩溃。我用仪器对其进行了分析,发现问题是由于UIDocumentInteractionController过度部分代理对象。 我还看到最后的过度使用方法叫_invalidateUIDocumentInteractionController(Private)类别被称为哪个发布了这个对象。

由于类别不能被其他类别覆盖,我决定用我自己的实现检查类别方法,检查URL是否包含文件扩展名,并将调用重定向到原始方法或者什么都不做。

下面的代码显示了我所做的:

#include <objc/runtime.h> 

@interface UIDocumentInteractionController(InvalidationRedirect) 

-(void)_invalidateMY; 
+(void)load; 
void Swizzle(Class c, SEL orig, SEL newSEL); 
@end 

@implementation UIDocumentInteractionController(InvalidationRedirect) 

void Swizzle(Class c, SEL orig, SEL newSEL) 
{ 
    Method origMethod = class_getInstanceMethod(c, orig); 
    Method newMethod = class_getInstanceMethod(c, newSEL); 
    if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) 
     class_replaceMethod(c, newSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); 
    else 
     method_exchangeImplementations(origMethod, newMethod); 
} 

-(void)_invalidateMY{ 
    @synchronized(self) { 
     if(![[[[self.URL lastPathComponent] componentsSeparatedByString:@"."] lastObject] isEqualToString:@"extension"]) { 
      [self _invalidateMY]; 
     } 
    } 
} 

+(void)load 
{ 
    Swizzle([UIDocumentInteractionController class], @selector(_invalidate), @selector(_invalidateMY)); 
} 

@end 

此代码交流原有_invalidate_invalidateMY,导致每次调用_invalidate调用_invalidateMY,反之亦然。

下面的代码显示了如何处理UIDocumentInteractionController

// create a file without extension 
    NSString *fileName = @"myFile"; 

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 

    NSString *documentsDirectory = [paths objectAtIndex:0]; 

    NSURL* target = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", documentsDirectory, fileName]]; 

    if([[@"THIS IS JUST A TEST STRING" dataUsingEncoding:NSUTF8StringEncoding] writeToURL:target atomically:NO]) { 
     NSLog(@"file written successfully"); 
    }else { 
     NSLog(@"Error.. file writing failed"); 
    } 

    UIDocumentInteractionController* dic = [UIDocumentInteractionController interactionControllerWithURL:target]; 
    [dic retain]; 
    dic.delegate = self; 


    // set the UTI to the known UTI we want to list applications for 
    dic.UTI = @"com.mycomp.a"; 

    [dic presentOpenInMenuFromRect:CGRectZero inView:superController.view animated:YES]; 

而这个代码显示了UIDocumentInteractionController的哪些交易所的URL的委托方法:

- (void)documentInteractionController:(UIDocumentInteractionController *)controller willBeginSendingToApplication:(NSString *)application 
{ 
    NSFileManager *fileMgr = [NSFileManager defaultManager]; 
    NSError *error; 
    NSURL* newTarget = [NSURL URLWithString:[NSString stringWithFormat:@"%@.extension", controller.URL]]; 
    // rename file to file with extension 
    if (![fileMgr moveItemAtURL:controller.URL toURL:newTarget error:&error] && error) { 
     NSLog(@"Error moving file: %@", [error localizedDescription]); 
    } 
    @synchronized(controller) { 
     //exchange URL with URL+extension 
     controller.URL = newTarget; //<- this results in calling _invalidate 
    } 
    NSLog(@"%@", [NSString stringWithContentsOfURL:controller.URL encoding:NSUTF8StringEncoding error:nil]); 
} 

此解决方案,但在我舆论认为这是一个肮脏的黑客,必须有更好的解决方案。

+0

我找到了一个更简单的解决方案。 “willBeginSendingToApplication:”中的代码在成功调用open菜单后可以执行,这就消除了调用方法的必要性! – Jan

+2

请为此提供代码。我尝试设置名称属性,但它不反映在第三方应用程序。 – slott

+0

是的,详细的*真实*解决方案将是最有帮助的。 – buildsucceeded