blog.petitviolet.net

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