Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
16
Help us understand the problem. What is going on with this article?

More than 5 years have passed since last update.

@petitviolet

PythonからGoogleのAPIを利用してAndroidへPUSH通知する

GoogleのAPIを用いてAndroid端末へのPUSHとステータスバーへの通知の表示メモ

クライアント(Android)

AndroidでPUSH通知をするための準備はhttp://dev.classmethod.jp/smartphone/android/gcm/に書いてあります。
本当に参考になりました。

ここからは上のリンクからの変更点と追加点についてです。

-
Google Developers Consoleでの手順が多少変わっているので、そこについて説明します。

まず、https://console.developers.google.com/projectにアクセスし、既存のprojectか"CREATE PROJECT"を選択します。

projectを作成or選択してprojectのページを開きます。
ページ上部の"Project Number"は控えておきましょう。
そして、左側のサイドメニューの"APIs & auth" > "APIs" から"Google Cloud Messaging for Android"のSTATUSをONにします。
なお、公式のドキュメントはここです。

次に、"APIs & auth" > "Credentials"で"Public API access"の"CREATE NEW KEY"を選択し、新しくAPI keyを取得します。
表示されるダイアログでは"Server Key"を選択し、IPアドレスは0.0.0.0を入力します。
ここは必要があれば変更しましょう。
テスト用であれば0.0.0.0で問題ありません。多分。

-
GcmBroadcastReceiver.javaは上のリンクのものをそのまま利用させてもらいます。
次に、GcmIntentService.javaを通知のために書き換えます。

GcmIntentService.java
public class GcmIntentService extends IntentService {
    private static final String TAG = GcmIntentService.class.getSimpleName();
    private Notification notification;
    private NotificationManager nm;

    public GcmIntentService() {
        super("GcmIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.v(TAG, "onHandleIntent");
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        String messageType = gcm.getMessageType(intent);

        if (!extras.isEmpty()) {
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
                Log.d(TAG, "messageType: " + messageType + ",body:" + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
                Log.d(TAG,"messageType: " + messageType + ",body:" + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                Log.d(TAG,"messageType: " + messageType + ",body:" + extras.toString());
            }
        }

        // ここまでhttp://dev.classmethod.jp/smartphone/android/gcm/のものとほぼ同じ
        // extrasに、サーバーからのdataが入っている
        // ここでは、すべて文字列として格納してある
        Log.v(TAG, extras.toString());
        int userId = Integer.parseInt(extras.getString("user_id"));
        String text = extras.getString("text");

        // 通知を開くとMainActivityが表示されるようにする
        Intent i = new Intent(getApplicationContext(), MainActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
        i.setType("notification");
        i.putExtra("user_id", userId);
        i.putExtra("text", text);

        // 第4引数を0にすると、Intentのextrasだけ更新されず、通知のテキストは違うのにextrasだけ同じなため、
        // Intent先のMainActivityでextrasを取得すると同じ値しかとれなくなる事態に
        PendingIntent pi = PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);

        Notification.Builder notificationBuilder =
                new Notification.Builder(getApplicationContext())
                        .setContentIntent(pi)
                        .setSmallIcon(R.drawable.icon_small)
                        .setTicker("通知がきました")  // 通知が来た時にステータスバーに表示されるテキスト
                        .setContentTitle("通知のタイトル")  // 通知バーを開いた時に表示されるタイトル
                        .setContentText("通知のテキスト") // タイトルの下に表示されるテキスト
                        .setWhen(System.currentTimeMillis());  // 通知が表示されるタイミング?

        long[] vibrate_ptn = {0, 100, 300, 1000}; // 振動パターン(適当)
        notification = notificationBuilder.build();
        notification.vibrate = vibrate_ptn;
        notification.defaults |= Notification.DEFAULT_LIGHTS; // デフォルトLED点滅パターンを設定
        notification.flags = Notification.FLAG_ONGOING_EVENT;

        // NotificationManagerのインスタンス取得
        nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        nm.notify(R.string.app_name, notification); // 設定したNotificationを通知する
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        nm.cancel(R.string.app_name);
    }
}

続いて通知をタップした時の動作として起動されるMainActivityです。
大体上のリンクのものでいいですが、onCreateに以下のコードを追加します。


MainActivity.java
// notification表示関係
Intent intent = getIntent();
String intentType = intent.getType();
if (intentType != null && intentType.equals("notification")) {
    Log.v(TAG + " extras", intent.getExtras().toString());
    // extrasからGcmIntentService.javaでいれたデータを取り出す
    int user_id = intent.getIntExtra("user_id", 0);
    String text = intent.getStringExtra("text");

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

    // ダイアログの表示
    Toast.makeText(this, text, Toast.LENGTH_LONG);
}

registerInBackground()によってLog catにregistrationIdが表示されるので、これを控えます。
アプリケーションとして実装するなら、このIDをサーバーに渡して保存するようにします。

サーバー(Python)

pythonからはrequestsを利用してGoogleへリクエストを送ります。

api.py
import requests
import json

def push_notificate(user_id, text):
    '''エラーが出るとrにエラーメッセージが入る
    これを呼び出せばAndroidに通知が行く
    '''
    gcm_url = 'https://android.googleapis.com/gcm/send'

    # 上で控えたregistrationIdとAPI key
    regid = REGID
    key = "key=" + APIKEY

    headers = {'content-type': 'application/json', 'Authorization': key}
    # 渡すデータは適当です。
    # dictのkeyはAndroidのextrasのkeyと合わせましょう
    params = json.dumps(\
            {'registration_ids': [regid], \
            'data': {'id': user_id, 'text': text}})

    r = requests.post(gcm_url, data=params, headers=headers)
    print r.text
    return

requestsでbasic認証をクリアするには引数にauth=(username, password)を渡しますが、今回はheadersに入れて渡します。

これで大丈夫だと思います。

16
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
16
Help us understand the problem. What is going on with this article?