2011-12-12 102 views
7

如何將文件發送到不同的應用程序,以瞭解應用程序支持哪個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中顯示應用程序。

謝謝

回答

2

我找到了解決這個問題的辦法。不過,我認爲這不太好。

在測試過程中,我發現當離開文件擴展名時,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

相關問題