* c2dm : Android Cloud to Device Messaging (C2DM)
* 단점
1. 메시지의 누실 가능성 |
* 제약 사항
1. 한 메세지 사이즈 제약 : 1024 bytes 2. 전송 가능한 할당량 : 디폴트 200,000개 / 일 ( 참고 : http://code.google.com/intl/ko-KR/android/c2dm/quotas.html ) |
* 사전 준비
1. 구글에 c2dm 서비스 신청 : http://code.google.com/intl/ko-KR/android/c2dm/signup.html 2. 승인 Mail을 받으면 신청 완료 |
단말기 구현 |
1. AndroidManifest.xml
<receiver android:name="C2dmReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="Package Name" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="Package Name" />
</intent-filter>
</receiver>
<permission android:name="Package Name.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="Package Name.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
2. Register : 단말기 등록을 신청 하고 Registration ID 받기 ( 패키지명, 메일 주소가 키가 되는 듯 )
/**
* google C2DM - Registration ID
*/
public class C2dmRegistrator{
private Activity activity;
public C2dmRegistrator(Context context){
this.activity = (Activity)context;
}
//C2DM registation ID
public void requestRegistionId(){
Util.d(">>>>>> C2dmRegistrator");
Intent registrationIntent
= new Intent("com.google.android.c2dm.intent.REGISTER");
registrationIntent.putExtra("app",
PendingIntent.getBroadcast(activity, 0, new Intent(), 0));
registrationIntent.putExtra("sender", mail Address);
activity.startService(registrationIntent);
}
public void requestUnRegistion(){
Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
unregIntent.putExtra("app",
PendingIntent.getBroadcast(activity, 0, new Intent(), 0));
activity.startService(unregIntent);
}
}
3. Recevier
기능 :
1). REGISTRATION ID 요청에 대한 처리
2). Push Messages에 대한 처리
/**
* C2DM Brodcast Receiver Class
*/
public class C2dmBroadcastReceiver extends BroadcastReceiver {
static String registration_id = null;
static String c2dm_msg = "";
@Override
public void onReceive(Context context, Intent intent) {
// Registration ID received via an 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")){
handleMessage(context, intent);
}
}
private void handleRegistration(Context context, Intent intent) {
registration_id = intent.getStringExtra("registration_id");
if (intent.getStringExtra("error") != null) { // Registration Fail
// Registration failed, should try again later.
Log.d("c2dm", "registration failed");
String error = intent.getStringExtra("error");
if(error == "SERVICE_NOT_AVAILABLE"){
Log.d("c2dm", "SERVICE_NOT_AVAILABLE");
}else if(error == "ACCOUNT_MISSING"){
Log.d("c2dm", "ACCOUNT_MISSING");
}else if(error == "AUTHENTICATION_FAILED"){
Log.d("c2dm", "AUTHENTICATION_FAILED");
}else if(error == "TOO_MANY_REGISTRATIONS"){
Log.d("c2dm", "TOO_MANY_REGISTRATIONS");
}else if(error == "INVALID_SENDER"){
Log.d("c2dm", "INVALID_SENDER");
}else if(error == "PHONE_REGISTRATION_ERROR"){
Log.d("c2dm", "PHONE_REGISTRATION_ERROR");
}
} else if (intent.getStringExtra("unregistered") != null) {
Log.d("c2dm", "unregistered");
} else if (registration_id != null) { // Registration done
Editor editor =
context.getSharedPreferences
(Constants.C2DM_PREFERENCES_KEY, Context.MODE_PRIVATE).edit();
editor.putString(Constants.C2DM_REGISTRATION_ID, registration_id);
editor.commit();
// Send the registration ID to the 3rd party site that is sending messages.
// This should be done in a separate thread.
// When done, remember that all registration is done.
try {
String androidID = Secure.getString(
context.getContentResolver(), Secure.ANDROID_ID);
StringBuffer postDataBuilder = new StringBuffer();
postDataBuilder.append(URLEncoder.encode("device", "UTF-8"));
postDataBuilder.append("=");
postDataBuilder.append(URLEncoder.encode("token", "UTF-8"));
postDataBuilder.append("=");
postDataBuilder.append(URLEncoder.encode(androidID, "UTF-8"));
postDataBuilder.append("&");
postDataBuilder.append(URLEncoder.encode("reg_id", "UTF-8"));
postDataBuilder.append("=");
postDataBuilder.append(URLEncoder.encode(registration_id, "UTF-8"));
URL url = new URL(Constants.C2DM_URL);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(
conn.getOutputStream());
wr.write(postDataBuilder.toString());
wr.flush();
wr.close();
BufferedReader rd = new BufferedReader(new InputStreamReader(
conn.getInputStream(), "EUC-KR"));
String line;
while ((line = rd.readLine()) != null) {
Util.d("RECEIVE VALUE : " + line);
}
rd.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void handleMessage(Context context, Intent intent)
{
Util.d(">>>>> PUSH RECEIVE MESSAGES : " + c2dm_msg + " <<<<<");
c2dm_msg = intent.getExtras().getString("msg");
Intent i = new Intent(context, ShowMsgActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra("RECEIVE_PUSH_MSG", c2dm_msg);
context.startActivity(i);
}
}
서버(Third Party Server) Web 구현 |
1. Auth 인증을 통한 ClientLogin ( Auth Key 획득 )
- URL parameter : https://www.google.com/accounts/ClientLogin
- request parameter
- request sample
private static void auth()
{
try
{
StringBuffer postDataBuilder = new StringBuffer();
postDataBuilder.append("Email=" + "개발자이메일주소");
postDataBuilder.append("&Passwd=" + "개발자이메일암호");
postDataBuilder.append("&accountType=GOOGLE");
postDataBuilder.append("&source=" + "어플정보 또는 디바이스 정보");
postDataBuilder.append("&service=ac2dm");
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 in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String inputLine;
while((inputLine = in.readLine()) != null)
{
System.out.println(inputLine);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
- response sample
* Push 메시지를 보내기 위해서는 Auth 값을 저장 하고 있다가 메시지를 보낼 때 사용된다.
2. PUSH SEND
- Post Data URL : https://android.apis.google.com/c2dm/send
- Request parameter
- Request Sample
/** C2DM으로 메세지를 보내는 메소드 */
public void sender(String registration_id, String authToken, String msg)
throws Exception {
// collapse_key는 C2DM에서 사용자가 SEND 버튼을 실수로 여러번 눌렀을때
// 이전 메세지 내용과 비교해서 반복전송되는 것을 막기 위해서 사용된다.
// 여기서는 반복전송도 허용되게끔 매번 collapse_key를 랜덤함수로 뽑는다.
String collaspe_key = String.valueOf(Math.random() % 100 + 1);
// 보낼 메세지 조립
StringBuffer postDataBuilder = new StringBuffer();
postDataBuilder.append("registration_id=" + registration_id);
postDataBuilder.append("&collapse_key=" + collaspe_key); // 중복방지 필터
postDataBuilder.append("&delay_while_idle=1");
postDataBuilder.append("&data.msg=" + URLEncoder.encode(msg, "UTF-8"));
// 조립된 메세지를 Byte배열로 인코딩
byte[] postData = postDataBuilder.toString().getBytes("UTF-8");
// HTTP 프로토콜로 통신한다.
// 먼저 해당 url 커넥션을 선언하고 연다.
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"); // POST 방식
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length",
Integer.toString(postData.length));
conn.setRequestProperty("Authorization", "GoogleLogin auth="
+ authToken);
// 출력스트림을 생성하여 postData를 기록.
OutputStream out = conn.getOutputStream();
// 출력(송신)후 출력스트림 종료
out.write(postData);
out.close();
// 소켓의 입력스트림을 반환
conn.getInputStream();
}