Skip to content

Google Cloud Messaging

GCM(Google 클라우드 메시징)은 개발자가 서버에서 자신의 Android 애플리케이션으로 데이터를 전송하게 해주는 무료 서비스입니다. 서버에서 가져와야할 새로운 데이터(예: 친구가 업로드한 영화)가 있음을 Android 애플리케이션에 알리는 적은 용량의 메시지이거나, 최대 4KB의 페이로드 데이터를 포함하는 메시지일 수 있습니다. 따라서 메신저와 같은 앱은 메시지를 직접 사용할 수 있습니다.

GCM Android jar file path:

${ANDROID_HOME}/extras/google/gcm/gcm-client/dist/gcm.jar

Google Developers Console

Architecture

Sample_init_gcm.jpg

Client setting

GCM을 사용하기 위한 클라이언트(안드로이드) 설정 방법을 정리한다.

AndroidManifest.xml setting

중요한 점은 "my.project.package"부분을 자신을 프로젝트 패키지명으로 변경해야 한다.

<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="my.project.package.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />

<uses-permission android:name="my.project.package.permission.C2D_MESSAGE" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

    <receiver
        android:name="com.google.android.gcm.GCMBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>

            <!-- Receives the actual messages. -->
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <!-- Receives the registration id. -->
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

            <!-- 젤리빈 부터는 category가 없어도 된다. -->
            <category android:name="my.project.package" />
        </intent-filter>
    </receiver>

    <service android:name=".GCMIntentService" />
  ...
</application>

참고로 Gradle을 사용할 경우 아래와 같이 설정하면 된다.

dependencies {
    compile 'com.google.android.gms:play-services-base:+'
    compile 'com.google.android.gms:play-services-gcm:+'
    compile 'com.google.android.gms:play-services:+'

    compile files('libs/gcm-server.jar')
    compile files('libs/gcm.jar')
}

MainActivity.java

첫 번째 시작되는 Activity(MainActivity)의 onCreate()에 아래와 같이 GCM을 등록한다.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // ...

    GCMRegistrar.checkDevice(this);
    GCMRegistrar.checkManifest(this);

    final String regId = GCMRegistrar.getRegistrationId(this);
    if (regId == null || regId.length() == 0) {
        // 정상적으로 등록될 경우 GCMIntentService.onRegistered()로 Event가 Callback된다.
        GCMRegistrar.register(this, "85810567300");
    }

    Log.d(TAG, "GCM Register" + regId);
}

GCMIntentService.java

GCMBaseIntentService를 상속받는 서비스를 구현해야 한다. AndroidManifest에 등록된 서비스 클래스 명칭과 동일해야 한다. 가급적 GCMIntentService을 고정하여 사용하도록 하자.

public class GCMIntentService extends GCMBaseIntentService {

    private static final String TAG = GCMIntentService.class.toString();
    private static final String PROJECT_ID = "my-project-id"; // 등록된 프로젝트 ID로 적용한다.

    // public 기본 생성자를 무조건 만들어야 한다.
    public GCMIntentService() {
        this(PROJECT_ID);
    }

    public GCMIntentService(String project_id) {
        super(project_id);
    }

    /** 에러 발생 */
    @Override
    protected void onError(Context arg0, String arg1) {
        Log.e(TAG, "onError: " + arg1);
    }

    /** 푸시 메세지 획득. */
    @Override
    protected void onMessage(Context arg0, Intent arg1) {
        Bundle b = arg1.getExtras();

        Iterator<String> iterator = b.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = b.get(key).toString();
            Log.d(TAG, "onMessage. " + key + " : " + value);
        }
    }

    /** 단말에서 GCM 서비스 등록 했을 때 등록 id를 받는다 */
    @Override
    protected void onRegistered(Context arg0, String arg1) {
        Log.e(TAG, "onRegistered: " + arg1);
    }

    /** 단말에서 GCM 서비스 등록 해지를 하면 해지된 등록 id를 받는다 */
    @Override
    protected void onUnregistered(Context arg0, String arg1) {
        Log.e(TAG, "onUnregistered: " + arg1);
    }
}

Troubleshooting

GCM과 관련된 문제점 및 해결 방법에 대하여 정리한다.

No receivers for action com.google.android.c2dm.intent.REGISTRATION

No receivers for action com.google.android.c2dm.intent.REGISTRATION 에러 메세지가 출력될 경우 receiverintent-filter에 아래와 같이 action을 추가하면 된다.

<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />

GcmBroadcastReceiver Class Not Found Exception

java.lang.ClassNotFoundException: com.google.android.gcm.GcmBroadcastReceiver 에러 메세지가 출력될 경우 android-suppert-v4.jar를 업데이트하거나 receiverandroid:name속성에 Package 전체 경로를 적어놓도록 한다.

<receiver
    android:name="com.google.android.gcm.GCMBroadcastReceiver"
    android:permission="com.google.android.c2dm.permission.SEND" >
  ....
</receiver>

혹시 앱이 죽지 않지만 로그캣에 IntentReceiver com.google.android.gcm.GCMBroadcastReceiver@40233b88 that was originally registered here. Are you missing a call to unregisterReceiver()?와 같은 에러 로그가 출력된다면 GCM서비스 등록 코드를 자신의 앱 application 클래스의 onCreate()로 옮겨주면 된다.

Cannot resolve symbol GCM

정리하면, GCMBaseIntentService는 obsolete되어있다. Android SDK Manager에서 하단의 Obsolete 라디오 버튼을 클릭하면 Extras에 아래 이름의 패키지가 출력된다.

Google Cloud Messaging for Android Library (Obsolete)

Libraries

See also

Favorite site

Guide

Tutorial

References


  1. JAVA_-_GCM_and_APNS.pdf 

  2. Android_use_gcm1.pdf 

  3. Android_use_gcm2.pdf 

  4. Android_use_gcm3.pdf