Androidアプリのプッシュ通知対応の要点 - APIキー取得から動作確認まで

R&D部の佐藤伸です。

先日、開発中のAndroidアプリでプッシュ通知機能に対応したのですが、このときに必要な「APIキー」の取得と設定の方法がわかりにくく、とても苦労しました。

Androidのプッシュ通知の仕様は過去に二度、大きく変更されているため、ネット上で検索しても新しい情報がなかなか見つからず、これも苦労した理由の一つでした。

そこで今回の記事では、この「APIキー」の取得手順、および実際にAndroidアプリに組み込んでプッシュ通知を受信できるようにするまでの一連の手順をご紹介します。
スマホアプリのプッシュ通知対応を検討されている開発者の皆様のお役に立てればと思います。

  • この記事は、2016年5月上旬時点のGoogle Developers Console の仕様を元に解説しています。今後、Googleによって仕様が変更される可能性があることをあらかじめご了承ください。
【2016年8月2日 追記】
プッシュ通知の仕組みが変更となったため、現在は本エントリーの方法ではプッシュ通知が行えなくなっています。

プッシュ通知の仕組み

スマホのメールやSNSなどのアプリは、端末使用者やアプリが自ら能動的に更新確認をしなくても、常に最新情報をサーバーから取得・表示できます。これは、情報に更新があったことをサーバーから端末へ「通知」してくれる仕組みを利用しているからです。この仕組みが「プッシュ通知」です。

送信者(アプリのサービス運用者)は、「Google Cloud Messaging (GCM)」というGoogle社のサービスを利用することで、世界中の端末にインストールされている自分のアプリ宛に通知メッセージを送信することができるようになっています。

* GCMを使ったプッシュ通知はiOSアプリでも利用可能ですが、今回の記事では割愛します。

スマホアプリでプッシュ通知を実現するためにはまず、下記の準備が必要となります。

  • GCMを利用するための「APIキー」を取得する
  • アプリで、プッシュ通知の「通知メッセージ」の受信と、インストールされた端末の「識別トークン」の送信に対応する
  • インストールされたアプリから端末毎に送られてくる「識別トークン」を受信し、データベースなどへ蓄積・管理する「トークン管理サーバー」を用意する
  • トークン管理サーバー」のデータベースに蓄積された「識別トークン」を用い、通知メッセージの送信をGCMへ依頼するための「通知送信ツール」を用意する

実際の処理の流れは下記のようになります。

  1. 端末にインストールされたアプリは、「識別トークン」を「トークン管理サーバー」へ送信する。
    * 識別トークンは端末再起動などで不定期に変わることがあるので、その都度、再送信する必要があります。
  2. 「トークン管理サーバー」は受信した「識別トークン」をデータベースなどへ保存する。
  3. 送信者は、プッシュ通知を行いたいタイミングで、通知相手の「識別トークン一覧」と「通知メッセージ」を用意し、これらを「通知送信ツール」を用いてGCMに送信する。このときに「APIキー」が必要となる。
  4. GCMは、受け取った「識別トークン一覧」のすべての端末へ「通知メッセージ」を一斉に送信する。
  5. 各端末のスマホアプリが「通知メッセージ」を受信し、その内容に応じて、画面の更新や通知バーへの表示などを行う。

今回は説明を簡略化するため、「トークン管理サーバー」部分は割愛します。アプリ開発者が既に端末の「識別トークン」を知っていることを前提とし、実際にGCMを利用してスマホアプリでプッシュ通知の受信をしてみます。

 

GCMの利用開始(APIキーの取得)手順

前述のように、プッシュ通知にはGCMが必要となります。また、GCMを利用するためにはGoogleのウェブサイトで「APIキー」を取得する必要があります。
この方法が意外とわかりにくいので、以下に画面キャプチャを交えて手順を説明します。

【1】まず、Google Developers Console へ、開発者用アカウントでログインします。ログインすると Google API 一覧画面が開きます。

push02

【2】ここで「Google Cloud Messaging」のリンクをクリックします。

push33

