Android Studio에서는 이렇게 해야한다.
Google Play Service 연결하기
- 이클립스 – Windows – Android SDK Manager 를 연다.
- 목록의 제일 아래쪽에 Goole Play Services 선택한다.
- 오른쪽 아래의 Install 버튼을 누른다.
- 설치가 끝나면 이클립스의 프로젝트 목록에서 오른쪽 클릭해서 import 메뉴를 선택하고,{sdk}/extras/google/google_play_services/ 를 선택한다.
- 작성할 프로젝트의 오른쪽 클릭 메뉴 – properties – Android – Library – Add… 버튼을 누른다.
- google-play-services_lib 를 선택한다.
Manifest 편집
kr.mint.testgcm 이라고 적힌 부분은 실제 패키지 경로로 바꿔야 함.
<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" /> <uses-permission android:name="android.permission.VIBRATE" /> <permission android:name="kr.mint.testgcm.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="kr.mint.testgcm.permission.C2D_MESSAGE" />
<activity android:name=".MainActivity" android:launchMode="singleTask" // notification bar에서 클릭할 때를 위해 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=".receiver.GcmBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" > <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <category android:name="kr.mint.testgcm" /> </intent-filter> </receiver> <service android:name=".GcmIntentService" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
MainActivity 편집
http://developer.android.com/google/gcm/client.html#sample-register 의 소스를 살짝 바꿨다.
public class MainActivity extends Activity { private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000; private static final String SENDER_ID = "388136674604"; private GoogleCloudMessaging _gcm; private String _regId; private TextView _textStatus; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); _textStatus = (TextView) findViewById(R.id.textView1); // google play service가 사용가능한가 if (checkPlayServices()) { _gcm = GoogleCloudMessaging.getInstance(this); _regId = getRegistrationId(); if (TextUtils.isEmpty(_regId)) registerInBackground(); } else { Log.i("MainActivity.java | onCreate", "|No valid Google Play Services APK found.|"); _textStatus.append("\n No valid Google Play Services APK found.\n"); } // display received msg String msg = getIntent().getStringExtra("msg"); if (!TextUtils.isEmpty(msg)) _textStatus.append("\n" + msg + "\n"); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // display received msg String msg = intent.getStringExtra("msg"); Log.i("MainActivity.java | onNewIntent", "|" + msg + "|"); if (!TextUtils.isEmpty(msg)) _textStatus.append("\n" + msg + "\n"); } // google play service가 사용가능한가 private boolean checkPlayServices() { int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (resultCode != ConnectionResult.SUCCESS) { if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { GooglePlayServicesUtil.getErrorDialog(resultCode, this, PLAY_SERVICES_RESOLUTION_REQUEST).show(); } else { Log.i("MainActivity.java | checkPlayService", "|This device is not supported.|"); _textStatus.append("\n This device is not supported.\n"); finish(); } return false; } return true; } // registration id를 가져온다. private String getRegistrationId() { String registrationId = PreferenceUtil.instance(getApplicationContext()).regId(); if (TextUtils.isEmpty(registrationId)) { Log.i("MainActivity.java | getRegistrationId", "|Registration not found.|"); _textStatus.append("\n Registration not found.\n"); return ""; } int registeredVersion = PreferenceUtil.instance(getApplicationContext()).appVersion(); int currentVersion = getAppVersion(); if (registeredVersion != currentVersion) { Log.i("MainActivity.java | getRegistrationId", "|App version changed.|"); _textStatus.append("\n App version changed.\n"); return ""; } return registrationId; } // app version을 가져온다. 뭐에 쓰는건지는 모르겠다. private int getAppVersion() { try { PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0); return packageInfo.versionCode; } catch (NameNotFoundException e) { // should never happen throw new RuntimeException("Could not get package name: " + e); } } // gcm 서버에 접속해서 registration id를 발급받는다. private void registerInBackground() { new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params) { String msg = ""; try { if (_gcm == null) { _gcm = GoogleCloudMessaging.getInstance(getApplicationContext()); } _regId = _gcm.register(SENDER_ID); msg = "Device registered, registration ID=" + _regId; // For this demo: we don't need to send it because the device // will send upstream messages to a server that echo back the // message using the 'from' address in the message. // Persist the regID - no need to register again. storeRegistrationId(_regId); } catch (IOException ex) { msg = "Error :" + ex.getMessage(); // If there is an error, don't just keep trying to register. // Require the user to click a button again, or perform // exponential back-off. } return msg; } @Override protected void onPostExecute(String msg) { Log.i("MainActivity.java | onPostExecute", "|" + msg + "|"); _textStatus.append(msg); } }.execute(null, null, null); } // registraion id를 preference에 저장한다. private void storeRegistrationId(String regId) { int appVersion = getAppVersion(); Log.i("MainActivity.java | storeRegistrationId", "|" + "Saving regId on app version " + appVersion + "|"); PreferenceUtil.instance(getApplicationContext()).putRedId(regId); PreferenceUtil.instance(getApplicationContext()).putAppVersion(appVersion); } }
Received Message
예전에는 브로드캐스트 리시버에서 다 했던 것 같은데, 구글에서 가이드 해줬으니 그거 따라해야지….
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.i("GcmBroadcastReceiver.java | onReceive", "|" + "================="+"|"); Bundle bundle = intent.getExtras(); for (String key : bundle.keySet()) { Object value = bundle.get(key); Log.i("GcmBroadcastReceiver.java | onReceive", "|" + String.format("%s : %s (%s)", key, value.toString(), value.getClass().getName()) + "|"); } Log.i("GcmBroadcastReceiver.java | onReceive", "|" + "================="+"|"); // Explicitly specify that GcmIntentService will handle the intent. ComponentName comp = new ComponentName(context.getPackageName(), GcmIntentService.class.getName()); // Start the service, keeping the device awake while it is launching. startWakefulService(context, intent.setComponent(comp)); setResultCode(Activity.RESULT_OK); } }
Show in Notification bar
노티바에 표시하면서 0.5초 동안 진동하고, 클릭하면 메인화면으로 가는 거 추가
public class GcmIntentService extends IntentService { public static final int NOTIFICATION_ID = 1; public GcmIntentService() { super("GcmIntentService"); } @Override protected void onHandleIntent(Intent intent) { Bundle extras = intent.getExtras(); GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); // The getMessageType() intent parameter must be the intent you received // in your BroadcastReceiver. String messageType = gcm.getMessageType(intent); if (!extras.isEmpty()) { // has effect of unparcelling Bundle /* * Filter messages based on message type. Since it is likely that GCM * will be extended in the future with new message types, just ignore * any message types you're not interested in, or that you don't * recognize. */ if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) { sendNotification("Send error: " + extras.toString()); } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) { sendNotification("Deleted messages on server: " + extras.toString()); // If it's a regular GCM message, do some work. } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) { String msg = intent.getStringExtra("msg"); // Post notification of received message. // sendNotification("Received: " + extras.toString()); sendNotification("Received: " + msg); Log.i("GcmIntentService.java | onHandleIntent", "Received: " + extras.toString()); } } // Release the wake lock provided by the WakefulBroadcastReceiver. GcmBroadcastReceiver.completeWakefulIntent(intent); } // Put the message into a notification and post it. // This is just one simple example of what you might choose to do with // a GCM message. private void sendNotification(String msg) { NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); Intent intent = new Intent(getApplicationContext(), MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra("msg", msg); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_launcher) .setContentTitle("GCM Notification") .setStyle(new NotificationCompat.BigTextStyle().bigText(msg)) .setContentText(msg) .setAutoCancel(true) .setVibrate(new long[] { 0, 500 }); mBuilder.setContentIntent(contentIntent); mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build()); } }
Preference
그냥 구글 소스대로 해놓고 글 작성할 걸 괜히 리팩토링해가지고 불편하게 됐네 ;;;
public class BasePreferenceUtil { private SharedPreferences _sharedPreferences; protected BasePreferenceUtil(Context $context) { super(); _sharedPreferences = PreferenceManager.getDefaultSharedPreferences($context); } /** * key 수동 설정 * * @param key * 키 값 * @param value * 내용 */ protected void put(String $key, String $value) { SharedPreferences.Editor editor = _sharedPreferences.edit(); editor.putString($key, $value); editor.commit(); } /** * String 값 가져오기 * * @param key * 키 값 * @return String (기본값 null) */ protected String get(String $key) { return _sharedPreferences.getString($key, null); } /** * key 설정 * * @param key * 키 값 * @param value * 내용 */ protected void put(String $key, boolean $value) { SharedPreferences.Editor editor = _sharedPreferences.edit(); editor.putBoolean($key, $value); editor.commit(); } /** * Boolean 값 가져오기 * * @param key * 키 값 * @param defValue * 기본값 * @return Boolean */ protected boolean get(String $key, boolean $default) { return _sharedPreferences.getBoolean($key, $default); } /** * key 설정 * * @param key * 키 값 * @param value * 내용 */ protected void put(String $key, int $value) { SharedPreferences.Editor editor = _sharedPreferences.edit(); editor.putInt($key, $value); editor.commit(); } /** * int 값 가져오기 * * @param key * 키 값 * @param defValue * 기본값 * @return int */ protected int get(String $key, int $default) { return _sharedPreferences.getInt($key, $default); } }
public class PreferenceUtil extends BasePreferenceUtil { private static PreferenceUtil _instance = null; private static final String PROPERTY_REG_ID = "registration_id"; private static final String PROPERTY_APP_VERSION = "appVersion"; public static synchronized PreferenceUtil instance(Context $context) { if (_instance == null) _instance = new PreferenceUtil($context); return _instance; } protected PreferenceUtil(Context $context) { super($context); } public void putRedId(String $regId) { put(PROPERTY_REG_ID, $regId); } public String regId() { return get(PROPERTY_REG_ID); } public void putAppVersion(int $appVersion) { put(PROPERTY_APP_VERSION, $appVersion); } public int appVersion() { return get(PROPERTY_APP_VERSION, Integer.MIN_VALUE); } }
Registration ID 복사해두기
정상적으로 등록이 됐다면 logcat 에 RegID가 나올텐데, 이걸 복사해뒀다가 송신 서버 만들 때 쓰자.
Error – SERVICE_NOT_AVAILABLE
도움받은 곳 : http://aroundck.tistory.com/2353
java.io.IOException: SERVICE_NOT_AVAILABLE at com.google.android.gms.gcm.GoogleCloudMessaging.register(Unknown Source) at com.mintshop.candibox.activities.MainActivity$3.doInBackground(MainActivity.java:151) at com.mintshop.candibox.activities.MainActivity$3.doInBackground(MainActivity.java:1) at android.os.AsyncTask$2.call(AsyncTask.java:288) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
이런 에러가 나오면 다른 방법으로 regId를 받아와야한다.
<receiver android:name=".receiver.GcmBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" > <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> <!-- add this line --> <category android:name="kr.susemi99.testgcm" /> </intent-filter> </receiver>
menifest.xml 에 저 부분을 추가하면 broadcast receiver에서 regId를 받아올 수 있다.
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.i("GcmBroadcastReceiver.java | onReceive", "|" + "=================" + "|"); Bundle bundle = intent.getExtras(); for (String key : bundle.keySet()) { Object value = bundle.get(key); Log.i("GcmBroadcastReceiver.java | onReceive", "|" + String.format("%s : %s (%s)", key, value.toString(), value.getClass().getName()) + "|"); if (key.equalsIgnoreCase("registration_id")) { String regId = bundle.getString(key); PreferenceUtil.instance(context).putRedId(regId); } } Log.i("GcmBroadcastReceiver.java | onReceive", "|" + "=================" + "|"); // Explicitly specify that GcmIntentService will handle the intent. ComponentName comp = new ComponentName(context.getPackageName(), GcmIntentService.class.getName()); // Start the service, keeping the device awake while it is launching. startWakefulService(context, intent.setComponent(comp)); setResultCode(Activity.RESULT_OK); } }
preference에 저장하는 부분을 여기서 하면 된다.