다음 마이피플이 PC용으로 나온다고해서 멀까 하고 찾아보고있었습니다
현재 C2DM 이라는 기술이 궁금해서 검색해보니 다음과 같은 정보를 얻을수 있었습니다.

출처는 : http://www.androidside.com/bbs/board.php?bo_table=B46&wr_id=14705

안녕하세요^^ 리칼입니다.

저도 안드로이드를 하면서 제가 이런글을 올리게 될지 몰랐네요 ㅎㅎ

솔직히 자기의 소스를 공유하면서 강좌 하시는분들을 보면서 정말 대단하다고 생각하였습니다.

자기 시간내기도 힘든데 저렇게 강좌하시는분들이 있기에 안드로이드의 미래가 밝다고 생각합니다.

그래서 조금이나마 저도 보템이 되려고 이렇게 c2dm에 관한 예제를 올리게 되었습니다^^

자! 그럼 시작할께요. 미숙하지만 잘봐주셨으면 감사하겠습니다~

일단 c2dm이 Cloud to Device Messaging 의 약자로 알고 있습니다. 안드로이드 2.2 프로요부터 생겨난 

이 API는 개발자들이 서버와 모바일 어플리케이션간에 데이타를 쉽게 싱크할 수 있도록, 서버쪽 에서에서 

안드로이드 폰 상의 어플리케이션으로 데이타를 손쉽게 전달할 수 있도록 도와줍니다.

쉽게 생각하시면 아이폰의 푸쉬 기능이라고 보시면 됩니다. 현재 c2dm이 나오기전까진 polling기법을 

토하여 실시간 메시징을 했다고 알고있는데 이번 이 api가 추가되면서 일반 서드파티 개발자도 손쉽게 

프로그래밍을 개발할수 있으리라 봅니다. 자! 서론이 길었네요 바로 본론으로!

먼저 푸쉬를 사용하기 위해선 구글에 신청을 하여야 합니다. 이게좀 귀찮죠. 신청을 해도 바로 사용할수 

있는게 아니라 승인 메일이 와야합니다. 전 일주정도 걸린듯 하네요..미리미리 신청하세요~~

http://code.google.com/intl/ko-KR/android/c2dm/signup.html 이쪽에서 신청하시면 됩니다.

그러면 메일이 invite어쩌고 올겁니다. 그러면 그담부터 사용해도 된다는거죠 

제가 만들어 보려는 예제는 메시지를 보내서 실시간으로 다른 폰으로 가게 하는겁니다. 하지만 

그럴려면 폰이 2대가 있어야 하는데 대부분 1대밖에 없다는 가정하에 제가 제 자신폰으로 보내게 하도록 

구성하였습니다.

간단히 기본 구성원리를 설명해드리겠습니다.

c2dm을 사용하기 위해선 크게 5가지가 필요합니다. 

개발자ID(구글계정), 애플리케이션ID(패키지이름정도), 등록ID(특정장치를식별하는 ID),
구글사용자계정(보통핸드폰로그인구글계정),인증토큰값이 필요합니다.

처음에 어플을 실행하여 개발자ID와 어플ID를 c2dm서버에 전송하여 등록ID를 발급 받습니다.
그러면 그 ID가 자기 식별고유ID가 됩니다. 이걸로 상대방 핸드폰을 식별하게 되는거죠.

그담에 메시지를 쓰고 전송을 누르면 먼저 c2dm에 인증을 요청해야 합니다. 아무나 보내면 

보안에 문제가 있겠죠? 이때 개발자ID가 필요합니다. 개발자가 c2dm을 신청하였기 때문에 

쓸수가 있는거죠~ 그리고 나서 인증을 되면 등록ID,인증토큰값,보낼 메시지등등을 푸쉬에 담아

상대방 핸드폰으로 보내게 됩니다... 여기서 중요한건 저는 지금 제 자신에게 푸쉬를 보내게 

만들었습니다. 그러므로 다중 메시지보내기 어플을 만들게 된다면 상대방의 등록ID를 알아야겠죠?

그럴라면 서드파티서버가 필요합니다. 그 서버를 구현하여 디비를 만들고 상대방의 ID를 등록

