안드로이드 푸시 기능 구현 (2) - 안드로이드 앱
Google Cloud Messaging for Android
구글 문서를 참고하여 작성한 글입니다.
Step 1. 프로젝트 생성
프로젝트 이름과 패키지, 경로를 설정합니다.
타깃 os 를 설정하고
기본 액티비티를 선택합니다.
몇가지 이름을 설정하고 Finish!
프로젝트가 생성되길 기다립니다.
Step 2. Dependencies 설정
푸시기능을 구현하기위해 라이브러리를 추가해야합니다.
네비게이터에서 최상위 디렉터리 app을 선택하고 F4를 누릅니다.
아래와 같은 Project structure 창이 뜹니다.
Dependencies탭을 선택하고 우측에 +버튼을 눌러
Library Dependency를 선택!
play-services를 검색하면
com.google.android.gms:play-services가 나옵니다.
고놈을 선택하고 OK!
* 만약 나오지 않는다면 SDK Manager를 통해 설치 하면됩니다.
추가 되었는지 확인하고 OK!
Step 3. Manifest 수정
푸시 기능을 사용하기 위해서 몇 가지 추가할 사항이 있습니다.
권한과 메시지를 수신햇을때의 receiver를 추가해야합니다.
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> <permission android:name="com.example.app.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="com.example.app.permission.C2D_MESSAGE" />
INTERNET
서드파티 서버와 통신하기위한 권한입니다.
서드파티 서버는 디바이스의 registrationID를 저장하고 해당 ID로 메시지를 요청할 수있는 기능을 합니다.
GET_ACCOUNTS
Gcm을 사용하기위해 필요한 권한입니다.
WAKE_LOCK
잠들어있는 디바이스를 꺠우는 권한 입니다.
RECEIVE
registrationId를 수신하기위한권한입니다.
C2D_MESSAGE
다른 앱이 메시지를 수신하는것을 방지하는 역할을 합니다.
패키지명을 정확히 입력해야합니다.
com.example.app부분에 자신의 패키지 경로를 입력합니다.
<receiver android:name=".GcmBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" > <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <category android:name="com.example.app" /> </intent-filter> </receiver> <service android:name=".GcmIntentService" />
GcmBroadcastReceiver
메시지를 수신할 녀석을 설정해줍니다.
만약 패키지가 다르다면 패키지명을 추가로 적어주시면 됩니다.
intent-filter category의 com.example.app 또한 수정해주어야합니다.
GcmIntentServic
쉽게말해 GcmBroadCastReceiver가 메시지 처리를 위해 실행해주는 녀석입니다.
여기서 Noti를 뿌려주게 됩니다.
만약 패키지가 다르다면 패키지명을 추가로 적어주시면됩니다.
Step 4. activity_main.xml 수정
기능테스트를 위해 다음과 같이 만들어줍니다.
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/regist" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="regist"/> <Button android:id="@+id/unregist" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="unregist"/> <Button android:id="@+id/send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="send"/> <Button android:id="@+id/clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="clear"/> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <ScrollView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/scrollView" android:layout_centerVertical="true" android:layout_centerHorizontal="true" > <TextView android:id="@+id/display" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="this is ScrollView"/> </ScrollView> </LinearLayout> </LinearLayout>
Step 5. 코딩
구글 코드의 GCM 예제 소스를 참고하여 수정해 작성하였습니다.
먼저 GCM서버로부터 푸시 신호를 받아 IntentService를 실행해줄 리시버를 작성합니다.
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { ComponentName comp = new ComponentName(context.getPackageName(), GcmIntentService.class.getName()); startWakefulService(context, (intent.setComponent(comp))); setResultCode(Activity.RESULT_OK); } }
예제소스의 GcmBaseIntentService를 확장하는 GcmIntentService를 작성합니다.
import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.support.v4.app.NotificationCompat; import android.util.Log; import com.utilities.ServerUtilities; import java.util.HashMap; import java.util.Map; import static com.utilities.CommonUtilities.displayMessage; public class GcmIntentService extends GcmBaseIntentService { private final static String TAG="IntentService"; public static final int NOTIFICATION_ID = 1; private NotificationManager mNotificationManager; NotificationCompat.Builder builder; public GcmIntentService() { super("GcmIntentService"); } @Override protected void onRegistered(Context context, String registrationId) { Log.i(TAG, "Device registered: regId = " + registrationId); displayMessage(context, getString(R.string.gcm_registered, registrationId)); ServerUtilities.register(context, registrationId); } @Override protected void onUnregistered(Context context, String registrationId) { Log.i(TAG, "Device unregistered"); displayMessage(context, getString(R.string.gcm_unregistered)); ServerUtilities.unregister(context, registrationId); } @Override protected void onMessage(Context context, Intent intent) { Log.i(TAG, "Received message. Extras: " + intent.getExtras()); displayMessage(context, intent.getExtras().toString()); generateNotification(context, intent.getExtras().toString()); } @Override protected void onDeletedMessages(Context context, int total) { Log.i(TAG, "Received deleted messages notification"); String message = getString(R.string.gcm_deleted, total); displayMessage(context, message); generateNotification(context, message); } @Override public void onError(Context context, String errorId) { Log.i(TAG, "Received error: " + errorId); displayMessage(context, getString(R.string.gcm_error, errorId)); } @Override protected boolean onRecoverableError(Context context, String errorId) { Log.i(TAG, "Received recoverable error: " + errorId); displayMessage(context, getString(R.string.gcm_recoverable_error, errorId)); return super.onRecoverableError(context, errorId); } private static void generateNotification(Context context, String message) { int icon = R.drawable.ic_launcher; long when = System.currentTimeMillis(); Map<string,string> kvMap=new HashMap<string,string>(); kvMap=MessageParser(message); Log.d("KVMAP", kvMap.toString()); Log.d("KVMAP", kvMap.get("title")); Log.d("KVMAP", kvMap.keySet().toString()); String TestTitle,TestMessage=""; TestTitle=kvMap.get("title"); Object[]keys=kvMap.keySet().toArray(); for(Object key:keys){ String k=(String)key; if(k.indexOf("key")==0){ TestMessage=kvMap.get(k)+"\n"+TestMessage; }else{ continue; } } Log.d("TestMessage", TestMessage); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); Notification notification = new Notification(icon, TestMessage, when); String title = context.getString(R.string.app_name); Intent notificationIntent = new Intent(context, MainActivity.class); notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0); notification.setLatestEventInfo(context, TestTitle, TestMessage, intent); notification.flags |= Notification.FLAG_AUTO_CANCEL; notification.vibrate=new long[]{0,100,200,300,400}; notificationManager.notify(0, notification); } public static HashMap<string, string=""> MessageParser(String jsonData){ HashMap<string, string=""> kvMap = new HashMap<string, string="">(); jsonData=jsonData.substring(8, jsonData.length()-2); Log.d("myTag",jsonData); String[]items=jsonData.split(", "); for(String item : items){ String[] kv=item.split("="); kvMap.put(kv[0], kv[1]); } return kvMap; } }
MainActivity에서 버튼의 기능등을 작성합니다.
package com.gcmtester; package com.gcmtester; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.AsyncTask; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import com.utilities.Constants; import com.utilities.ServerUtilities; import com.google.android.gms.gcm.GoogleCloudMessaging; import com.utilities.CommonUtilities; import java.io.IOException; import static com.utilities.Constants.SENDER_ID; public class MainActivity extends ActionBarActivity { private static final String TAG = "MainActivity"; private GoogleCloudMessaging gcm; private String regId; private Context context; Button regist, unregist, send, clear; TextView mDisplay; AsyncTask<void,void,string> sender; AsyncTask<void,void,string> register; AsyncTask<void,void,void> registerOnServer; AsyncTask<void,void,string> unregister; AsyncTask<void,void,void> unregisterOnServer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = getApplicationContext(); registerReceiver(mHandleMessageReceiver,new IntentFilter(Constants.DISPLAY_MESSAGE_ACTION)); mDisplay = (TextView)findViewById(R.id.display); regist=(Button)findViewById(R.id.regist); unregist=(Button)findViewById(R.id.unregist); send=(Button)findViewById(R.id.send); clear=(Button)findViewById(R.id.clear); send.setOnClickListener(clickAction); clear.setOnClickListener(clickAction); regist.setOnClickListener(clickAction); unregist.setOnClickListener(clickAction); if(CommonUtilities.checkPlayServices(this)){ gcm = GoogleCloudMessaging.getInstance(this); regId = CommonUtilities.getRegistrationId(context); } } View.OnClickListener clickAction=new View.OnClickListener() { @Override public void onClick(View view) { if(view == findViewById(R.id.regist)){ register=new AsyncTask<void,void,string>() { @Override protected String doInBackground(Void... params) { String msg = ""; try { if (gcm == null) { gcm = GoogleCloudMessaging.getInstance(context); } regId = gcm.register(SENDER_ID); msg = "Device registered, registration ID=" + regId; RegistToBackend(); CommonUtilities.storeRegistrationId(context, regId); } catch (IOException ex) { msg = "Error :" + ex.getMessage(); } return msg; } @Override protected void onPostExecute(String msg) { register=null; mDisplay.append(msg + "\n"); } }.execute(null, null, null); } else if (view == findViewById(R.id.unregist)){ unregister=new AsyncTask<void,void,string>() { @Override protected String doInBackground(Void... params) { String msg = ""; try { if (gcm == null) { gcm = GoogleCloudMessaging.getInstance(context); } gcm.unregister(); msg = "Device unregistered, registration ID=" + regId; unRegistToBackend(); CommonUtilities.removeRegistrationId(context, regId); } catch (IOException ex) { msg = "Error :" + ex.getMessage(); } return msg; } @Override protected void onPostExecute(String msg) { unregister=null; mDisplay.append(msg + "\n"); } }.execute(null, null, null); } else if (view == findViewById(R.id.send)) { sender=new AsyncTask<void,void,string>() { @Override protected String doInBackground(Void... params) { String msg = ""; ServerUtilities.sendPushMessage(context,regId); return msg; } @Override protected void onPostExecute(String msg) { sender=null; mDisplay.append(msg + "\n"); } }.execute(null, null, null); } else if (view == findViewById(R.id.clear)) { mDisplay.setText(""); } } }; private void RegistToBackend() { if (CommonUtilities.isRegisteredOnServer(context)) { mDisplay.append(getString(R.string.already_registered) + "\n"); return; } registerOnServer=new AsyncTask<void, void,="" void="">() { @Override protected Void doInBackground(Void... params) { ServerUtilities.register(context,regId); return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); CommonUtilities.setRegisteredOnServer(context,true); registerOnServer=null; } }.execute(null,null,null); } private void unRegistToBackend() { if (!CommonUtilities.isRegisteredOnServer(context)) { mDisplay.append(getString(R.string.already_unregistered) + "\n"); return; } registerOnServer=new AsyncTask<void, void,="" void="">() { @Override protected Void doInBackground(Void... params) { ServerUtilities.unregister(context,regId); return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); CommonUtilities.setRegisteredOnServer(context,false); registerOnServer=null; } }.execute(null,null,null); } private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d("sequence", "receiver"); String newMessage = intent.getExtras().getString(Constants.EXTRA_MESSAGE); mDisplay.append(newMessage + "\n"); Log.d(TAG, "newMessage is : " + newMessage); } }; }
RegistToBackend는 post요청을 통해 서버에 RegistrationID를 보내줍니다.
마찬가지로 unRegistToBackend 또한 단순히 RegistrationID를 보내줍니다.
이를 받은서버는 각각 DB에 저장하고 DB에서 삭제하는 기능을 수행합니다.
sendPushMessage도 post요청을 보내고 요청을 받은 서버는
GCM서버에 메시지 전송을 요청합니다.
CommonUtilities에서 몇가지 기능들을 작성합니다.
package com.utilities; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.util.Log; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import java.sql.Timestamp; import static com.utilities.Constants.PLAY_SERVICES_RESOLUTION_REQUEST; public class CommonUtilities { private final static String TAG = "CommonUtilities"; private static final String PROPERTY_REG_ID = "registration_id"; private static final String PROPERTY_APP_VERSION = "appVersion"; public static boolean checkPlayServices(Activity activity){ int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity); if (resultCode != ConnectionResult.SUCCESS) { if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { GooglePlayServicesUtil.getErrorDialog(resultCode, activity, PLAY_SERVICES_RESOLUTION_REQUEST).show(); } else { Log.i(TAG, "This device is not supported."); activity.finish(); } return false; } return true; } public static void storeRegistrationId(Context context, String regId) { final SharedPreferences prefs = getGCMPreferences(context); int appVersion = getAppVersion(context); Log.i(TAG, "Saving regId on app version " + appVersion); SharedPreferences.Editor editor = prefs.edit(); editor.putString(PROPERTY_REG_ID, regId); editor.putInt(PROPERTY_APP_VERSION, appVersion); editor.apply(); } public static void removeRegistrationId(Context context, String regId) { final SharedPreferences prefs = getGCMPreferences(context); int appVersion = getAppVersion(context); Log.i(TAG, "Saving regId on app version " + appVersion); SharedPreferences.Editor editor = prefs.edit(); editor.putString(PROPERTY_REG_ID, ""); editor.putInt(PROPERTY_APP_VERSION, appVersion); editor.apply(); } public static String getRegistrationId(Context context) { final SharedPreferences prefs = getGCMPreferences(context); String registrationId = prefs.getString(PROPERTY_REG_ID, ""); if (registrationId.isEmpty()) { Log.i(TAG, "Registration not found."); return ""; } int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE); int currentVersion = getAppVersion(context); if (registeredVersion != currentVersion) { Log.i(TAG, "App version changed."); return ""; } return registrationId; } public static SharedPreferences getGCMPreferences(Context context) { return context.getSharedPreferences(com.gcmtester.MainActivity.class.getSimpleName(), Context.MODE_PRIVATE); } public static int getAppVersion(Context context) { try { PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return packageInfo.versionCode; } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException("Could not get package name: " + e); } } public static void displayMessage(Context context, String message) { Log.d("sequence", "displaymessage"); Intent intent = new Intent(Constants.DISPLAY_MESSAGE_ACTION); intent.putExtra(Constants.EXTRA_MESSAGE, message); context.sendBroadcast(intent); } public static long getRegisterOnServerLifespan(Context context) { final SharedPreferences prefs = getGCMPreferences(context); long lifespan = prefs.getLong(Constants.PROPERTY_ON_SERVER_LIFESPAN, Constants.DEFAULT_ON_SERVER_LIFESPAN_MS); return lifespan; } public static void setRegisteredOnServer(Context context, boolean flag) { // set the flag's expiration date long lifespan = getRegisterOnServerLifespan(context); long expirationTime = System.currentTimeMillis() + lifespan; setRegisteredOnServer(context, flag, expirationTime); } private static void setRegisteredOnServer(Context context, Boolean flag, long expirationTime) { final SharedPreferences prefs = getGCMPreferences(context); SharedPreferences.Editor editor = prefs.edit(); if (flag != null) { editor.putBoolean(Constants.PROPERTY_ON_SERVER, flag); log(context, Log.VERBOSE, "Setting registeredOnServer flag as %b until %s", flag, new Timestamp(expirationTime)); } else { log(context, Log.VERBOSE, "Setting registeredOnServer expiration to %s", new Timestamp(expirationTime)); } editor.putLong(Constants.PROPERTY_ON_SERVER_EXPIRATION_TIME, expirationTime); editor.commit(); } public static boolean isRegisteredOnServer(Context context) { final SharedPreferences prefs = getGCMPreferences(context); boolean isRegistered = prefs.getBoolean(Constants.PROPERTY_ON_SERVER, false); log(context, Log.VERBOSE, "Is registered on server: %b", isRegistered); if (isRegistered) { long expirationTime = prefs.getLong(Constants.PROPERTY_ON_SERVER_EXPIRATION_TIME, -1); if (System.currentTimeMillis() > expirationTime) { log(context, Log.VERBOSE, "flag expired on: %s", new Timestamp(expirationTime)); return false; } } return isRegistered; } private static void log(Context context, int priority, String template, Object... args) { if (Log.isLoggable(TAG, priority)) { String message = String.format(template, args); Log.println(priority, TAG, "[" + context.getPackageName() + "]: " + message); } } }
ServerUtilities에서 서버에 등록, 제거, 메시지 전송요청 등의 기능을 작성합니다.
package com.utilities; import android.content.Context; import android.content.Intent; import android.util.Log; import com.gcmtester.R; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Random; public final class ServerUtilities { static final String DISPLAY_MESSAGE_ACTION = "com.google.android.gcm.demo.app.DISPLAY_MESSAGE"; public static final String EXTRA_MESSAGE = "message"; private final static String TAG="serverUtil"; private static final int MAX_ATTEMPTS = 5; private static final int BACKOFF_MILLI_SECONDS = 2000; private static final Random random = new Random(); public static void register(final Context context, final String regId) { Log.i(TAG, "registering device (regId = " + regId + ")"); String serverUrl = "서버주소:포트/register"; JSONObject jsonObject = new JSONObject(); try{ jsonObject.accumulate("regId",regId); jsonObject.accumulate("senderId",Constants.SENDER_ID); }catch(Exception e){ Log.d("makeJson", e.getLocalizedMessage()); } for (int i = 1; i <= MAX_ATTEMPTS; i++) { Log.d(TAG, "Attempt #" + i + " to register"); Log.d("sequence", "server util"); displayMessage(context, context.getString( R.string.server_registering, i, MAX_ATTEMPTS)); post(serverUrl,jsonObject); String message = context.getString(R.string.server_registered); displayMessage(context, message); return; } String message = context.getString(R.string.server_register_error,MAX_ATTEMPTS); displayMessage(context, message); } public static void unregister(final Context context, final String regId) { Log.i(TAG, "unregistering device (regId = " + regId + ")"); String serverUrl = "서버주소:포트/unregister"; JSONObject jsonObject = new JSONObject(); try{ jsonObject.accumulate("regId",regId); jsonObject.accumulate("senderId",Constants.SENDER_ID); }catch(Exception e){ Log.d("makeJson", e.getLocalizedMessage()); } try { post(serverUrl, jsonObject); String message = context.getString(R.string.server_unregistered); displayMessage(context, message); } catch (Exception e) { String message = context.getString(R.string.server_unregister_error, e.getMessage()); displayMessage(context, message); } } public static void sendPushMessage(final Context context, final String regId){ Log.i(TAG, "Request Send Push Message"); String serverUrl = "서버주소:포트/send"; JSONObject jsonObject = new JSONObject(); try{ jsonObject.accumulate("regId",regId); jsonObject.accumulate("senderId",Constants.SENDER_ID); }catch(Exception e){ Log.d("makeJson", e.getLocalizedMessage()); } try { post(serverUrl, jsonObject); String message = context.getString(R.string.server_sended); displayMessage(context, message); } catch (Exception e) { String message = context.getString(R.string.server_send_error, e.getMessage()); displayMessage(context, message); } } private static String post(String url, JSONObject jsonObject){ InputStream inputStream = null; String result = ""; try { HttpClient httpclient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(url); String json = ""; json = jsonObject.toString(); StringEntity se = new StringEntity(json); httpPost.setEntity(se); httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Content-type", "application/json"); HttpResponse httpResponse = httpclient.execute(httpPost); inputStream = httpResponse.getEntity().getContent(); if(inputStream != null) result = convertInputStreamToString(inputStream); else result = "Did not work!"; } catch (Exception e) { Log.d("InputStream", e.getLocalizedMessage()); } return result; } private static String convertInputStreamToString(InputStream inputStream) throws IOException{ BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream)); String line = ""; String result = ""; while((line = bufferedReader.readLine()) != null) result += line; inputStream.close(); return result; } static void displayMessage(Context context, String message) { Log.d("sequence", "displaymessage"); Intent intent = new Intent(DISPLAY_MESSAGE_ACTION); intent.putExtra(EXTRA_MESSAGE, message); context.sendBroadcast(intent); } }
Constants에서는 각각의 코드에서 필요한 상수를 정의합니다.
package com.utilities; public class Constants { public final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000; public final static String SENDER_ID="1번글에서 획득한 프로젝트넘버"; public static final String INTENT_FROM_GCM_LIBRARY_RETRY = "com.google.android.gcm.intent.RETRY"; public static final String INTENT_FROM_GCM_MESSAGE = "com.google.android.c2dm.intent.RECEIVE"; public static final String EXTRA_UNREGISTERED = "unregistered"; public static final String EXTRA_ERROR = "error"; public static final String EXTRA_REGISTRATION_ID = "registration_id"; public static final String EXTRA_SPECIAL_MESSAGE = "message_type"; public static final String VALUE_DELETED_MESSAGES = "deleted_messages"; public static final String EXTRA_TOTAL_DELETED = "total_deleted"; public static final String ERROR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE"; public static final String BACKOFF_MS = "backoff_ms"; public static final int DEFAULT_BACKOFF_MS = 3000; public static final String DISPLAY_MESSAGE_ACTION = "com.google.android.gcm.demo.app.DISPLAY_MESSAGE"; public static final String EXTRA_MESSAGE = "message"; public static final String PROPERTY_ON_SERVER = "onServer"; public static final String PROPERTY_ON_SERVER_EXPIRATION_TIME = "onServerExpirationTime"; public static final String PROPERTY_ON_SERVER_LIFESPAN = "onServerLifeSpan"; public static final long DEFAULT_ON_SERVER_LIFESPAN_MS = 1000 * 3600 * 24 * 7; private Constants() { throw new UnsupportedOperationException(); } }
안드로이드 앱이 준비되었습니다.
앱을 등록하고 등록된 앱에게 메시지를 보내기위해 앱서버를 만들어 줘야합니다.
다음 글에서 확인 하도록하겠습니다.
이전글 : 안드로이드 푸시 기능 구현 (1) - 구글 개발자 콘솔 프로젝트
다음글 : 안드로이드 푸시 기능 구현 (3) - Nodejs 푸시 서버
-----------------------------------------------------------
읽어 주셔서 감사합니다.
최근에 구현하기 좁더 쉽게 바뀐것 같습니다.
아래의 링크는 푸시 관련 하여 새로 작성한 포스팅입니다.
변경된 GCM에 대해 조금은 도움이 될것 같습니다.
[Android GCM] 3. C언어로 GCM 메시지를 보내자!
'Android' 카테고리의 다른 글
안드로이드 푸시 기능 구현 (4) - 결과 (0) | 2015.01.16 |
---|---|
안드로이드 푸시 기능 구현 (3) - Nodejs 푸시 서버 (0) | 2015.01.14 |
안드로이드 푸시 기능 구현 (1) - 구글 개발자 콘솔 프로젝트 생성 (0) | 2015.01.09 |
[Android] SQLite 쿼리 (0) | 2014.12.18 |
[Android] SharedPreference의 활용 (0) | 2014.12.13 |
댓글