こんにちは。

田中(邦)です。

今回はAmazon Simple Queue Service(Amazon SQS)Amazon Simple Notification Service(SNS)を使ってAndroid端末にプッシュ通知を送信する仕組みを実装していきます。

イメージとしては

  1. プッシュ通知用のデータがアプリ側でMongoDBにどんどん登録されていく
  2. 貯まったデータをSQSに登録するrakeタスクを一定間隔で実行
  3. SQSに登録されたキューを取り出し、SNSを利用しAndroid端末にプッシュ通知を配信する

という感じです。

準備するもの

アプリの設定(Google Play)

  1. Google Developer Consoleにログインし、アプリを登録しますアプリ登録
  2. Google Cloud Consoleにログインします
  3. Create Projectを選択し、新しいプロジェクトを作成します
  4. 一覧から先ほど作成したプロジェクトを選択します
  5. 画面左側のサイドバーからAPIsを選択し、”Google Cloud Messaging for Android”をONにしますGoogle Cloud Console
  6. 次にサイドバーから今度はRegistered appsを選択し、画面上部の”REGISTER APP”を選択します
  7. PlatformにAndroidを選択し、”Accessing APIs directly from Android”と”Accessing APIs via a web server”を選択したものでそれぞれアプリケーションを登録します。NameはGoogle Developer Consoleで登録したものと同じで良いと思います
  8. 7で登録した”Accessing APIs via a web server”の方を一覧から選択し、Server Keyを開くと表示されるAPI KEYをコピーしておきますAPI KEY
  9. Google Developer Consoleを開き、1で登録したアプリを選択します
  10. 画面左側に表示されているサイドバーの”サービスとAPI”を選択し”別の送信者IDをリンク”をクリックします
  11. 8でコピーしておいたAPI KEYをここで入力すると、1で登録したものと7で登録したものがリンクされますサービスとAPI
  12. サンプルを参考にしてアプリを作成し、Registration IDをサーバに登録できる仕組みを実装する。説明は割愛します

SQS,SNSの設定

次にSNSとSQSを設定します。

  1. まずSQSです。”Create New Queue”ボタンを選択肢、新しいキューを登録します。ここではSampleQueueとQueue Nameを設定しました
  2. 次にSNSです。SNSを開くとDashboardに”Add a New App”というボタンがあるので、そちらを選択します
  3. Push PlatformにGoogle Cloud Messaging(GCM)を選択し、API Keyに”アプリの設定(Google Play)” 8でコピーしたAPI KEYを入力してください。正しく設定できていれば画面左のAppsに(1)と表示されているはずです
    スクリーンショット 2013-12-16 15.13.46
  4. ついでにIAMでプッシュ通知専用のユーザを作っておくと良いかもしれません
    IAM

rakeタスクの実装

前回開発したアプリにモデルやタスクを追加していきます。

  1. まずプッシュ通知用のモデルを作成します
    padrino g model push_notification
    を実行してください
  2. モデルにフィールドを追加します
    
    class PushNotification
     include Mongoid::Document
     include Mongoid::Timestamps # adds created_at and updated_at fields
     WAITING = 0
     REGISTERED = 1
     DELIVERED = 2
    
     field :message, :type => String
     field :status, :type => Integer #0 => 未配信,1 => SQS登録済み 2 => 配信済み
     field :token, :type => String
    
     scope :waiting, where(:status => WAITING)
     scope :registered, where(:status => REGISTERED)
     scope :delivered, where(:status => DELIVERED)
    
    end
    
    
  3. タスクを作成します。 lib/tasksというディレクトリを作成し、その中にpush_notification.rakeというファイルを作成します。
    # -*- encoding: utf-8 -*-
    ACCESS_KEY = 'your-aws-access-key'
    SECRET_KEY = 'your-aws-secret-key'
    SQS_ENDPOINT = 'sqs.ap-southeast-1.amazonaws.com' #使用しているリージョンにあわせて変更
    SNS_REGION = 'ap-southeast-1' #使用しているリージョンにあわせて変更
    QUEUE_NAME = 'SampleQueue' #SQSで設定したキューの名前
    SNS_APPLICATION_ARN = "arn:aws:sns:ap-southeast-1:xxxxxxxxx:app/GCM/Sample" #snsに登録したアプリケーションのarn
    
    namespace :batch do
     desc 'SQSにキューを登録する'
     task :register_queue => :environment do
     sqs = AWS::SQS.new(
     :access_key_id => ACCESS_KEY,
     :secret_access_key => SECRET_KEY,
     :sqs_endpoint => SQS_ENDPOINT
     ).client
     queue_url = sqs.get_queue_url(:queue_name => QUEUE_NAME)[:queue_url]
     PushNotification.waiting.each do | notification|
     message = {:id => notification.id, :token => notification.token, :message => notification.message}.to_json
     sqs.send_message(:queue_url => queue_url, :message_body => message)
     notification.status = PushNotification::REGISTERED
     notification.save
     end
     end
    
    desc 'SQSからキューを取り出し、SNSでプッシュ通知を配信する'
     task :broadcast => :environment do
     sqs = AWS::SQS.new(
     :access_key_id => ACCESS_KEY,
     :secret_access_key => SECRET_KEY,
     :sqs_endpoint => SQS_ENDPOINT
     ).client
     queue_url = sqs.get_queue_url(:queue_name => QUEUE_NAME)[:queue_url]
     messages = sqs.receive_message(:queue_url => queue_url)[:messages]
     messages.each do |message|
     json = JSON.parse(message[:body])
     broadcast_via_sns json
     end
     end
    
    end
    def broadcast_via_sns json
     sns = AWS::SNS.new(
     :access_key_id => ACCESS_KEY,
     :secret_access_key => SECRET_KEY,
     :region => SNS_REGION
     )
     client = sns.client
     response = client.create_platform_endpoint(
     :platform_application_arn => SNS_APPLICATION_ARN,
     :token => json["token"]
     )
     endpoint_arn = response[:endpoint_arn]
     client.publish(:target_arn => endpoint_arn, :message => json["message"])
     notification = PushNotification.find_by_id json["id"]
     notification.status = PushNotification::DELIVERED
     notification.save
    end
    
  4. aws-sdkを利用するのでGemfileに下記を追記し、bundle installを実行します
    gem 'aws-sdk'
    
  5. rake -T でタスク一覧を確認する。下記2行が表示されていればOK
    rake batch:broadcast # SQSからキューを取り出し、SNSでプッシュ通知を配信する
    rake batch:register_queue # SQSにキューを登録する
  6. テスト用にデータを登録する。(実際にクライアントからRegistration IDを送信してサーバで登録しても良いし、めんどくさければpadrino consoleから登録しても良いです)
  7. rake batch:register_queue と rake batch:broadcast を順番に実行する
    スクリーンショット 2013-12-16 16.41.41
  8. プッシュ通知の受信を確認するスクリーンショット 2013-12-16 16.30.20

今回はコードをシンプルにするためにエラーのハンドリングやSQSやSNSの不要なレコードの削除などを行っていません。

モデルやタスクを修正すればiOSのプッシュ通知やE-mailでの通知などにも柔軟に対応できるんじゃないかと思います。

ソースはこちらに置いておきます。