프로그래밍/모바일2012. 12. 3. 13:08

본 포스팅은 java 서버 기반으로 apns, gcm을 활용해 모바일 기기로 PUSH 메세지를 전송하는 방법에 대해 설명합니다.

모바일 기기 단에서 처리 코드는 포함하지 않습니다 :)


1. APNS 사용하기

애플의 아이폰 등의 기기에 PUSH 메세지를 전송하기 위해서는 다음과 같은 준비물이 필요합니다.


* javaPNS 라이브러리 : http://code.google.com/p/javapns/

* javaPNS에서 사용하는 Bouncy Castle 라이브러리 : http://www.bouncycastle.org/

* PUSH 인증서/인증서 비밀번호

* 디바이스 UDID

* 모바일앱


javaPNS는 Apple Push Notification Service(APNS)를 사용하기 쉽게 만들어진 오픈소스 라이브러리로 GNU Lesser GPL 라이선스를 따릅니다. 


본 포스팅에서 사용되는 javaPNS 버전은 2.2 입니다. 

JVM 버전은 1.5 이상을 쓰면 되지만 현재 1.7 버전에서는 SSL connection오류가 발생할 수 있음에 주의합니다. 

또한 javaPNS는 BouncyCastle에서 제공하는 암복호화 라이브러리에 의존성이 있습니다. BouncyCastle를 온전히 사용하기 위해서는 JCE Policy 파일 패치가 필요할 수 있습니다.


이상 위 준비과정을 마쳤다면, APNS는 아주 쉽게 사용할 수 있습니다.

기본 코드는 아래와 같습니다.

public boolean send(String certificate, String password, boolean production, String udid, String message, Map<String, String> extra) {
	try {
		PushNotificationPayload payload = PushNotificationPayload.complex();
		payload.addAlert(message);
		payload.addBadge(-1);
		payload.addSound("default");
			
		if( extra != null ) {
			Iterator<String> keys = extra.keySet().iterator();
			while( keys.hasNext() ) {
				String key = keys.next();
				String value = extra.get(key);
				
				payload.addCustomDictionary(key, value);
			}
		}

		PushedNotifications notifications = Push.payload(payload, 
				certificate, password, production, udid);
			
		return (notifications != null && notifications.size() > 0 && notifications.get(0).isSuccessful());
			
	} catch (Exception e) {
		logger.error(e, e);
	} 
		
	return false;
}

certificate는 인증서 경로, password는 인증서 비밀번호, udid는 디바이스 고유키 입니다.

extra는 전송 메세지 외에 커스텀 딕셔너리에 넣을 데이터를 처리합니다.


APNS 전송이 수 만건 단위로 많아질 경우 위 코드를 그대로 사용하는 것은 매우 비효율적입니다.  


APNS의 경우 한번 커넥션이 맺어질 경우 해당 커넥션을 통해 다수의 PUSH 데이터를 한번에 전송하는 방식을 사용해야 합니다. 필요에 따라 멀티쓰레드 방식을 통해 PUSH 데이터를 나누어 전송할 수도 있습니다. 


Message Broadcasting, payloadPerDevice, multithread, connection pool과 같은 고급 주제들 또한 javaPNS 문서와 소스에서 힌트를 얻을 수 있으니 반드시 참고하기를 권장합니다.



2. Google Cloud Messaging for Android(GCM) 사용하기

GCM을 사용하기 위해서는 다음과 같은 준비물이 필요합니다.


* Google API Console을 통해 프로젝트 생성

* GCM 활성화

* API Key 및 프로젝트 ID 얻기

* 디바이스 토큰

* 모바일 앱

* gmc-server 라이브러리

* json-simple 라이브러리


먼저 https://code.google.com/apis/console/ 에 처음 방문하면 다음 그림과 같이 프로젝트를 개설하기 위한 과정이 나타납니다.


프로젝트를 생성한후 좌측 메뉴의 Services에서 "Google Cloud Messaging for Android"를 활성화 해줍니다.



그 다음 좌측 메뉴의 API Access에서 아래 그림과 같이 Create New Server Key를 생성합니다.



서버 키를 생성하면서 접근 가능한 서버의 IP를 입력하는 과정이 있습니다. 

정상적으로 서버 키가 생성됬다면 아래와 같이 API키와 허용 IP목록을 확인할 수 있씁니다.



프로젝트 ID는 다음 그림과 같이 URL의 project: 다음의 일련번호를 통해 확인할 수 있습니다.



gcm-server 라이브러리는 안드로이드 SDK의 extras > google > gcm > gcm-server > dist 에서 찾을 수 있씁니다.

만약 gcm이 없다면 안드로이드 SDK 매니저를 통해 설치해야합니다.


gcm-server는 json-simple 라이브러리에 의존성이 있습니다. 

json-simple은 http://code.google.com/p/json-simple/ 에서 다운로드 받을 수 있습니다.


기본 코드는 다음과 같습니다.

public boolean send(String apiKey, String token, String message, Map<String, String> extra) {
	Sender sender = new Sender(apiKey);
		
	try { message = URLEncoder.encode(message, "UTF-8"); } 
	catch (UnsupportedEncodingException ignore) {}
		
	Message.Builder messageBuilder = new Message.Builder();	
	messageBuilder.delayWhileIdle(false);
	messageBuilder.timeToLive(1800); // 30min
	messageBuilder.addData("msg", message);
		
	if( extra != null ) {
		Iterator<String> keys = extra.keySet().iterator();
		while( keys.hasNext() ) {
			String key = keys.next();
			String value = extra.get(key);
				
			messageBuilder.addData(key, value);
		}
	}
		
	try {
		Result result = sender.send(messageBuilder.build(), token, 5);
		String messageId = result.getMessageId();
			
		return (messageId!=null);
	} catch(Exception e) {
		logger.error(e, e);
	}			
		
	return false;
}

APNS와 마찬가지로 많은 양의 PUSH 메세지를 위 코드를 통해 처리하는 것은 매우 비효율 적입니다.


C2DM에서 GCM으로 넘어오며 얻을 수 있는 큰 장점중의 하나는 Message Broadcasting이 가능해졌다는 것입니다.

아직 경험적/통계적으로 GCM 에서의 적절한 connection과 multithread 갯수는 파악하지 못했지만, Message Broadcasting 기술과 delayWhileIdle, timeToLive의 설정값을 통해 PUSH 메세지 도달율을 C2DM보다 높힐 수 있을것이라 기대합니다. 


Posted by devop

댓글을 달아 주세요