2011-12-12 6 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에 관계없이 동일한 파일 확장명을 지원하는 다른 모든 응용 프로그램이 표시됩니다.

DocumentInteractionController에 파일을 전달하고, com.mycomp.a에 UTI를 설정
App1 with UTI1: com.mycomp.a with extension .abc 
App2 with UTI2: com.mycomp.b with extension .abc 

그것은 또한 파일을 처리 할 수있는 가능한 응용 프로그램으로 앱 2를 표시합니다 :

내가 2 개 개의 다른 애플리케이션에서이 개 요로 감염을 선언 말 .

나는 다음과 같은 방식으로 확장명을 가진 UTI를 정의 :

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

나는 당신의 도움을 주셔서 감사합니다 정말 것이다, 내가 가지 붙어있어. 그럼 다시 질문입니다. 확장자가 없거나 DocumentInteractionController에서 응용 프로그램을 선택으로 표시하지 않으려는 다른 파일과 동일한 확장자를 가진 알려진 UTI가있는 응용 프로그램으로 파일을 보내려면 어떻게해야합니까?

감사합니다.

답변

2

이 문제에 대한 해결책을 찾았습니다. 그러나, 나는 그것이 아주 좋지 않다고 생각한다.

테스트하는 동안 파일 확장자를 없애면 UIDocumentInteractionController은 내가 지정한 UTI에 따라 응용 프로그램을 표시한다는 것을 알았습니다. 파일을 대상 응용 프로그램에 보낼 때 아무 일도 일어나지 않습니다. 나는 최종 전송을하기 위해 파일 확장이 필요하다고 결론을 내렸다.

내 접근 방식은 파일을 대상 응용 프로그램에 보내기 전에 URL 속성을 수정하여 동일한 파일을 제공하지만 대상 응용 프로그램에서 허용하는 파일 확장명을 제공하는 것이 었습니다. 그럼에도 불구하고, 내 응용 프로그램이 그냥 추락했습니다. 나는 Instruments와 함께 그 프로파일을 만들었고 그 문제는 어떤 프록시 객체를 과다 처리하는 것으로 인해 UIDocumentInteractionController으로 인한 것으로 나타났습니다. 나는 또한 과부하가 최종적으로 _invalidate이라는 UIDocumentInteractionController(Private)이라는 범주에있는 것을보고 객체를 릴리스했습니다.

범주를 다른 범주로 재정의 할 수 없기 때문에 URL에 파일 확장명이 포함되어 있는지 여부를 확인하고 원래 _invalidate 메서드로 호출을 리디렉션하거나 아무 것도하지 않으면 내 구현 검사로 범주 메서드를 사용하기로 결정했습니다.

#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으로, 그 반대의 경우도 마찬가지 _invalidateMY 및 전화 _invalidate에 모든 호출 결과 :

다음 코드

내가 무슨 짓을했는지 보여줍니다.

다음 코드는 내가 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]; 

그리고이 코드는 URL 교환 UIDocumentInteractionController의 대리자 메서드를 보여줍니다

- (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 in 메뉴가 성공적으로 호출 된 후에 이미 실행될 수 있습니다. 이렇게하면 메소드를 뒤 흔드는 일이 없어집니다! – Jan

+2

코드를 제공해주십시오. 이름 속성 설정을 시도했지만 타사 앱에 반영되지 않았습니다. – slott

+0

예, * 실제 * 솔루션의 자세한 작성이 가장 도움이 될 것입니다. – buildsucceeded