2011. 3. 21. 18:10
[android] C2DM을 이용한 push notification
2011. 3. 21. 18:10 in 개발/모바일OS(안드로이드,아이폰,윈도모바일등)
C2DM 소개
등록
http://code.google.com/intl/ko-KR/android/c2dm/signup.html 에서 가입을 하고나면 해당 메일 주소로 메일이 하나 온다.
AUTH 정보 받기
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 |
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; public class Auth_android { private static String EMAIL = "메일주소" ; private static String PASS = "메일주소 비밀번호" ; private static String SOURCE = "알아보기 쉽게 적힌 프로그램 정보(예 : company-project-version. apple-iphone-4.2.1)" ; public static void main( String[] args ) throws Exception { try { StringBuffer postDataBuilder = new StringBuffer(); postDataBuilder.append( "Email=" + EMAIL); postDataBuilder.append( "&Passwd=" + PASS); postDataBuilder.append( "&accountType=GOOGLE" ); postDataBuilder.append( "&source=" + SOURCE); postDataBuilder.append( "&service=ac2dm" ); byte [] postData = postDataBuilder.toString().getBytes( "UTF8" ); URL url = new URL(HOST); 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(); } } } // 결과 SID=DQAAAL0AAADVvGAVXO....... LSID=DQAAAL8AAAAp5iSaE8h......... Auth=DQAAAL8AAADrYkFbucd............ // 요것만 사용함 |
registration_id 받기
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 |
<? xml version = "1.0" encoding = "utf-8" ?> package = "mint.TestC2dm" android:versionCode = "1" android:versionName = "1.0" android:minSdkVersion = "8" > < permission android:name = "mint.TestC2dm.permission.C2D_MESSAGE" android:protectionLevel = "signature" /> < uses-permission android:name = "mint.TestC2dm.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.WAKE_LOCK" /> < uses-permission android:name = "android.permission.GET_ACCOUNTS" /> < uses-permission android:name = "android.permission.USE_CREDENTIALS" /> < uses-permission android:name = "android.permission.READ_PHONE_STATE" /> < application android:icon = "@drawable/icon" android:label = "@string/app_name" > < activity android:name = ".TestC2dm" android:theme = "@android:style/Theme.Black.NoTitleBar" 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 = ".C2DMReceiver" android:permission = "com.google.android.c2dm.permission.SEND" > < intent-filter > < action android:name = "com.google.android.c2dm.intent.RECEIVE" /> < category android:name = "mint.TestC2dm" /> </ intent-filter > < intent-filter > < action android:name = "com.google.android.c2dm.intent.REGISTRATION" /> < category android:name = "mint.TestC2dm" /> </ intent-filter > </ receiver > < activity android:name = ".showMsg" android:screenOrientation = "portrait" android:theme = "@android:style/Theme.Translucent" android:launchMode = "singleTask" > < intent-filter > < action android:name = "android.intent.action.AlertDialogs" /> < category android:name = "android.intent.category.LAUNCHER" /> </ intent-filter > </ activity > </ application > </ manifest > |
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
32
33
34
35 |
package mint.TestC2dm; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.os.Bundle; import android.view.View; public class TestC2dm extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); } // 등록 public void onRegist(View v) { Intent registrationIntent = new Intent( "com.google.android.c2dm.intent.REGISTER" ); registrationIntent.putExtra( "app" , PendingIntent.getBroadcast( this , 0 , new Intent(), 0 )); registrationIntent.putExtra( "sender" , "메일주소" ); startService(registrationIntent); } // 해지 public void onUnregist(View v) { Intent unregIntent = new Intent( "com.google.android.c2dm.intent.UNREGISTER" ); unregIntent.putExtra( "app" , PendingIntent.getBroadcast( this , 0 , new Intent(), 0 )); startService(unregIntent); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
<? xml version = "1.0" encoding = "utf-8" ?> android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > < Button android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:text = "가입" android:onClick = "onRegist" /> < Button android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:text = "해지" android:onClick = "onUnregist" /> </ LinearLayout >l |
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 |
package mint.TestC2dm; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; import android.widget.Toast; public class C2DMReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.e( "###############" , "onReceive" ); 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) { Log.e( "###############" , "handleRegistration" ); String registration = intent.getStringExtra( "registration_id" ); if (intent.getStringExtra( "error" ) != null ) { // Registration failed, should try again later. } else if (intent.getStringExtra( "unregistered" ) != null ) { Log.e( "@@@@@@@@unregistered" , "unregistered" ); } else if (registration != null ) { // Send the registration ID to the 3rd party site that is sending the messages. // This should be done in a separate thread. // When done, remember that all registration is done. Log.e( "@@@@@@@@registration_id" , registration); } } private void handleMessage(Context context, Intent intent) { Log.e( "###############" , "handleMessage" ); String title = intent.getStringExtra( "title" ); String msg = intent.getStringExtra( "msg" ); // 화면 깨우기 PushWakeLock.acquireCpuWakeLock(context); Intent i = new Intent(context, showMsg. class ); Bundle b = new Bundle(); b.putString( "title" , title); b.putString( "msg" , msg); i.putExtras(b); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); } } |
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 |
package mint.TestC2dm; import android.app.KeyguardManager; import android.content.Context; import android.os.PowerManager; import android.util.Log; class PushWakeLock { private static PowerManager.WakeLock sCpuWakeLock; private static KeyguardManager.KeyguardLock mKeyguardLock; private static boolean isScreenLock; static void acquireCpuWakeLock(Context context) { Log.e( "PushWakeLock" , "Acquiring cpu wake lock" ); if (sCpuWakeLock != null ) { return ; } PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); sCpuWakeLock = pm.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "I'm your father" ); sCpuWakeLock.acquire(); // KeyguardManager km = (KeyguardManager)context.getSystemService(context.KEYGUARD_SERVICE); // mKeyguardLock = km.newKeyguardLock("key guard"); // if (km.inKeyguardRestrictedInputMode()) { // mKeyguardLock.disableKeyguard(); // isScreenLock = true; // } else { // isScreenLock = false; // } } static void releaseCpuLock() { Log.e( "PushWakeLock" , "Releasing cpu wake lock" ); // if (isScreenLock) { // mKeyguardLock.reenableKeyguard(); // isScreenLock = false; // } if (sCpuWakeLock != null ) { sCpuWakeLock.release(); sCpuWakeLock = null ; } } } |
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 |
package mint.TestC2dm; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; public class showMsg extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); String title, msg; Bundle bun = getIntent().getExtras(); title = bun.getString( "title" ); msg = bun.getString( "msg" ); AlertDialog.Builder alertDialog = new AlertDialog.Builder(showMsg. this ); alertDialog.setPositiveButton( "닫기" , new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { PushWakeLock.releaseCpuLock(); showMsg. this .finish(); } }); alertDialog.setNegativeButton( "보기" , new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startActivity( new Intent().setClassName(getPackageName(), getPackageName()+ ".TestC2dm" )); PushWakeLock.releaseCpuLock(); showMsg. this .finish(); } }); alertDialog.setTitle(title); alertDialog.setMessage(msg); alertDialog.show(); // 폰 설정의 조명시간을 가져와서 해당 시간만큼만 화면을 켠다. int defTimeOut = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 15000 ); TimerTask task = new TimerTask() { @Override public void run() { PushWakeLock.releaseCpuLock(); } }; Timer timer = new Timer(); timer.schedule(task, defTimeOut); } } |
1
2
3
4
5 |
###############: onReceive ###############: handleRegistration registration_id: APA91bGxex5sJi5hbeQkGUaURZo8....... |
메세지 보내기
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 |
import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; public class Push { private static String AUTH = "DQAAAL8AAADrYkFbucd............" ; // DB에 저장된 디바이스 토큰 목록 private static String[] arrId = { "APA91bGxex5sJi5hbeQkGUaURZo8......." // "APA91bHCRg6NhgMYv8Rbb2LVCoj4al......." }; public static void main( String[] args ) throws Exception { for ( int i= 0 ; i<arrId.length; i++) { androidPush(arrId[i], "제목" , "내용" ); } } public static void androidPush(String regId, String title, String msg) throws Exception { try { StringBuffer postDataBuilder = new StringBuffer(); postDataBuilder.append( "registration_id=" + regId); // 등록ID postDataBuilder.append( "&collapse_key=1" ); postDataBuilder.append( "&delay_while_idle=1" ); postDataBuilder.append( "&data.title=" + URLEncoder.encode(title, "UTF-8" )); // 제목 postDataBuilder.append( "&data.msg=" + URLEncoder.encode(msg, "UTF-8" )); // 내용 byte [] postData = postDataBuilder.toString().getBytes( "UTF8" ); URL url = new URL(HOST); 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=" +AUTH); OutputStream out = conn.getOutputStream(); out.write(postData); out.close(); conn.getInputStream(); } catch (Exception e) { e.printStackTrace(); } } } |
결과
문제점
- 메세지는 한번에 하나의 폰에만 전송 가능(해당 registration_id를 가진 폰에만 전송)=>그래서 loop를 돌아야한다
- 가끔씩 엄청 느리게 오는 메세지가 있다.(잘 되다가도 10분후에 메세지가 오는 경우도 있다)
- 폰에 구글계정을 등록해놔야한다
장점
- 한번 구독을 하면 앱이 실행되고있지 않아도 구독이 가능(재부팅 후 앱 실행없이도 정상 작동)