본문 바로가기
  • 그냥 하자
Android

Android에서 C2DM 사용하기

by Mash 2011. 10. 19.
반응형

1. C2DM 이란?

- C2DM(Cloud To Device Message)는 안드로이드 2.2 프로요부터 생겨난 API로 개발자들이 서버와 모바일 어플리케이션간에 데이터를 쉽게 싱크할 수 있도록, 서버쪽 에서 안드로이드 폰 상의 어플리케이션으로 데이터를 손쉽게 전달할 수 있도록 도와준다. 쉽게 말하면 서버쪽에서 app이 설치되어있는 폰으로 push방식으로 원하는 메시지를 전달할 수 있게 해준다. 아이폰의 그것과 같다. 현재 C2DM이 나오기 전까지는 클라이언트가 서버쪽을 방문하여 메시지를 요구하는 polling기법을 통하여 실시간 메시징을 했는데, 이 API가 추가되면서 일반 서드파티 개발자도 손쉽게 프로그래밍을 개발할 수 있게 되었다.





2. 준비

- 먼저 push를 사용하기 위해선 구글에 신청을 해야 한다. 예전에는 신청 후 승인 메일이 올 때까지(승인 메일이 와야 사용할 수 있다.) 일주일이 걸렸다고 하는데 요즘엔 5분이면 온다.
링크 : http://code.google.com/intl/ko-KR/android/c2dm/signup.html 
여기서 중요한 부분이 바로 첫번째 부분인 Package name of your Android app 이다. 자신이 만들고 있는 app의 package명을 정확히 적어야 한다. 대충 아무렇게 적거나 잘 못 적을시 사용할 수 없다.

C2DM을 사용하기 위해서는 개발자ID(구글개정), app ID(패키지이름), 등록ID(특정장치를 식별하는 ID), 구글사용자계정, 인증토큰값이 필요하다. 이중 등록ID는 다른 사람의 등록ID를 알 수 있다면 그 사람에게 메시지를 보낼 수 있다. 하지만 이것은 사용자가 등록ID를 신청할 때 마다 바뀐다. 
위의 그림을 잠깐 설명하면 app을 실행하여 개발자 ID와 appID를 C2DM서버에 전송하여 등록ID를 발급 받는다. 이 등록ID는 등록할 때 마다 다르다. 그다음 메시지를 쓰고 전송을 누르면 먼저 C2DM에 인증을 요청해야 한다.  이 때 개발자ID가 필요하다. 인증이 되면 등록ID, 인증토큰값, 보낼 메시지 등을 push에 담아 상대방 핸드폰에 보내게 된다.


3. 핵심 코드 & 설명

- C2DM 등록 ID 발급을 위해서

//C2DM 등록ID 발급
Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
//App ID 
registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0)); 
//개발자 ID 
registrationIntent.putExtra("sender", "xxxxxxxx@gmail.com"); 
//서비스 시작(등록ID발급받기) 
startService(registrationIntent);
// 위에서 지정한 "app"와 "sender"은 맘대로 지정하시는게 아니라 구글에서 필요한 변수명들입니다.

위의 코드로 등록 ID를 받을 수 있다. 그리고 나서

// 메시지를 보낼때 sender(발급받은 ID, 토큰인증값, 메시지)
sender(C2dm_BroadcastReceiver.registration_id, getAuthToken(), "보낼 메시지");

