devhkh


앱 - 앱 간 자료 전송에는 두가지 방법이 있다.

첫번째는 Keychain 을 이용하여 전송하는 방법이 있고,

두번째는 UIDocumentInterationController를 이용하여 다른 앱에 전송할 수 있다.


* Keychain을 이용하는 방법

1. 프로젝트 생성

- 두개의 프로젝트를 생성 하는데, 편의를 위해 GenericKeychain 1,2 로 각각 생성한다. 

- 일단 아래는 GenericKeychain1 을 설정하는 방법을 설명한다. 


2. Property List 추가

- ⌘+N -> Resource -> Property List 선택 -> Next -> KeychainAccessGroups 로 지정 -> Create 

- KeychainAccessGroups를 선택 후 아래와 같이 추가 ( Item 0, Item 1은 공유할 데이터의 Identifier로 생각하면 편하다. )

* APP_ID는 아래에 설명 (일단 아래와 같이 추가)


- Targets 에 Code Signing Entitlements 에 추가한 KeychainAccessGroups.plist 를 아래와 같이 설정한다.



3. 프로비저닝 프로파일 설정

- 프로비저닝 포털 접속 (https://developer.apple.com/ios/manage/provisioningprofiles/index.action)

- 일단은 테스트를 위해 iOS Team Provisioning Profile 을 다운로드 한다. (이미 있다면 다운로드 하지 않아도 된다.)

- 다운받은 iOS Team Provisioning Profile 을 Organizer에 추가한다.

- GenericKeyChain1에 Project와 Targets에 모두 iOS Team Provisioning Profile 로 설정한다. ( ex) APP_ID.* )

- 아래 스크린샷 참고하여 APP_ID 를 적는다. 아래에 보면 X79T7HS6HZ 가 APP_ID 이다. 

* 2번에서 설정한 Property List에 APP_ID 대신 X79T7HS6HZ 로 바꾼다.



4. KeychainItemWrapper 추가

- http://developer.apple.com/library/ios/#samplecode/GenericKeychain/Introduction/Intro.html 에서 샘플코드를 받은 후

 KeychainItemWrapper.h, KeychainItemWrapper.m 파일을 GenericKeychain1 프로젝트에 추가한다.


5. 자료 전송

KeyChainAccessGroup에 저장 하는 방법

#import "KeychainItemWrapper.h"


KeychainItemWrapper *nameItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"Name" accessGroup:@"APP_ID.com.yesungcni.Name"];

[nameItem setObject:nameItem forKey:(id)kSecValueData];


- KeyChainAccessGroup에서 가져오는 방법

#import "KeychainItemWrapper.h"


KeychainItemWrapper *nameItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"Name" accessGroup:@"APP_ID.com.yesungcni.Name"];

[nameItem objectForKey:(id)kSecValueData];


위에까지 한 작업을 또 GenericKeyChain2에도 적용을 한다.

GenericKeychain1에서는 5번을 참고하여 저장을 하고 GenericKeychain2에서는 가져오게 되면 자료를 가져올 수 있다.


간단한 스트링은 전송은 되지만 이미지는 전송 할 수가 없다.




* UIDocumentInteractionController를 이용하는 방법

Keychain을 이용할때는 프로젝트 두개를 동일하게 해야 하지만 UIDocumentInteracitonController를 이용하여 자료를 공유할때는

각각 구현을 해줘야 한다. 일단 Sender부터 구현을 한다.


1. Sender 프로젝트 생성

- ShareImageSender 로 프로젝트 생성한다.

- 프로젝트에 간단하게 생성한 이미지 두개를 넣는다.

* 테스트할 이미지


2. Sender 버튼 구현

 UIButton *shareButton1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];

    [shareButton1 setFrame:CGRectMake(10, 40, 300, 70)];

    [shareButton1 setImage:[UIImage imageNamed:@"1.png"] forState:UIControlStateNormal];

    [shareButton1 setTag:1];

    [shareButton1 addTarget:self action:@selector(shareAction:) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:shareButton1];

    

    UIButton *shareButton2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];

    [shareButton2 setFrame:CGRectMake(10, 120, 300, 70)];

    [shareButton2 setImage:[UIImage imageNamed:@"2.png"] forState:UIControlStateNormal];    

    [shareButton2 setTag:2];

    [shareButton2 addTarget:self action:@selector(shareAction:) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:shareButton2];


3. Sender 버튼 기능 구현

-(void)shareAction:(id)sender {


    if([sender tag]==1){

        NSURL* imageURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"1" ofType:@"png"]];

        NSLog(@"url: %@", [imageURL absoluteURL]);

        

        UIDocumentInteractionController *docInteractionContrlr = 

 [UIDocumentInteractionController interactionControllerWithURL:imageURL];

        docInteractionContrlr.delegate = self;

        [docInteractionContrlr presentPreviewAnimated:YES];

    } 

    

    else if([sender tag]==2){

        

        NSURL* imageURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"2" ofType:@"png"]];

        NSLog(@"url: %@", [imageURL absoluteURL]);

        

        UIDocumentInteractionController *docInteractionContrlr = 

 [UIDocumentInteractionController interactionControllerWithURL:imageURL];

        docInteractionContrlr.delegate = self;

        [docInteractionContrlr presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];

        [docInteractionContrlr retain];

    }

}