【3】「Google Cloud Messaging」の下にある「詳細」のリンクをクリックすると、Cloud Messaging のページに飛びます。

push15

「Simple and reliable messaging to reach over a billion devices.」素敵な響きです。

【4】「TRY IT ON ANDROID」ボタンを押します。

push16

ここでサンプルのプロジェクトも入手できますが、今回の解説では自前で用意してみました。もちろん、このページにあるサンプルを使用しても構いません。

【5】次に、「2. Get a configuration file」の説明の下の方にある「GET A CONFIGURATION FILE」ボタンを押します。

push34

「App name」と「Android package name」の入力が必要です。実際にプッシュ通知対応するアプリのアプリ名とパッケージ名を指定してください。
ここでは App name は「PushTestApp」、Android package name は「jp.co.webtech.pushtestapp」としました。

【6】「CONTINUE TO Choose and configure services」ボタンを押して先に進みます。

push35

「You are configuring the PushTestApp app with package name jp.co.webtech.pushtestapp.」
と表示されれば、手続きは完了です。

【7】続いて、「ENABLE GOOGLE CLOUD MESSAGING」ボタンを押してGoogle Cloud Messaging サービスを有効にしましょう。

push36

Cloud Messaging が有効になり、「Server API Key」と「Sender ID」が発行されました。これが、アプリのプッシュ通知対応に必須となる文字列です。

なお、このKeyとIDは、発行しなおすたびに変わってしまうので注意してください。

GCMの利用に必要となる「APIキー」の取得手順はこれで完了です。お疲れ様でした。

 

Androidアプリのプッシュ通知対応手順

では次に、Androidアプリでプッシュ通知の受信に対応してみましょう。開発環境にはAndroid Studio を使用します。

 

まず、Android Studio で新規プロジェクトを作成します。

APIキーを取得したときに指定したアプリ名とパッケージ名に合わせる必要があるので注意してください。

Application nameを「PushTestApp」、Company Domainを「webtech.co.jp」にしています。

push21

 

クラスを3つ追加します。

まず、識別トークンを取得するクラスです。

SENDER_ID に先ほど入手した Sender ID を指定します。

MyGcmIntentService.java:

package jp.co.webtech.pushtestapp;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.google.android.gms.iid.InstanceID;

/**
 * 非同期で識別トークンを取得する
 */
public class MyGcmIntentService extends IntentService {

    public static final String TAG = MyGcmIntentService.class.getSimpleName();

    public static final String SENDER_ID = "470359069872";

    public MyGcmIntentService() {
        super("MyGcmIntentService service");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        try {
            InstanceID instanceID = InstanceID.getInstance(this);
            //GCM Registration Token取得
            String token = instanceID.getToken(SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
            Log.i(TAG, "GCM Registration Token: " + token);
        } catch (Exception e) {
            Log.e(TAG, "exception " + e.getMessage());
        }
    }
}

次に、プッシュ通知を受け取るクラスです。

MyGcmListenerService.java:

package jp.co.webtech.pushtestapp;

import android.os.Bundle;
import android.util.Log;

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

/**
 * プッシュ通知受け取り
 */
public class MyGcmListenerService extends GcmListenerService {
    public static final String TAG = MyGcmIntentService.class.getSimpleName();

    @Override
    public void onMessageReceived(String from, Bundle data) {
        super.onMessageReceived(from, data);
        // 送信元プロジェクト番号
        Log.v(TAG, "from=" + from);
        // 送信されたメッセージ
        Log.v(TAG, "message=" + data.get("message"));
    }
}

最後に、識別トークンが更新されたことを検知するためのクラスです。

識別トークンは端末の再起動などで不定期に更新されることがあるので、その場合は取得しなおし、必要であれば「認証キー管理サーバー」へ送信する必要があります。

MyInstanceIDListenerService.java

package jp.co.webtech.pushtestapp;

import android.content.Intent;

import com.google.android.gms.iid.InstanceIDListenerService;

/**
 * 識別トークンが更新された
 */
public class MyInstanceIDListenerService extends InstanceIDListenerService {
    @Override
    public void onTokenRefresh() {
        super.onTokenRefresh();
        // 識別トークンを取得しなおす
        Intent intent = new Intent(this, MyGcmIntentService.class);
        startService(intent);
    }
}

 

build.gradle を編集します。

クラスを3つ追加したら、続いて build.gradle の dependencies に「compile ‘com.google.android.gms:play-services:8.4.0’」を追加します。

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.google.android.gms:play-services:8.4.0'    ←追加
}

 