.......

 public void sender(String regId,String authToken,String msg) throws Exception{
     StringBuffer postDataBuilder = new StringBuffer();

     //등록ID
     postDataBuilder.append("registration_id="+regId); 
     postDataBuilder.append("&collapse_key=1"); 
     postDataBuilder.append("&delay_while_idle=1");
     //보낼 메세지 
     postDataBuilder.append("&data.msg="+URLEncoder.encode(msg, "UTF-8")); 
     //메시지 이외에도 다른 변수들도 보낼 수 있다.
     //ex)&data.phone="+URLEncoder.encode(phone, "UTF-8"
     //받을 때는 intent.getExtras().getString("msg"); 이렇게 받는다. 또는 msg대신 phone
     //이렇게....

     byte[] postData = postDataBuilder.toString().getBytes("UTF8");

     URL url = new URL("https://android.apis.google.com/c2dm/send");
        
     HttpURLConnection conn = (HttpURLConnection) url.openConnection();
     conn.setDoOutput(true);
     conn.setUseCaches(false);
     conn.setRequestMethod("POST");
     conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
     conn.setRequestProperty("Content-Length", Integer.toString(postData.length));
     conn.setRequestProperty("Authorization", "GoogleLogin auth=" + authToken);

     OutputStream out = conn.getOutputStream();
     out.write(postData);
     out.close();

     conn.getInputStream();
 
    }
    
 
    public String getAuthToken() throws Exception{
        String authtoken = "";
        
        StringBuffer postDataBuilder = new StringBuffer();
        //똑같이 써준다. 
        postDataBuilder.append("accountType=HOSTED_OR_GOOGLE"); 
        //개발자 구글 ID 
        postDataBuilder.append("&Email=xxxxxx@gmail.com");
        //개발자 구글 비밀번호 
        postDataBuilder.append("&Passwd=xxxxxx");        
        postDataBuilder.append("&service=ac2dm");
        postDataBuilder.append("&source=test-1.0");

        byte[] postData = postDataBuilder.toString().getBytes("UTF8");

        URL url = new URL("https://www.google.com/accounts/ClientLogin");
        
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", Integer.toString(postData.length));

        OutputStream out = conn.getOutputStream();
        out.write(postData);
        out.close();
        
        authtoken = authLine.substring(5, authLine.length());
        
        return authtoken;
}
 


인증ID와 토큰값을 구해서 메시지만 push에 태워서 보낸다.

AndroidManifest.xml에도 등록이 필요하다.

<!-- C2DM을 이용한 메시지 SEND Permission -->
<receiver android:name=".C2dm_BroadcastReceiver"
       android:permission="com.google.android.c2dm.permission.SEND"> 
<!-- C2DM을 이용한 메시지 RECEIVE intent-filter -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="org.mash.c2dm"/>
</intent-filter>
<!-- C2DM을 이용하기 위해서 ID등록 intent-filter -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="org.mash.c2dm"/>
</intent-filter>
</receiver>

..........

<!-- 여기서 protectionLevel 이라는 놈은 normal/dangerous/signature/signatureOrSystem 이렇게 3가지로 구분하는데, normal과 dangerous로 선언된 것은 그냥 어떤 application 이든 맘대로 사용할 수 있지만, signature가 들어가는 것으로 선언되어 있으면, 이 permission을 사용하기 위해서는 이 permission을 선언한 패키지와 같은 certicate로 application이 signature 되어야 한다. 이에 대한 설명은 다음에 하기로 한다. 절대 귀찮아서가 아님...-->
 
<permission android:name="org.mash.c2dm.permission.C2D_MESSAGE"
     android:protectionLevel="signature"/>

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="org.mash.c2dm.permission.C2D_MESSAGE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.INTERNET"/>



다음으로 메시지가 도착하게 되면 BroadcastReceiver를 등록하였기 때문에 이 클래스를 상속받은 클래스의 Override한 onReceive함수가 이벤트를 받게되고 여기서

@Override
public void onReceive(Context context, Intent intent){
     if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
         //등록ID를 받는 부분
          handleRegistration(context, intent);

     } else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")){
          //push된 메시지가 도착했을 때
     }

private void handleRegistration(Context context, Intent intent) {
    
     registration_id = intent.getStringExtra("registration_id");
    
     System.out.println("registration_id====>"+registration_id);
    
     if (intent.getStringExtra("error") != null) {
          //에러
     } else if (intent.getStringExtra("unregistered") != null) {
          //미등록
     } else if (registration_id != null) {
          //등록 아이디가 안왔을 때(안오는 경우도 가끔있다.)
     }
}

 
 
많이들 사용하는 카카오톡도 이걸로 할 수 있을듯 하다. 여하튼 C2DM은 유용하다.

반응형

'Android' 카테고리의 다른 글

Android 이메일&MMS 로 이미지 파일 첨부 보내기  (0) 2011.10.21
Android 미디어스캔  (0) 2011.10.21
버튼에 이미지와 텍스트  (0) 2011.10.17
Intro 활ㅋ용ㅋ  (0) 2011.10.13
Facebook 연동 방법  (0) 2011.10.13