Closed9

LINE Messaging API触ってみる

ピン留めされたアイテム
himawarichanhimawarichan

【目標】
公式アカウントからMessaging APIでメッセージを送る。できればFlexMessageを送ってみたい。
メッセージ以外にも面白そうな機能あったら寄り道するかも。

【環境】
Laravel 8.83.14 ※laradockで構築済み
mysql 8.0.28

himawarichanhimawarichan

設定 > Messaging APIからDeveloperアカウント?作成する。
名前とメールアドレスを入力し、プロバイダーを作る。プロバイダーは後から変更できないとのこと。

完了するとChannel IDとChannel secretが発行された

himawarichanhimawarichan

WebhookURLはSSL化が必須とのこと。
ドキュメントだとHerokuを使った例があるが、ngrokというツールを使ってローカル環境をSSL化し公開してみる。

himawarichanhimawarichan

ngrok導入手順

  1. 下記からサインアップ
    https://ngrok.com/
  2. ログイン後setup手順に従ってセットアップする。winなのでexeダウンロードし、認証を行う
  3. コマンドプロンプトからexeが置いてある場所へ移動し、そこでngrokコマンドを実行
    ローカル環境はvirtualhost設定してるので、--host-headerオプションを付けてこんな感じのコマンド実行した
ngrok http --host-header=rewrite hogehoge.local:80

参考:
https://qiita.com/yamatmoo/items/8d5c2ffe6edf54c91957#virtualhostとか

ちょっと困ったのが、exeを直接実行したらコマンドプロンプトが立ち上がったのでそこでngrokコマンドを実行するものだと思い、実行したらエラー落ちしてしまった。

しかもこの時ngrokの起動はできていて、改めてコマンドプロンプトから実行するとエラーが起きる(無課金だと1セッションまでしか使えない)
本来、ngrokを終了する場合はctr+cで処理を終了する形なのだが、異常終了しているためそれもできない。
どうしようもなかったのでtaskkikllコマンドで強制終了させた。停止コマンドとかないのか…。
https://stackoverflow.com/questions/26291006/stop-sharing-a-port-on-ngrok

管理画面から終了しようにも無料だとダメだと怒られるし、公式ドキュメントにも検索機能ないから調べにくいし……便利なのか不便なのか……。

himawarichanhimawarichan

メッセージを送ったらそのメッセージをおうむ返しするbotを作ってみる。
「メッセージを送るなどでWebhookイベントが発火→WebhookURLに設定したURL(API)へリクエスト 」の流れ

アクセストークンとチャネルシークレットは.envに記載し、config/service.php経由で呼び出す。
チャネルシークレットなどの作成は下記参考。
https://zenn.dev/protoout/articles/16-line-bot-setup#6.-line-botの二つのキーを取得

ルーティング設定

routes/api.php
Route::prefix('line')->group(function () {
    Route::post('webhook', [App\Http\Controllers\Line\WebhookController::class, 'webhook'])->name('api.line.webhook');
});

コントローラーに実装

app/Services/Line/WebhookController.php
use LINE\LINEBot\HTTPClient\CurlHTTPClient;
use LINE\LINEBot;

class WebhookController extends Controller
{
    public function webhook(Request $request)
    {
        $httpClient = new CurlHTTPClient(config('services.line.access_token'));
        $bot = new LINEBot($httpClient, ['channelSecret' => config('services.line.chanel_secret')]);
        
        Log::debug($request->all());

        $request->collect('events')->each(function ($event) use ($bot) {
            $bot->replyText($event['replyToken'], $event['message']['text']);
        });
        return;
    }

どういうリクエストが来るのかドキュメント読んでてもわからなかったので、ログに出した。
(トークンやID系は伏せとく)

[2022-06-13 16:39:55] local.DEBUG: array (
  'destination' => '<destination>',
  'events' => 
  array (
    0 => 
    array (
      'type' => 'message',
      'message' => 
      array (
        'type' => 'text',
        'id' => '<id>',
        'text' => 'てすてす',
      ),
      'webhookEventId' => '<webhookEventId>',
      'deliveryContext' => 
      array (
        'isRedelivery' => false,
      ),
      'timestamp' => 1655105989419,
      'source' => 
      array (
        'type' => 'user',
        'userId' => '<userId>,
      ),
      'replyToken' => '<replyToken>',
      'mode' => 'active',
    ),
  ),
)  
himawarichanhimawarichan

webhookイベントにはこういうのがある。
https://developers.line.biz/ja/docs/messaging-api/receiving-messages/#webhook-event-types

ユーザーからメッセージが送られた時にメッセージを返したいのでその処理を追加。
またメッセージも画像などテキスト以外が送られた場合にはおうむ返しはしないよう修正。

他色々直したのがこれ。request取得時コレクションにしていたが、配列で扱うように変更してる(そっちの方が個人的に慣れているので)

app/Services/Line/WebhookController.php
    public function webhook(Request $request)
    {
        //webhookのイベントの種類がmessage以外であれば何もしない
        $request_params = $request->input('events.0');
        if($request_params['type'] !== 'message'){
            return;
        }

        $httpClient = new CurlHTTPClient(config('services.line.access_token'));
        $bot = new LINEBot($httpClient, ['channelSecret' => config('services.line.chanel_secret')]);

        //メッセージがテキストだったらおうむ返し
        if($request_params['message']['type'] === 'text'){
            $bot->replyText($request_params['replyToken'], $request_params['message']['text']);
        }else{
            $bot->replyText($request_params['replyToken'], 'テキストを送ってください。');
        }

        return;
    }
himawarichanhimawarichan

今更だが、Messageing APIでメッセージを送るパターンは二つ

  • 応答メッセージ
    ここまでやったようにユーザーからメッセージが送られてきたなど、何かのアクションが発生した時にメッセージを送るパターン。
  • プッシュメッセージ
    ユーザーからのアクションの有無にかかわらず、任意のタイミングでメッセージを送る。

ここからはプッシュメッセージを実装してみようと思う。

※余談
プッシュメッセージは有料プランでないと送れない~みたいな記述を見かけたが、今はそんなことはないらしい。
ただ送る人数分月の通数にカウントされてしまうので注意。今回はテストアカウントで友達登録も1~2人なので大丈夫でしょう。

このスクラップは2022/07/21にクローズされました