- (UIViewController *)documentInteractionControllerViewControllerForPreview:

(UIDocumentInteractionController *)controller {

    return self;

}


1번 버튼을 눌렀을때는 Receiver에 전송할 프리뷰를 보여주고 그 후에 전송할 수 있다. 그래서 프리뷰를 보여줄 뷰컨트롤러를 정할 수 있다.

그 메소드가 

- (UIViewController *)documentInteractionControllerViewControllerForPreview:

(UIDocumentInteractionController *)controller {

    return self;

}

이 메소드 이다. 현재 뷰컨트롤러에 보여줘야 하니 self 를 리턴한다.


아래는 1번 버튼을 눌렀을때 화면 이다.

    

                                                                 프리뷰 화면                                                                              오른쪽 공유버튼을 눌렀을때 액션



2번 버튼을 눌렀을 때는 아래와 같다.

2번 버튼을 누르면 아래와 같이 Receiver 가 구현되어 있는 앱은 같이 뜬다. Receiver 는 아래에 자세히 설명 하겠다.

4. Receiver 프로젝트 생성

- ShareImageReceiver 로 생성

- ShareImageReceiver-Info.plist 에 다음과 같이 추가한다.

( PNG 파일과 JPG 파일을 받을수 있게 설정. 만약에 다른 확장자를 더 추가 해야한다면 현재의 format 으로 추가 할 것.  )


5. AppDelegate에 RootViewController 설정 및 openURL 메소드 설정

⌘+N -> RootViewController 추가

- 생성된 RootViewController.h에 아래와 같이 UIImageView 선언

#import <UIKit/UIKit.h>


@interface RootViewController : UIViewController {

    

    UIImageView *_imageView;

}


- (void)setShareImage:(UIImage *)image;


@end


- RootViewController.m에 아래와 같이 설정

- (void)loadView

{

    [super loadView];

    

    self.title = @"ShareImageReceiver";

    _imageView = [[UIImageView alloc]initWithFrame:CGRectMake(10, 40, 300, 70)];

    [self.view addSubview:_imageView];

}


- (void)setShareImage:(UIImage *)image {

    

    [_imageView setImage:image];

}


- AppDelegate.h에 RootViewController를 클래스변수로 선언

#import "RootViewController.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate> {

    RootViewController *_rootViewContrlr;

    

}


- AppDelegate.m에 처음보여질 뷰 컨트롤러를 생성한 RootViewController로 설정

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    // Override point for customization after application launch.

    self.window.backgroundColor = [UIColor whiteColor];

    

    _rootViewContrlr = [[RootViewController alloc]init];

    UINavigationController *navigationContrlr = 

[[UINavigationController alloc]initWithRootViewController:_rootViewContrlr];

    

    [self.window setRootViewController:navigationContrlr];

    

    [navigationContrlr release];

    [_rootViewContrlr release];


    [self.window makeKeyAndVisible];

    return YES;

}



- AppDelegate.m에 openURL 설정

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url 

sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {

    

    NSLog(@"url: %@", [url absoluteURL]);

    

    NSData* imageData = [NSData dataWithContentsOfURL:url];

    UIImage* image = [UIImage imageWithData:imageData];

    

    [_rootViewContrlr setShareImage:image];

    

    return YES;

}


ShareImageSender 앱에서 전송을 하게 되면 이 메소드로 오게 된다.

Sender에서 이미지를 전송할때 이미지 객체 자체를 전송하는게 아니라 Sender앱에서 이미지를 가지고 있는 경로를 Receiver앱에 알려주게 된다.

Receiver는 그 경로를 받아서 NSData로 받은 후 UIImage로 변환 하게 된다.

그 후 생성한 RootViewController에 이미지를 지정하면 RootViewController의 UIImageView에 보여주게 된다.


실험.

Sender앱에서 UIDocumentInteracitonController를 이용하지 않고 openURL로 전송하고 Receiver앱에 URL Schema를 이용하여 같은 방식으로 Image의 경로를 받게 해 보았다.

결과는 실패했지만 UIDocumentInteractionController가 어떤방식으로 이미지를 받는지 정확하게 알 수 있었다. 우선 로그를 공개한다.

ShareImageReceiver[1398:707] url: ShareImageReceiver://file://localhost/var/mobile/Applications/2FCBDD6F-417C-47A6-AA52-46439660567C/ShareImageSender.app/2.png

위 로그는 Receiver앱에서 AppDelegate의 openURL 메소드의 url 로그 이다.

위 로그를 잘 살펴보면 알겠지만 샌드박싱된 앱 안에 접근을 할수 없는 이미지 경로를 가져오게 된다. 이 경로로는 NSData로 변환할수 없었다.


ShareImageReceiver[1398:707] url: file://localhost/private/var/mobile/Applications/DFFFF23A-A6B2-4B70-9072-CCC42459E6FB/Documents/Inbox/1-19.png

하지만 UIDocumentInteracitonController를 이용할 경우 위와 같이 Sender앱이 아닌 Receiver앱의 Documents 폴더에 복사시켜주어 Receiver앱에서 사용가능한 경로를 주게 된다. 

이 테스트로 인한 결론은 UIDocumentInteracitonController는 샌드박싱된 앱과 앱 사이에서 Documents 폴더에 복사하여 이미지를 공유하는 것을 도와준다는 것을 알 수 있다.