앱 - 앱 간 자료 전송 방법 2가지
앱 - 앱 간 자료 전송에는 두가지 방법이 있다.
첫번째는 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 폴더에 복사하여 이미지를 공유하는 것을 도와준다는 것을 알 수 있다.
'iOS' 카테고리의 다른 글
UITabBarController Custom (0) | 2012.04.16 |
---|---|
AVPlayerLayer 사용, 비디오 썸네일 만들기 (0) | 2012.04.10 |
iOS 전 기종(The new iPad 포함) 아이콘 사이즈 정의 (0) | 2012.03.15 |
APNS 사용 (0) | 2012.03.12 |
장면이동시 애니메이션 주기 (0) | 2012.03.06 |