N0guch1.GitHub.io


home > GCMのPush通知を使ってみた Project maintained. GitHub Pages — by n0guch1

GCMのPush通知を使ってみた


〜Push通知とは〜

公式
GCMのサンプルアプリ
端末の通知エリアにアプリからメッセージを飛ばす機能の事です。
代表的なものを言うとLineなどに使われています。
ちなみにアプリ内のみ(通信しない)でNotificationを実行しているのはローカル通知と言います。
もちろんローカル通知なのでユーザー間のやり取りは出来ないです。アプリから定期的なお知らせを出す時などに使います。
ここで言うPush通知はGCMのサーバーを使って送信するリモート通知の事を言います。

〜Push通知の流れ〜

ざっくりGCMのPush通知の流れを書くと以下のような感じになります。

  1. アプリ : 端末をGCMに登録する。RegistrationTokenを取得するためリクエストを送信。
  2. GCMサーバー : 登録成功後、端末固有のIDをアプリに送信
  3. アプリ : 取得した端末IDを自サーバーにリクエストを送信。必要であればPush情報も一緒に送信
  4. 自サーバー : 端末IDを元にPush情報をGCMサーバーにリクエスト送信
  5. GCMサーバー : 端末IDに向けて受け取ったPush情報を送信
  6. アプリ : GCMサーバーからPush情報を受信。通知エリアにその情報を元に表示させる

〜1,2実装(RegistrationTokenの取得)〜

公式の通りAndroidManifest.xmlにpermissionを追記。 ※受信部分の物もそのまま追記しています
「com.example.gcm」の部分は自分のアプリのパッケージ名に変更します。

<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.gcm.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
<uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />

次にトークン取得メソッドを作成。
getTokenメソッドを使用します。
トークンの取得はメインスレッドでは出来ないので非同期で取得します。

public void getRegistrationToken(String senderId, NCMBRegistrationCallback callback) {
    new AsyncTask<String, Void, Void>() {
        @Override
        protected Void doInBackground(String... params) {
            try {
                InstanceID instanceID = InstanceID.getInstance(NCMB.sCurrentContext.context);
                String token = instanceID.getToken(params[0], GoogleCloudMessaging.INSTANCE_ID_SCOPE);
                Log.d("tag","token:"+token);
            } catch (IOException error) {
                Log.d("tag","error:"+error);
            }
            return null;
        }
    }.execute(senderId, null, null);
}

これでGCMに端末の登録とトークンの取得は完了です。

※おまけ
GooglePlay開発者サービスが端末にインストールされてないとそもそも動かないので、
そのチェックメソッドを追加します。公式推奨でonCreateメソッドで呼び出します。


/**
 * 端末にGooglePlay開発者サービスがインストールされているか確認
 * インストールされていな場合はPlayストアへのダイアログを表示
 */
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(TAG, "This device is not supported.");
            finish();
        }
        return false;
    }
    return true;
}

〜3,4,5実装(自サーバー経由でGCMサーバーに通知をコール)〜

この部分は自サーバが必要なため割愛します。
自力でサーバーを立てられない人はmBaaSなどでPush通知に対応したサーバーを借りると楽です。

〜6実装(Push通知の受信/表示)〜

受信クラスの作成とAndroidManifestにreceiverの登録をします。

まずAndroidManifest.xmlのタグ内に以下を記載します。
「com.example.gcm」の部分は自分のアプリのパッケージ名に変更します。


<receiver
    android:name="com.google.android.gms.gcm.GcmReceiver"
    android:exported="true"
    android:permission="com.google.android.c2dm.permission.SEND" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <category android:name="com.example.gcm" />
    </intent-filter>
</receiver>
<service
    android:name="com.nifty.cloud.mb.core.NCMBGcmListenerService"
    android:exported="false" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>

次に以下のクラスを作成します。
受信クラスにはGcmListenerServiceを継承させます。※公式推奨

package com.example.gcm;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.google.android.gms.gcm.GcmListenerService;

public class MylistenerService extends GcmListenerService {

    //GCMからの通知を受信
    @Override
    public void onMessageReceived(String from, Bundle data) {
        String message = data.getString("message");
        Log.d("tag", "受信 From: " + from);
        Log.d("tag", "受信 Message: " + message);

        sendNotification(message);
    }

    //通知エリアにNotificationを表示
    private void sendNotification(String message) {

        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 , intent,
                PendingIntent.FLAG_ONE_SHOT);

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_ic_notification)
                .setContentTitle("GCM Message")
                .setContentText(message)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 , notificationBuilder.build());
    }
}

後はGCMからメッセージが送られた場合にonMessageReceivedメソッドが受信を行います。
そしてsendNotificationメソッドでその通知情報を元に通知エリアにNotificationを表示します。