WHITEPLUS TechBlog

Pusherを使ったリアルタイム通知機能

この記事はWHITEPLUS Advent Calendar 2018 - Qiitaの23日目になります。

どうも皆さん、おはこんばんにちは。WHITEPLUSのエンジニアのkazunkrandsです。 昨日に引き続き、どうもです。

私は、弊社で新規事業として運営している生活サービスに特化した事業者様とユーザーのマッチングプラットフォームである生活手帖というサービスのシステム担当をしております。 ※ここまでのクダリは昨日の内容と同じでございます。

生活手帖には生活サービスを提供する側の事業者様と、サービスを受けるユーザーとのやりとりを行うためのメッセージ機能が存在します。現状、いずれか一方の新着メッセージを送信した際にはメールにて相手に通知される仕組みになっております。ただ、ページ上にリアルタイムに「メッセージが来たよ〜」といった通知が見れたら、メッセージのレスポンス時間短縮にも繋がるし便利じゃないかな〜と思ったのが本記事を書くきっかけとなりました。

開発環境

今回も、弊社で普及しているWebフレームワークのLaravelで簡単な通知アプリケーションを作成したいと思います。 環境は以下のような感じです。

  • Laravel 5.5系
  • PHP7.1系

Pusherの導入

Pusherは、WebSocketを利用したリアルタイム双方向通信を行うためのAPIです。Webだけでなく、iOS・Androidアプリにも対応しています。

www.pusher.com

Pusherプロジェクト作成(Sign Up)

上のPusherの公式ページよりログインアカウントを作成します。GithubアカウントやGoogleアカウントからも作成できます。

ログインすると、以下のようなポップが出ます。

f:id:kazunkrands:20181214151840p:plain
プロジェクト作成

今回はfront-endは「JQuery」、back-endは「Laravel」を選択しました。

プロジェクトが作成されるとOverviewタブの左下にKeys情報が表示されます(後々必要になる)。

f:id:kazunkrands:20181214152659j:plain
OverviewのKeys

Pusherライブラリインストール

ComposerでPusherライブラリをインストールします。

composer require pusher/pusher-php-server

config下準備

今回は、Laravelのイベントブロードキャストを使用してリアルタイム通信を実現します。

config/app.phpで以下のApp\Providers\BroadcastServiceProvider::classの行のコメントアウトを解除します。

        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        App\Providers\BroadcastServiceProvider::class, // ←ここ
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,

※これしないと、イベントが全く走りません。当たり前ではあるのですが、凡ミスしてここに気づかず私は30minほどハマりました・・・。

config/web.phpの末尾に以下を追加します。

Route::get('/hello', function() {
    event(new \App\Events\HelloPusher('テストメッセージ'));
    return 'hello pusher';
});

config/broadcasting.phpの以下のところをenvで設定できるよう修正します。clusterを正しく設定しないと動かないです。

'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
                'cluster' => env('PUSHER_APP_CLUSTER'), // ←ここ
                'encrypted' => true,
            ],
        ],

.envを以下のように修正します。PUSHER_APP_CLUSTERはexampleにもともと入っていない定義なので追加してください。

PUSHER_APP_ID=XXXXXX
PUSHER_APP_KEY=XXXXXXXXXXXXXXXXX
PUSHER_APP_SECRET=XXXXXXXXXXXXXXXXX
PUSHER_APP_CLUSTER=XXX

イベント作成

以下のコマンドでイベントクラスを生成します。とりあえずクラス名はHelloPusherとしました。

php artisan make:event HelloPusher

app/Events配下にクラスが生成されるため、以下のように編集します。

<?php

namespace App\Events;

use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class HelloPusher implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

    /**
     * コンストラクタ
     * 
     * @param string $message
     */
    public function __construct($message = 'hello pusher')
    {
        $this->message = $message;
    }


    /**
     * 送信先のチャンネル
     * @return array
     */
    public function broadcastOn()
    {
        return ['my-channel'];
    }


    /**
     * イベント名
     * @return string
     */
    public function broadcastAs()
    {
        return 'my-event';
    }
}

View

Viewは新しく生成しても良かったのですが、今回は横着にwelcomeを編集しちゃいました。簡単に説明すると、前項で作成したイベントを画面上で待機し、イベントを受信すると画面右端からニョロッと通知が出ます。通知に関してはjqueryのnotify.jsプラグインを使いました。

<!DOCTYPE html>
<head>
  <title>Pusher Test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/notify/0.4.2/notify.min.js"></script>
  <script src="https://js.pusher.com/4.3/pusher.min.js"></script>
  <script>

    // log出力設定(本番環境とかでは消してね)
    Pusher.logToConsole = true;

    // XXXXにApp Keyを入れてね。XXXにclusterを入れてね。
    var pusher = new Pusher('XXXX', {
      cluster: 'XXX',
      forceTLS: true
    });

    var channel = pusher.subscribe('my-channel');
    channel.bind('my-event', function(data) {
      $.notify(data.message, 'info');
    });
  </script>
</head>
<body>
<h1>Pusher Test</h1>
<p>
  別ブラウザ(タブ)で/helloにアクセスすると、右端から通知が出現します。
</p>
</body>

完成品

localhostで/を開くと、イベント受信待ちとなります。ここで、別ブラウザ(タブ)で/helloにアクセスすると/の方に以下のように通知が表示されます。

f:id:kazunkrands:20181214163419j:plain
イベント受信(通知表示)

シンプルですが、これだけです(笑)。

まとめ

Pusherを使うことで容易にリアルタイム通信が実現できます。実を言うと、生活手帖のメッセージ機能自体もこのPusherを利用してたりします。チャット形式でお客様と事業者様間のメッセージのやりとりを実現しております。

ただ前述の通り、config系でコメントアウトの罠にまんまとハマってしまってしまい予想以上に時間を要してしまいました(汗)。

参考

最後に

明日は、私と同じくエンジニアngmyさんの「リネットのPHP + LaravelアプリケーションのCIにPHPStanによる静的解析を導入した話」です。

そして、WHITEPLUSでは一緒に働く仲間を募集しています。 www.wantedly.com