이 포스팅에서는 애플 푸시 서비스를 사용하는 방법에 대해서 알아보자. 작년 겨울 앱공모전을 준비하면서 "분실물 다나와"
라는 앱을 개발했다. 서울 분실물 센터에 수거되어 있는 분실물 목록을 조회할 수 있고, 등록된 분실물과 유사한 분신물 목록을
사용자 아이폰으로 알리는 앱이었다. 이때 유사 분실물 발견유무를 푸시 기능을 통해 구현하였다. 당시에 푸시와 관련된
자료가 별로 없어서(내가 못찾았겠지만...) 애플 개발자 가이드 문서를 참고하여 구현하였다. 그 때 정리한 내용을 올려본다.
(사진 캡처를 안해서 이해가 잘 안될 수도....-_-;; )
라는 앱을 개발했다. 서울 분실물 센터에 수거되어 있는 분실물 목록을 조회할 수 있고, 등록된 분실물과 유사한 분신물 목록을
사용자 아이폰으로 알리는 앱이었다. 이때 유사 분실물 발견유무를 푸시 기능을 통해 구현하였다. 당시에 푸시와 관련된
자료가 별로 없어서(내가 못찾았겠지만...) 애플 개발자 가이드 문서를 참고하여 구현하였다. 그 때 정리한 내용을 올려본다.
(사진 캡처를 안해서 이해가 잘 안될 수도....-_-;; )
1. Push Service 란?
서버에서 아이폰 애플리케이션으로 데이터를 역으로 전송할 수 있는 서비스이다.
Remote Notification을 등록하고 수신하는 애플리케이션과 푸시 서비스를 제공하는 APNS(Apple Push Notification Service),
APNS에 데이터 푸시요청을 수행할 수 있는 권한을 획득한 Provider(서버) 로 구성된다.
APNS는 애플에서 제공하는 푸시서버가 된다. iPhone에 전송된 푸시메시지는 iOS 를 거쳐 실제 앱에 전달된다.
2. Push 서비스 사용절차
APNS는 실제 아이폰 기기로 푸시를 전송해주는 애플측에서 제공하는 서비스이다. 푸시서비스를 이용하는 서버인 Provider는
푸시할 데이터만을 가공하여 APNS에 푸시를 요청한다. Provider가 APNS에 접속하여 푸시데이터를 전송하려 할 때, APNS는
푸시요청을 할수 있는 권한을 SSL 인증을 통해 검사하게 된다. 그래서 Provider는 사전에 이 인증을 위한 암호화 파일을 사전에
푸시할 데이터만을 가공하여 APNS에 푸시를 요청한다. Provider가 APNS에 접속하여 푸시데이터를 전송하려 할 때, APNS는
푸시요청을 할수 있는 권한을 SSL 인증을 통해 검사하게 된다. 그래서 Provider는 사전에 이 인증을 위한 암호화 파일을 사전에
가지고 있어야 한다.
① 개발자 포탈에서 애플리케이션에 대한 Push Serivce 사용권한 받기
개발자 포탈에서 App Id에 대한 Development 또는 Product 푸시 서비스 옵션을 enable 시키고, 다운받은 인증파일을 KeyCain에
등록시킨다. 이 파일을 p12 파일로 export 하여, 파일, 비밀번호와 함께 Provider 에게 사전에 전달해야 한다.
등록시킨다. 이 파일을 p12 파일로 export 하여, 파일, 비밀번호와 함께 Provider 에게 사전에 전달해야 한다.
② 아이폰 애플리케이션 실행시 APNS에 RemoteNotification 등록
아이폰 애플리케이션이 처음 구동시 APNS에 RemoteNotification 을 등록하고, 애플리케이션 DeviceToken을 수신받는다.
③ Provider에게 DeviceToken 전송
DeviceToken을 수신하면, 서버에 아이폰 UUID와 함께 전달한다. 이 토큰은 APNS에서 아이폰의 애플리케이션을 식별하는 키가
되기 때문에 Provider가 보유하고 있어야 하는 데이터이다. DeviceToken은 거의 변하지 않지만, 애플리케이션이 삭제되고 다시
설치될 때 변할 수도 있기 때문에 애플리케이션이 실행될 때마다, Provider에게 전송하여 갱신여부를 확인하는 것이 좋다. Development용과 Product용의 DeviceToken 값은 다르다는 것에 주의한다.
되기 때문에 Provider가 보유하고 있어야 하는 데이터이다. DeviceToken은 거의 변하지 않지만, 애플리케이션이 삭제되고 다시
설치될 때 변할 수도 있기 때문에 애플리케이션이 실행될 때마다, Provider에게 전송하여 갱신여부를 확인하는 것이 좋다. Development용과 Product용의 DeviceToken 값은 다르다는 것에 주의한다.
④ Provider 에서 푸시 메시지를 생성하여 APNS에 푸시 요청
Provider 에서는 ①단계에서 전달받은 인증파일을 보유하고 있고, 인증파일 비밀번호를 알고 있어야 한다.
DeviceToken와 함께 다음의 주소로 push를 요청할 수 있다. 개발환경과 실제 서비스를 위한 APNS 의 주소가 다르다.
DeviceToken와 함께 다음의 주소로 push를 요청할 수 있다. 개발환경과 실제 서비스를 위한 APNS 의 주소가 다르다.
개발환경 푸시서버 주소: gateway.sandbox.push.apple.com / 2195
제품환경 푸시서버 주소: gateway.push.apple.com / 2195
⑤ APNS 에 전송하는 메시지의 포맷
메시지는 JSON 포맷을 따르며 256바이트 이내야한다. 메시지를 구성하는 키는 다음과 같다.
단순한 메시지 포맷은 위와 같으며, 좀더 세부적으로 메시지를 지정할 수도 있다. 더 자세한 사항은
Local, Remote Notification Programming Guide 를 참고하자.
Local, Remote Notification Programming Guide 를 참고하자.
JSON 형태로 생성된 메시지 형태는 다음과 같다.
{"aps":{"sound":"default","alert":"My alert message","badge":45}}
⑥ APNS에 푸시 요청하기
Provider는 APNS가 요구하는 프로토콜을 따라 데이터를 전송해야 한다. 프로토콜은 APNS에 전송하는 Push 메시지 포맷을
참고하자. 이 메시지 포맷과 APNS 의 요구사항에 맞게 구현한 javapns라는 오픈소스 라이브러리를 사용하여 APNS에 푸시를
요청해보자
참고하자. 이 메시지 포맷과 APNS 의 요구사항에 맞게 구현한 javapns라는 오픈소스 라이브러리를 사용하여 APNS에 푸시를
요청해보자
javapns를 사용하기 위해서 아래의 의존 라이브러리를 가지고 있어야한다.
commons-lang-2.4.jar // String클래스 등의 유틸리티 기능을 제
commons-io-1.4.ja
bcprov-jdk16-145.jar // Bouncy Castle 단체의 암호화 관련 api
log4j-1.2.15.ja
javapns 오픈소스 라이브러리 : http://code.google.com/p/javapns/
Legion of the Bouncy Castle 사이트 : http://www.bouncycastle.org/java.html
다음은 javapns 라이브러리를 사용하여 Provider 에서 APNS 에 푸시를 요청하는 예이다.
String password = "1q2w3e4r"; String certicatePath = "/home/CertificateSR/Interesting_Dev_Cert_pass.p12"; String apnsAddress = "gateway.sandbox.push.apple.com"; String apnsPort = "2195"; try { PayLoad payload = new PayLoad(); payload.addAlert(pushMessage.getAlert()); payload.addBadge(pushMessage.getBadge()); payload.addSound(pushMessage.getSound()); HashMap customMap = (HashMap) pushMessage.getCustomData(); Iterator iterator = customMap.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); payload.addCustomDictionary(key, customMap.get(key)); } PushNotificationManager manager = PushNotificationManager.getInstance(); manager.addDevice("myIphone", pushMessage.getDeviceToken()); Device device = PushNotificationManager.getInstance().getDevice("myIphone"); manager.initializeConnection( apnsAddress, Integer.parseInt(apnsPort), certicatePath, password, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12); manager.sendNotification(device, payload); manager.stopConnection(); manager.removeDevice("myIphone"); } catch (Exception e) { e.printStackTrace(); }
⑦ 애플리케이션측에서 Push를 수신하기 위해서 UIApplicationDelegate 프로토콜의 메소드를 구현
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 배지넘버 초기화 application.applicationIconBadgeNumber = 0; NSDictionary *aps = [launchOptionsobjectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; // 애플리케이션을 처음실행 : RemoteNotification을 등록함 if (aps == nil) { [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge) ]; } else { // 애플리케이션이 원격 통보에 의해 실행됐음 // alert 추출 NSString *alert = [aps objectForKey:@"alert"]; // custom 데이터 추출 NSString *pushSeq = [userInfo objectForKey:@"pushSeq"]; } return YES; } // RemoteNotification 등록 성공. deviceToken을 수신 (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // Provider에게 DeviceToken 전송 //[service registDeviceToken:[deviceToken description]]; } // APNS 에 RemoteNotification 등록 실패 (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { NSLog(@"fail RemoteNotification Registration: %@", [error description]); } // 애플리케이션 실행 중에 RemoteNotification 을 수신 (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { // push 메시지 추출 NSDictionary *aps = [userInfo objectForKey:@"aps"]; // alert 추출 NSString *alert = [aps objectForKey:@"alert"]; // custom 데이터 추출 NSString *pushSeq = [userInfo objectForKey:@"pushSeq"]; }
RemoteNotification이 성공적으로 등록되면, 응답으로 호출되는 didRegistForRemoteNotificationWithDeviceToken 메시지의 파라미터에
DeviceToken 값이 담겨져 온다. 이 Token의 값은 다음과 같은 형태를 갖는다. <12345678 12345678 12345678 12345678 50cfb1 3f5febbe497df>
APNS에 전송하기 하기 위해서는 애플리케이션 또는 Provider 측에서 <, >, 공백문자를 제거해야 한다는 것을 잊지 말자!!
지금까지 애플 푸시서비스에 대해 알아보았다. 사실 푸시 서비스를 이용하는 과정은 그렇게 어렵지 않다. 오히려 개발자 포탈에서
푸시 서비스 권한을 설정하고, 키체인에서 인증파일을 생성하는 과정이 번거롭고... 푸시를 받을 앱이 실행중일 때와 실행중이지
않을 때 푸시 수신 시 동작방식을 달리 처리해줘야 하는 것이 조금 번거로울 뿐이다. 다음 포스팅에서는 실제 푸시메시지 포맷에
대해서 좀더 자세히 알아보자.
푸시 서비스 권한을 설정하고, 키체인에서 인증파일을 생성하는 과정이 번거롭고... 푸시를 받을 앱이 실행중일 때와 실행중이지
않을 때 푸시 수신 시 동작방식을 달리 처리해줘야 하는 것이 조금 번거로울 뿐이다. 다음 포스팅에서는 실제 푸시메시지 포맷에
대해서 좀더 자세히 알아보자.
'프로그래밍 > iOS' 카테고리의 다른 글
[iPhone] 로깅 프레임웍 cocoalumberjack (0) | 2012.02.07 |
---|---|
애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2012.02.07 |
푸시 메시지 포맷 (0) | 2012.02.07 |
NSNotification (0) | 2012.02.07 |
아이폰 Document 폴더의 파일,폴더 리스트 보기 (0) | 2012.02.07 |