시켜서 푸쉬를 보내야 할것입니다. 이건 사용자가 직접 구현해야 하는 사항입니다.

대충이렇습니다. 


////////////////////////////////////////////////////////////////////////////////////


자 이제 c2dm 예제를 시작하겠습니다. 먼저 프로젝트 생성후 대충 저처럼 UI구성하세요.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#ffffff"
    android:gravity="center_vertical"
    >
<TextView  
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="메세지 보내기"
    />
    <EditText
    android:id="@+id/msg_text"
    android:layout_width="180dip" 
    android:layout_height="wrap_content"/> 
    <Button
    android:id="@+id/msg_send"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="보내기"/> 
</LinearLayout>




그리고 메인 activity 에서 아까 말한것 같이 등록ID를 발급 받아야 합니다. 
이렇게 작성하시면 됩니다. 

C2dm.java

public class C2dmTest extends Activity {
    /** Called when the activity is first created. */
EditText msg_text;
Button msg_send;
private OutputStream out = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
//C2DM 등록ID 발급
Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0)); // 어플리케이션ID
registrationIntent.putExtra("sender", "xxxxxxxx@gmail.com"); //개발자ID
startService(registrationIntent); //서비스 시작(등록ID발급받기)
                 // 위에서 지정한 "app"와 "sender"은 맘대로 지정하시는게 아니라 구글에서 필요한 변수명들입니다.
        
        
        msg_text = (EditText)findViewById(R.id.msg_text);
        msg_send = (Button)findViewById(R.id.msg_send);
        
        msg_send.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
try {
// 메시지를 보낼때 sender(발급받은 ID, 토큰인증값, 메시지)
sender(C2dm_BroadcastReceiver.registration_id,getAuthToken(),msg_text.getText().toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
    }
    
    public void sender(String regId,String authToken,String msg) throws Exception{
     StringBuffer postDataBuilder = new StringBuffer();
        
     postDataBuilder.append("registration_id="+regId); //등록ID
     postDataBuilder.append("&collapse_key=1"); 
     postDataBuilder.append("&delay_while_idle=1");
     postDataBuilder.append("&data.msg="+URLEncoder.encode(msg, "UTF-8")); //태울 메시지

        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"); //똑같이 써주셔야 합니다.
        postDataBuilder.append("&Email=xxxxxx@gmail.com");  //개발자 구글 id
        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();

        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        
        String sidLine = br.readLine();
        String lsidLine = br.readLine();
        String authLine = br.readLine();
        
        System.out.println("sidLine----------->>>"+sidLine);
        System.out.println("lsidLine----------->>>"+lsidLine);
        System.out.println("authLine----------->>>"+authLine);
        System.out.println("AuthKey----------->>>"+authLine.substring(5, authLine.length()));
        
        authtoken = authLine.substring(5, authLine.length());
        
     return authtoken;
    }

}


소스를 보시면 대충 아실겁니다. 인증ID와 토큰값을 구해서 메시지만 푸쉬에 태워서 보내는겁니다.

자 여기서 중요한건 저 메시지를 이용하기 위해선 AndroidManifest.xml 등록을 해줘야 하는 부분이 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="test.android.test"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".C2dmTest"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
<receiver android:name=".C2dm_BroadcastReceiver"
       android:permission="com.google.android.c2dm.permission.SEND"> 
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="test.android.test"/>
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="test.android.test"/>
</intent-filter>
    </receiver>
    </application>
    
    <permission android:name="test.android.test.permission.C2D_MESSAGE"
     android:protectionLevel="signature"/>
    
    <uses-permission android:name="test.android.test.permission.C2D_MESSAGE"/>
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    
    <uses-sdk android:minSdkVersion="8" />

</manifest> 

빨간색으로 표시한 부분이 추가한 부분입니다. 퍼피션 부분을 추가하고 자기 패키지에 맞게 설정을

하셔야 보내고 받기를 할수가 있습니다. 그리고 저위에 리시버 부분을 보시면 저부분이 발급ID를 만들기

위해 보내고 메시지를 받고 하는 부분입니다. C2dm_BroadcastReceiver 클래스 파일이 중요한 역할을 