AndroidManifest.xml を編集します。

AndroidManifest.xml にパーミッション、サービス、レシーバを追加します。

コメントの”↓↓↓”から”↑↑↑”の部分が追加した部分になります。もちろんアプリのパッケージ名とクラス名は適宜置き換えてください。

<?xml version="1.0" encoding="utf-8"?>
<manifest package="jp.co.webtech.pushtestapp"
          xmlns:android="http://schemas.android.com/apk/res/android">

<!-- ↓↓↓パーミッション -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- ↑↑↑-->

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

    <!-- ↓↓↓サービス、レシーバ-->
    <service android:name=".MyGcmIntentService"/>
    <service
        android:name=".MyGcmListenerService"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>
    <service
        android:name=".MyInstanceIDListenerService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID"/>
        </intent-filter>
    </service>

    <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="jp.co.webtech.pushtestapp" />
        </intent-filter>
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="jp.co.webtech.pushtestapp" />
        </intent-filter>
    </receiver>
    <!-- ↑↑↑-->

    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>

            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
</application>

</manifest>

 

では、作成したアプリケーションを実行してみてください。

logcatを確認すると、下記のように IntentService でバックグラウンドで実行されて取得された識別トークン(Registration Token)がログに出力されます。

03-31 09:24:00.047 3721-3816/jp.co.webtech.pushtestapp I/MyGcmIntentService: GCM Registration Token: cfF7YmCvVrU:APA91bHqvpto7rfdHxi4b5Vizm1MKFWXL2avZ5suOjcCVQuLzCoRjc79ehjVUm2syaz9RbWG7mhcopAJC0TZk21YXmA-rgg6x9QTiESzcPbJhqUZLMCjHlk_iYiBIpMv8SLKsnNzyoRU

出力された “Registration Token :” 以降の文字列をコピーして控えておいてください。

識別トークンは環境ごとに異なるものになります。プッシュ通知では、この識別トークンを使って、通知メッセージの送信先端末を区別しています。実際の運用時には、識別トークンは「識別トークン管理サーバー」を用意してアプリから受信し、管理することになります。

それでは続いて、この識別トークンの端末に、プッシュ通知で通知メッセージを送ってみましょう。

 

プッシュ通知の送信

では、「通知送信ツール」を使ってプッシュ通知をしてみましょう。

ここで言う「通知送信ツール」というのは、GCMへの通知依頼を実現できればどのようなものでも構いません。

まずは例として、Linux のコマンドラインから “curl” コマンドを使い、GCMへプッシュ通知を依頼する手順を紹介します。

* “curl” コマンドはWindows環境でもインストールすれば使えます。興味ある方は試してみてください。

コマンドライン引数はこのようになります。

curl --header "project_id: <Sender ID>" --header "Authorization: key=<Server API Key>" --header "Content-Type: application/json" https://gcm-http.googleapis.com/gcm/send -d "{\"registration_ids\":[\"<Registration Token>\"], \"data\":{\"message\":\"<送りたいメッセージ>\"}}" -k

実際に Server API Key, Sender ID, Registration Token を入れるとこうなります。

curl --header "project_id: 470359069872" --header "Authorization: key=AIzaSyAm2PGhAkDMe51AwqR0RcdesRu2mGF9h5U" --header "Content-Type: application/json" https://gcm-http.googleapis.com/gcm/send -d "{\"registration_ids\":[\"cfF7YmCvVrU:APA91bHqvpto7rfdHxi4b5Vizm1MKFWXL2avZ5suOjcCVQuLzCoRjc79ehjVUm2syaz9RbWG7mhcopAJC0TZk21YXmA-rgg6x9QTiESzcPbJhqUZLMCjHlk_iYiBIpMv8SLKsnNzyoRU\"], \"data\":{\"message\":\"Hello GCM World\"}}" -k

