petitviolet blog

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

    2014-03-08

    QiitaPythonAndroid

    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 に入れて渡します。

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

    from: https://qiita.com/petitviolet/items/4dd5cc8f7dd6d1f22933