하게 되죠.

C2dm_BroadcastReceiver.java

public class C2dm_BroadcastReceiver extends BroadcastReceiver{
    /** Called when the activity is first created. */
static String registration_id = null;
static String c2dm_msg = "";
    @Override
    public void onReceive(Context context, Intent intent) {
     if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
    
     handleRegistration(context, intent);
    
     } else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
    
     c2dm_msg = intent.getExtras().getString("msg");
    
     System.out.println("c2dm_msg======>"+c2dm_msg);
     Toast toast = Toast.makeText(context, "메시지 도착!\n"+c2dm_msg, Toast.LENGTH_SHORT );
  toast.setGravity( Gravity.TOP | Gravity.CENTER, 0, 150 );
  toast.show();
    
     }
    }
    
    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) {
    
     Log.v("C2DM_REGISTRATION",">>>>>" + "Registration failed, should try again later." + "<<<<<");
    
     } else if (intent.getStringExtra("unregistered") != null) {

     Log.v("C2DM_REGISTRATION",">>>>>" + "unregistration done, new messages from the authorized sender will be rejected" + "<<<<<");
    
     } else if (registration_id != null) {
    
     System.out.println("registration_id complete!!");
     }
    }
    
    
}

바로 이 클래스가 BroadcastReceiver를 상속받아서 통보를 하는 역할을 하게 되죠.

BroadcastReceiver 의 역할은 제 설명보다는 직접 찾아보시는게 좋을듯해요 ㅠㅠ 제가 설명을 잘못해서~

무튼 간단하게 통보 역할을 하신다고 보면 되겠네요~

저위에 보면 BroadcastReceiver를 상속받아  onReceive를 오버라이드 한걸 보실수 있습니다.

C2dmTest activity에서 처음에 등록을 하게되면 이 onReceive를 통해 아이디를 받을수 있습니다.

적절한 if문을 통해 받을수가 있죠 

if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
이부분이 바로 등록ID를 받는 부분입니다. 등록ID를 받게되면 handleRegistration함수에서 id를 제대로 받았는지 

검사하게 됩니다. 이제 등록ID를 받으면 준비가 된겁니다. 그리고 이제 메시지를 쓰셔서 보내기를 

클릭하시면sender(C2dm_BroadcastReceiver.registration_id,getAuthToken(),msg_text.getText().toString());이 메소드를 

통해 인증을 하고 등록값과 메시지를 상대방에게 보내지게 됩니다. 

그러면 메시지를 수신하게 되면 또 BroadcastReceiver를 사용하게 됩니다. 아까 메니페스트에서 등록한 

리시브가 그역할을 하게 됩니다. 

이번엔 else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
이부분이 받게 되겠죠? 여기서 메시지를 이제 받아야겠죠? 아까 위에서 센드해서 보낼때

postDataBuilder.append("&data.msg="+URLEncoder.encode(msg, "UTF-8")); 이부분을 볼수 있습니다. 

메시지 말고 다른 변수도 태워 보내실거면 저밑에 data.xxx로 추가하셔서 보내시면 됩니다. 

postDataBuilder.append("&data.phone="+URLEncoder.encode(phone, "UTF-8")); 이렇게 보내시면 됩니다.

그렇게 보낸걸 받을때는 c2dm_msg = intent.getExtras().getString("msg");이렇게만 받으시면 됩니다. 

data.xxx 에서 xxx만 꺼내시면 됩니다. 이렇게 하시면 푸쉬를 받게 되실 겁니다. 

그리고 아직 c2dm이 정식으로 나온게 아니라 그런지 푸쉬가 잘안올때가 있습니다.

안오게 된다고 걱정마시고 계속 하시다 보면 언젠가 옵니다 ㅋㅋ

저부분에서 응용하시면 될듯하네요 노티를 사용하시거나 진동및 사운드 등등은

여러분의 몫!



휴 쓰다보니 정신없이 쓰게 됐네요 -_-;; 제대로 썻는지도 모르겠습니다..


무튼 저처럼 고생하시는 분없기를 기대하면서.. 저는 이만 






+ Recent posts