送信先の識別トークン(Registration Token)が複数ある場合はカンマで区切って指定します。なお、エスケープ文字がわかりにくいので注意してください。

* ところで、プッシュ通知の依頼先(GCM)のURLは、現在は下記のようになっています。これをコマンドラインの引数に指定しています。
https://gcm-http.googleapis.com/gcm/send
このURLは、Googleの大きな仕様変更で変わってしまう場合がありますので注意してください。

では、先程のAndroidアプリが起動してある状態で、このコマンドを実行してみましょう。このような実行結果が表示されると思います。

{"multicast_id":7625687185847865149,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1459384639091038%02219117f9fd7ecd"}]}

「”success”:1」となっていれば、GCMへの送信は成功です。「”failure”:1」となった場合はどこか引数などが間違えていないか確認してください。

送信が成功し、Androidアプリも正常に動作していれば、プッシュ通知で “Hello GCM World” という文字列をを受信したことがlogcatで確認できると思います。

03-31 09:37:18.566 3721-18992/jp.co.webtech.pushtestapp V/MyGcmIntentService: message=Hello GCM World

 

以上が curl コマンドによる通知開始の手順ですが、これでは少々わかりにくいかもしれません。

そこで、Ruby を使った場合の送信コードの例も紹介しておきます。
こちらも、環境を用意できればWindows上でも実行可能だと思います。

gcm_send.rb:

require 'net/http'
require 'json'
require 'openssl'

#GCMのPOST先URL (変更される可能性があるので注意!)
URL_GCM               = "https://gcm-http.googleapis.com/gcm/send"

#Server APIキー
GOOGLE_API_KEY        = "AIzaSyAm2PGhAkDMe51AwqR0RcdesRu2mGF9h5U"

#プロジェクト番号(Sender ID)
GOOGLE_PROJECT_NUMBER = "470359069872"

#ヘッダ
headers = {
  'project_id' => GOOGLE_PROJECT_NUMBER,
  'Authorization' => 'key=' + GOOGLE_API_KEY,
  'Content-Type' => 'application/json'
}

#送信先の識別トークンの配列
ids = [
  "cfF7YmCvVrU:APA91bHqvpto7rfdHxi4b5Vizm1MKFWXL2avZ5suOjcCVQuLzCoRjc79ehjVUm2syaz9RbWG7mhcopAJC0TZk21YXmA-rgg6x9QTiESzcPbJhqUZLMCjHlk_iYiBIpMv8SLKsnNzyoRU",
]

#送信するメッセージ
message = { 'message' => 'Hello GCM!' }

#送信内容の連想配列
body = { 'registration_ids' => ids, 'data' => message }

#HTTPクライアント作成
uri = URI(URL_GCM)
http = Net::HTTP.new(uri.host, uri.port)

#httpsで通信します
http.use_ssl = true

#証明書を使いません
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

#POSTリクエストクラス生成
post = Net::HTTP::Post.new(uri.path, headers)

#連想配列をJSON化
post.body = body.to_json

#送信
response = http.request(post)

#結果JSONを連想配列にする
result = JSON.parse!(response.body)

#整形して表示
puts jj(result)

#レスポンスコード表示
puts "response=#{response.code}"

 

以上です。いかがでしたでしょうか。

今回は「識別トークン管理サーバー」についての詳細は割愛させていただきましたが、要はスマホアプリから識別トークンを受け取って管理し、プッシュ通知したいときにその一覧を生成できるものであれば、仕組みは何でもかまいません。

なお、ウェブテクノロジでは、プッシュ通知や歩数計測エンジンなどを使った、「健康促進」「見守り」を目的としたスマホアプリの提案・開発を行っております。ご興味がありましたら是非お気軽にご相談ください。

タグ , , , , | 2020/06/16 更新 |