2011-12-12 17 views
7

Jak wysłać plik do innej aplikacji, wiedząc, która aplikacja UTI obsługuje? Powiedzmy, że plik nie ma rozszerzenia pliku, ale wiem, że wiem, UTI pliku.UIDocumentInteractionController, bez rozszerzenia pliku, ale UTI

Próbowałem następujące:

// 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] 

To pokazuje obsługiwanej aplikacji, jednak gdybym go zaznaczyć, że nie będzie przełączyć aplikację. zwraca pełnomocnikowi

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

ale

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

nigdy nie jest wywoływana i aplikacji nie jest przełączanie.

Cel App eksportuje swoje ZUM w następujących przypadkach:

<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> 

Jak to nie działa, próbowałem również dodanie rozszerzenia niestandardowe. Wciąż jednak nie działałoby w ten sposób. Po dodaniu niestandardowego rozszerzenia do pliku przekazuję do DocumentInteractionController i działa. Jednak lista aplikacji pokazuje wszystkie inne aplikacje obsługujące to samo rozszerzenie pliku bez względu na to, czy jest ono dostępne w UTI typu I.

Say Oświadczam 2 ZUM w 2 różnych zastosowań:

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

Kiedy wręczając plik do DocumentInteractionController i ustawienie ZUM do com.mycomp.a będzie również pokazać APP2 jako ewentualnego stosowania jest w stanie obsłużyć plik .

zdefiniowałem ZUM z rozszerzeniem w następujący sposób:

<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> 

będę naprawdę wdzięczny za pomoc, jestem trochę zakleszczony. Zatem znowu pytanie: Jak wysłać plik do aplikacji ze znanym UTI bez rozszerzenia lub o takim samym rozszerzeniu jak inne pliki, których nie chcę pokazywać aplikacji jako wyboru w DocumentInteractionController?

Dzięki

Odpowiedz

2

Znalazłem rozwiązanie tego problemu. Jednak myślę, że nie jest to bardzo dobry.

Podczas testów dowiedziałem się, że po pozostawieniu rozszerzenia pliku z dala, UIDocumentInteractionController pokaże aplikacje w zależności od podanego UTI. Wysyłając plik do docelowej aplikacji nic się nie stanie. Doszedłem do wniosku, że do ostatecznego wysłania potrzebuję rozszerzenia pliku.

Moje podejście polegało na modyfikacji właściwości URL, zanim plik zostanie wysłany do aplikacji docelowej i dostarczeniu jej tego samego pliku, ale z rozszerzeniem pliku akceptowanym przez aplikację docelową. Mimo to moja aplikacja właśnie się zawiesiła. Profilowałem go za pomocą Instruments i odkryłem, że problem spowodowany jest tym, że niektóre obiekty proxy są zwalniane. Widziałem również, że ostateczne przesadzenie było w metodzie o nazwie _invalidate o nazwie UIDocumentInteractionController(Private), która zwróciła obiekt.

Ponieważ kategorii nie można przesłonić przez inne kategorie, postanowiłem przetasować metodę kategorii za pomocą własnego sprawdzenia implementacji, jeśli URL zawierał rozszerzenie pliku i przekierować połączenie do oryginalnej metody _invalidate lub po prostu nie robić nic.

poniższych kodów pokazuje, co zrobiłem:

#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 

Ten kod wymiany oryginału _invalidate metoda z _invalidateMY, w wyniku czego każde wezwanie do _invalidate nazywając _invalidateMY i vice versa.

Poniższy kod pokazuje, w jaki sposób obsłużyć 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]; 

I ten kod przedstawia metodę delegować UIDocumentInteractionController „s, która zamienia 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]); 
} 

to rozwiązanie działa, ale w moim opinia jest brudnym hackiem, musi być lepsze rozwiązanie.

+0

Znalazłem prostsze rozwiązanie. Kod z 'willBeginSendingToApplication:' może być już wykonany po pomyślnym wywołaniu otwartego menu, co wymazuje potrzebę zamiany metod! – Jan

+2

Proszę podać kod dla tego. Próbowałem ustawić właściwość name, ale nie odzwierciedla to w aplikacji innej firmy. – slott

+0

Tak, najbardziej pomocne byłoby szczegółowe zapisanie * rzeczywistego * rozwiązania. – buildsucceeded

Powiązane problemy