티스토리 뷰

학교/졸업작품

C2DM Push 사용하기

사탕맛커피 2011. 8. 19. 21:08

C2DM Push를 사용하면 서비스를 항상 돌리지 않아도 서버의 메시지를 받을 수 있다.(물론 결국 휴대폰에서 C2DM서비스가 실행중이여야 하지만, 특별한 경우가 아니면 지금도 돌고 있다.)

준비물 : 구글 계정, 3rd party 서버

메시지 전달 과정은 다음과 같다.

1. 단말기에서 3rd party 서버로 메시지 전송을 요청 
2. 3rd party 서버에서 C2DM서버로 Push 전송 요청
3. C2DM 서버에서 단말기로 Push 메시지 전송
4. 받은 Push메시지를 단말기에서 처리

3번은 구글 서버에서 알아서 해주므로 1, 2, 4번을 직접 처리해야 한다. 1번은 직접 구현하면 되고, 2번과 4번은 정해진 프로세스에 따라서 구현하면 된다.

간단하게 C2DM메시지를 서버는 메시지 전송만, 어플은 메시지 수신만 하게 된다.

먼저 어플리케이션을 살펴보면 C2DM 서비스를 사용할 것이란 선언을 해야 한다.

 

AndroidManifest.xml 에서

1 <!-- C2DM Receiver --> 2 <receiver android:name=".C2DM_BroadcastReceiver" 3 android:permission="com.google.android.c2dm.permission.SEND"> 4 <intent-filter> 5 <action android:name="com.google.android.c2dm.intent.RECEIVE"/> 6 <category android:name="(패키지명)"/> 7 </intent-filter> 8 <intent-filter> 9 <action android:name="com.google.android.c2dm.intent.REGISTRATION"/> 10 <category android:name="(패키지명)"/> 11 </intent-filter> 12 </receiver>

다음으로 어플 시작시 C2DM서버에 등록하는 과정이 필요하다.

1 Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER"); 2 // 어플리케이션 ID 3 registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0)); 4 registrationIntent.putExtra("sender", "개발자 E-mail 주소"); 5 //서비스 시작 6 startService(registrationIntent);

새로운 클래스를 하나 생성하고 BroadcastReceiver를 상속한다.

1 public class C2DM_BroadcastReceiver extends BroadcastReceiver { 2 static String registration_id = null; 3 4 @Override 5 public void onReceive(Context context, Intent intent) { 6 7 String intentName = intent.getAction(); 8 if (intentName.equals("com.google.android.c2dm.intent.REGISTRATION")) { 9 // C2DM 등록 후 결과를 받아온다. 10 handleRegistration(context, intent); 11 } else if (intentName.equals("com.google.android.c2dm.intent.RECEIVE")) { 12 // 메시지 도착 13 // 상황에 맞게 처리 14 } 15 16 private void handleRegistration(Context context, Intent intent) { 17 registration_id = intent.getStringExtra("registration_id"); 18 }

C2DM서버에 등록 요청을 하면 onReceive 메소드가 호출되는데, registration_id가 기기의 등록 id이다. 키값은 휴대폰이 꺼지거나 어플이 삭제되는 경우 재발급된다고 한다. 따라서 따로 저장해 둘 필요는 없을 것 같다.

이제 서버쪽을 살펴보면,

1 public void C2DM_SendMessage(final String receiverRegId, final String authToken, final String message) throws Exception{ 2 3 final String c2dmUrl = "https://android.apis.google.com/c2dm/send"; 4 5 // parameter 설정 6 StringBuffer params = new StringBuffer(); 7 params.append("registration_id=" + receiverRegId); 8 params.append("&collapse_key=1"); 9 params.append("&delay_while_idle=1"); 10 params.append("&data.msg=" + URLEncoder.encode(message, "UTF-8")); 11 byte[] postData = params.toString().getBytes("UTF8"); 12 13 URL url = new URL(c2dmUrl); 14 15 // 추가한 부분 16 HttpsURLConnection.setDefaultHostnameVerifier(new FakeHostnameVerifier()); 17 HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 18 conn.setDoOutput(true); 19 conn.setUseCaches(false); 20 conn.setRequestMethod("POST"); 21 conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 22 conn.setRequestProperty("Content-Length", Integer.toString(postData.length)); 23 conn.setRequestProperty("Authorization", "GoogleLogin auth=" + authToken); 24 25 OutputStream out = conn.getOutputStream(); 26 out.write(postData); 27 out.close(); 28 conn.getInputStream(); // 실행하지 않으면 메시지가 가지 않는다. 29 }

마지막 부분은 의미 없는 행 인것 같아서 삭제했더니 메시지가 전달되지 않는다. 또 중간에 추가한 부분이 없으면 SSL관련 오류가 발생한다. 예전에는 문제가 없었는데 최근에 문제가 생기는 것을 보면 서버보안정책이 바뀐 듯 하다. 아래 클래스를 추가해 주면 된다.

1 private static class FakeHostnameVerifier implements HostnameVerifier { 2 @Override 3 public boolean verify(String hostname, SSLSession session) { 4 return true; 5 } 6 }

인증키 값은 다음 함수로 얻어온다.

 

1 public String getAuthToken() throws Exception{ 2 final String email = "개발자 구글 계정"; 3 final String password = "개발자 계정 비밀번호"; 4 final String authTokenUrl = "https://www.google.com/accounts/ClientLogin"; 5 String authToken = ""; 6 StringBuffer parameter = new StringBuffer(); 7 parameter.append("accountType=HOSTED_OR_GOOGLE"); 8 parameter.append("&Email=" + email); 9 parameter.append("&Passwd=" + password); 10 parameter.append("&service=ac2dm"); 11 parameter.append("&source=pe-mytrace-1"); 12 13 byte[] postData = parameter.toString().getBytes("UTF8"); 14 15 URL url = new URL(authTokenUrl); 16 17 HttpsURLConnection.setDefaultHostnameVerifier(new FakeHostnameVerifier()); 18 HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 19 conn.setDoOutput(true); 20 conn.setUseCaches(false); 21 conn.setRequestMethod("POST"); 22 conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 23 conn.setRequestProperty("Content-Length", Integer.toString(postData.length)); 24 25 OutputStream out = conn.getOutputStream(); 26 out.write(postData); 27 out.close(); 28 29 BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); 30 String sidLine = br.readLine(); 31 String lsidLine = br.readLine(); 32 String authLine = br.readLine(); 33 34 System.out.println("sidLine----------->>>"+sidLine); 35 System.out.println("lsidLine----------->>>"+lsidLine); 36 System.out.println("authLine----------->>>"+authLine); 37 System.out.println("AuthKey----------->>>"+authLine.substring(5, authLine.length())); 38 39 authToken = authLine.substring(5, authLine.length()); 40 return authToken; 41 }

11번째 줄의 source에는 어플리케이션에 대한 정보를 넣는다. 아마 구글에서 로그찍을때 사용하는 것 같다. 인증 키 값은 Auth=로 시작하는 줄에 담겨 있다. 이것을 넘겨주면 된다. 인증키는 매번 전송할 때 마다 보낼 필요는 없을 것 같다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함