先日業務でLaravel Echoを使ってFlutterアプリに対してお知らせの未読通知を実装することがありました。
備忘録も兼ねて投稿したいと思います。
バージョン
$ php artisan --version
Laravel Framework 7.30.6
$ flutter --version
Flutter 3.0.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 85684f9300 (3 weeks ago) • 2022-06-30 13:22:47 -0700
Engine • revision 6ba2af10bb
Tools • Dart 2.17.5 • DevTools 2.12.2
Laravel側の設定
まずはLaravel側でLaravel Echoの設定をしていきましょう。
今回はPusherではなくlaravel-echo-serverを使って実装していきたいと思います。
Redisのインストール
まずはRedisをインストールします。僕はMacを使っているので下記コマンドでインストールします。
もし既にローカルにRedisがインストールされている場合は当然インストールは不要です。
// インストール
$ brew install redis
redisはredis-server
で起動します。一度起動してみましょう。
$ redis-server
42978:C 24 Jul 2022 16:23:49.242 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
42978:C 24 Jul 2022 16:23:49.242 # Redis version=7.0.3, bits=64, commit=00000000, modified=0, pid=42978, just started
42978:C 24 Jul 2022 16:23:49.242 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
42978:M 24 Jul 2022 16:23:49.243 * Increased maximum number of open files to 10032 (it was originally set to 2560).
42978:M 24 Jul 2022 16:23:49.243 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 7.0.3 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 42978
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
42978:M 24 Jul 2022 16:23:49.244 # WARNING: The TCP backlog setting of 511 cannot be enforced because kern.ipc.somaxconn is set to the lower value of 128.
42978:M 24 Jul 2022 16:23:49.244 # Server initialized
42978:M 24 Jul 2022 16:23:49.244 * Ready to accept connections
ここで表示されたポート(上記の場合は6379)は後で設定に使うので覚えておいてください。
Laravel Echoのインストール
次にプロジェクトルートに移動して下記コマンドを実行し、Laravel Echo等をインストールします。
// laravel Echoに必要なライブラリのインストール
$ composer require predis/predis
$ npm install --save laravel-echo socket.io-client
// laravel-echo-serverをインストール
$ npm install -g laravel-echo-server
// laravel echoの初期設定を行いlaravel-echo-server.jsonを作成する
$ laravel-echo-server init
// ローカル環境の時のものです。参考にしてください
? Do you want to run this server in development mode? Yes
? Which port would you like to serve from? 6001
atomu@okunoMacBook-Pro mygolf % laravel-echo-server init
? Do you want to run this server in development mode? Yes
? Which port would you like to serve from? 6001
? Which database would you like to use to store presence channel members? redis
? Enter the host of your Laravel authentication server. http://localhost
? Will you be serving on http or https? http
? Do you want to generate a client ID/Key for HTTP API? Yes
? Do you want to setup cross domain access to the API? Yes
? Specify the URI that may access the API: http://localhost:8000
? Enter the HTTP methods that are allowed for CORS: GET, POST
? Enter the HTTP headers that are allowed for CORS: Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id
? What do you want this config to be saved as? laravel-echo-server.json
appId: f526a01938a20971
key: 7e9ec298b4b10e8dccc0e5c930bb8c94
Configuration file saved. Run laravel-echo-server start to run server.
作成されたlaravel-echo-server.json
を見るとの"redis"の部分が{}になっていると思います。
この部分を下記のように編集します。
{
"databaseConfig": {
// この部分を記入する
"redis": {
"scheme" : "tls",
"host" : "localhost",
// redisを起動した時に表示されたポート
"port" : "6379"
// config/database.phpのredis.options.prefixの値
"keyPrefix": "laravel_database_"
},
},
}
注意してほしいのはkeyPrefix
の部分です。
この部分はconfig/database.phpのredis.options.prefixに入る値と同じ値を設定するようにしてください。
<?php
use Illuminate\Support\Str;
return [
・・・
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
// ここに入る
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
・・・
];
少しややこしいですがこれで完成です。
ちなみにここで作成されたlaravel-echo-server.jsonは環境ごとに異なるので.gitignoreに追加しておくことをおすすめします。
Laravelの設定
次に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,
SimpleSoftwareIO\QrCode\QrCodeServiceProvider::class,
App\Providers\ViewComposerServiceProvider::class,
そして次に.envを編集します
// 両方とも既にある場合はredisに変更、そもそも記載ない場合は追記
BROADCAST_DRIVER=redis
QUEUE_CONNECTION=redis
REDIS_CLIENT=predis
忘れずにキャッシュの更新を実施してくださいね。
$ php artisan config:cache
通知するイベントを作成
ここまで来たら次は実際にFlutterアプリに通知するイベントを作成します。
イベントはphp artisan make:event イベントのクラス名
で作成できるので任意の名前で作成してください。
今回僕はお知らせに関する通知を送信したいのでNewInformationEvent
としました。
$ php artisan make:event NewInformationEvent
Event created successfully.
通知するチャンネル名と送信する値をこのファイルに記述していきます。
今回は
- チャンネル名:test-channel
- 送信する値:message
のように設定していきます。
またimplements ShouldBroadcast
をクラス名の後に追記します。
完成形はこのような形になります。
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
// implements以降を追加
class NewInformationEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
// チャンネル名
return new Channel('test-channel');
}
public function broadcastWith()
{
return [
// 送信する値
'message' => 'テストです!',
];
}
}
これでLaravel側の設定は完了です!!
Flutter側の設定
次にFlutter側の設定をしていきましょう。
Flutter側でLaravelから送信されたブロードキャストをリッスンするには下記パッケージを使います。
パッケージ導入
まずはパッケージの導入
$ flutter pub add socket_io_client
$ flutter pub add laravel_echo
$ flutter pub get
通知を受け取る設定
main.dartに下記記述を追記します。
import 'package:laravel_echo/laravel_echo.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;
void main() async {
・・・
// 追記
Echo echo = Echo({
'broadcaster': 'socket.io',
// laravel-echo-server initで設定したホスト:ポート
'client': IO.io('http://localhost:6001'),
});
// php artisan make:event イベントのクラス名で作成したイベント名とチャンネル名
echo.channel('test-channel').listen('NewInformationEvent', (e) {
print(e);
});
・・・
}
公式ドキュメント通りですね。これで終了です!
テスト
それでは早速テストしてみましょう。
、、、と思ってflutter run
したのですが、残念ながらLaravel EchoパッケージがNull Safetyに対応していないとのこと。
公式を確認するとNull Safety対応しているのはベータ版のみだったので仕方なくベータ版をインストールしました。
あとsocket_io_client
についても最新版を入れると動かなかったので別バージョンを入れました。
dependencies:
// 変更
laravel_echo: ^1.0.0-beta.1
// 変更
socket_io_client: ^1.0.1
$ flutter pub get
それに伴いmain.dartも少し変更します。
void main() async {
・・・
IO.Socket socket = IO.io(
'http://localhost:6001',
IO.OptionBuilder()
.disableAutoConnect()
.setTransports(['websocket']).build(),
);
Echo echo = Echo(
broadcaster: EchoBroadcasterType.SocketIO,
client: socket,
);
・・・
}
再度flutter run
$ flutter run
Launching lib/main.dart on iPhone 13 in debug mode...
Running Xcode build...
└─Compiling, linking and signing... 10.0s
Xcode build done. 43.7s
よし!!
Laravelから通知してみる
無事ビルドできたのでLaravelから通知してみましょう。
まずLaravel側でRedis・Laravel Echo Server・キューを起動します。
redisの起動
$ redis-server
Laravel Echo Serverの起動
$ laravel-echo-server start
L A R A V E L E C H O S E R V E R
version 1.6.3
⚠ Starting server in DEV mode...
✔ Running at localhost on port 6001
✔ Channels are ready.
✔ Listening for http events...
✔ Listening for redis events...
Server ready!
キューワーカーの起動
$ php artisan queue:work
特にエラーが発生しなければOKです。
Laravelから通知するには通知したいところでevent(new PublicEvent());
で通知できます。
今回はテストなのでtinkerから通知してみたいと思います。
$ php artisan tinker
Psy Shell v0.11.5 (PHP 7.4.24 — cli) by Justin Hileman
>>> use App\Events\NewInformationEvent;
>>> event(new NewInformationEvent());
=> []
Flutterのコンソール
flutter: {message: テストです!, socket: null}
できた!!
おわりに
初めてLaravel-echo-serverを使用してみたのですがかなり面倒臭いですね。。。
素直にPusherを使う方がいいかなと思いました。
もしうまくいかない・分からないなどあればコメントに書いていただければと思います。
ありがとうございました!