32
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【2022年改訂版】AizuHack LINEBot勉強会 Vol.1

Last updated at Posted at 2021-06-20

AizuHack LINEBot勉強会 Vol.1

資料一覧

はじめに

こんにちは、会津大学学部二年のしんぶんぶんです。

本記事はAizuHackのLINEBot勉強会 Vol.1の資料になります。

本記事のサンプルコードは個人利用で一般的に使われるLINE Messaging APIの機能をだいたいカバーしており、サンプルコードを書き換えるだけでLINE Messaging APIのだいたいの機能が使えるようになっています。

LINEBotの入門記事やサンプルはたくさんありますが、その多くがオウム返しbotを作るだけやngrokで動かすだけの拡張性が低いものになっています。
AWSなどにデプロイする記事などもありますが、初心者には若干ハードルが高くとっつきにくいかと思います。
今回の資料では、初心者でも理解できるということを念頭におきつつ、例えば、Vercelでデプロイして永続化する、ソースコードはできるだけ改造しやすいように書くなど、できるだけ拡張性が高いように作成しました。
コピペだけで簡単に機能拡張できるようなサンプルコードになっています。

【追記】
最初からクラウドにデプロイすると手間がかかるため、最初はngrokで試して後からGCPのCloud Runへデプロイする形に変更しました。
GCPへのデプロイ手順はAizuHack LINEBot勉強会 Vol.4に掲載しています。

また、本記事に掲載している解説の多くは公式リファレンスを参考に作成しています。
このリファレンスは非常にわかりやすいため、作っていて何かわからないことがあったらリファレンスを参考にしましょう。

できるようになること

  • ngrokを使ってLINEBotを動かすことができる
  • 一般的に使われるイベントの種類を理解できる
  • LINE Messaging APIで返信できるメッセージの種類が理解できる

サンプルコードについて

本サンプルコードで試せることは以下の通りです

  • メッセージイベント
    • テキスト
    • 画像
    • 動画
    • 音声
    • ファイル
    • 位置情報
    • スタンプ
  • 送信取消イベント
  • フォローイベント
  • フォロー解除イベント
  • 参加イベント
  • 退出イベント
  • メンバー参加イベント
  • メンバー退出イベント
  • ポストバックイベント

LINEBotについて

LINEBotについてはこちらのGoogle Slidesで解説しています。

事前準備

この記事を読む前に以下の事前準備を行ってください。

  • JavaScriptについて勉強する
  • LINE Developersのアカウントを作成して、プロバイダを1つ作成する
    • 普段使っているLINEアカウントでログインしてください
  • ngrokのアカウントを作成する
  • (ローカルで開発したい人は)ローカルにNode.jsの環境を導入する

簡単な流れ

  1. LINEBotのアカウントを作成する(Messaging APIのチャネルを作成する)
  2. GitHubのリポジトリからソースコードをcloneして、モジュールをインストールする
  3. LINE DevelopersからLINE Botの設定をする
  1. ngrokで試してみる
  2. 完成!

作ってみよう!

初回準備

  1. LINE DevelopersにログインしてMessaging APIのチャネルを作成する
    • チャネル名とかは適当にいれる(LINEという単語が入っていると作成できないので注意)
  2. GitHubリポジトリからコードをcloneする
  3. ソースコードがあるリポジトリに移動してnpm iを実行する(この先の手順でもterminalでコマンドを実行する操作がいくつか出てきますが、全てソースコードのリポジトリで実行してください)
  4. LINE Developersに移動して先ほど作成したチャネルを開き、以下の設定をする
    1. "Messaging API設定"→"LINE公式アカウント機能"から"グループ・複数人チャットへの参加を許可する"を有効化、"応答メッセージ"を無効化、"あいさつメッセージ"を無効化する
    2. チャネルアクセストークン(長期)を発行し、コピーしてどこかにメモしておく
    3. "チャネル基本設定"→"基本情報"からチャネルシークレットを発行し、コピーしてどこかにメモしておく
  5. ソースコードがあるリポジトリに.envというファイルを作成して、以下のコードを記述する
.env
channelSecret=先ほどコピーしたチャネルシークレット
channelAccessToken=先ほどコピーしたチャネルアクセストークン

6.ngrokにログインする
7. 左側のメニューにあるYour Authtokenを選択する
スクリーンショット 2022-05-19 11.19.43.png
8. Tokenが表示されるのでコピーする。
スクリーンショット 2022-05-19 11.23.14.png
9. terminalで以下のコマンドを入力する

npx ngrok authtoken 先ほどコピーしたngrokのtoken

以上で初回の準備は完了です!
上記の手順はサーバ初回起動時のみ必要となるため、2回目以降サーバを起動したい場合は以下のサーバ起動の手順を行えば大丈夫です。

サーバ起動

  1. npm startを実行する(これでNode.jsのサーバが3000番ポートで起動されます)
  2. terminalをもう1つ開いて、npx ngrok http 3000を実行する(これでローカルPCの3000番ポートが外部に公開されます)
  3. Forwardingという項目が2つありそれぞれURLが記述されているので、httpsから始まる方をコピーする
  4. LINE Developersに移動して先ほど作成したチャネルを開き、以下の設定をする
    1. "Messaging API設定"→"Webhook URL"に、先ほどコピーしたURLの後ろに/webhookを追加したものを貼り付ける
    2. "Webhookの利用"をオンにする(2回目以降この手順は必要ありません)
  5. 完成!!!

動かしてみよう

  1. LINE Developersに移動して先ほど作成したチャネルを開き、"Messaging API設定"→"ボット情報"→"QRコード"に掲載されているQRコードを読み取って友達追加する
  2. 挨拶メッセージが返ってきたら設定成功です!

※サーバのログは先ほどnpm startを実行したterminalに表示されるので、メッセージを送ったらどんなログが表示されるか確認してみましょう

コード解説

eventの種類

LINE Messaging APIのWebhookには様々なイベントがあります。
今回のサンプルコードで使用しているイベントを以下で簡単に解説します。

※途中で挿入しているイベント例は公式リファレンスから引用したものになります

共通プロパティ

すべてのイベントに共通するプロパティについて解説します。イベントは以下のような形になっています。

{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "0f3779fba3b349968c5d07db31eab56f",
      "type": "message",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "user",
        "userId": "U4af4980629..."
      },
      ・・・
    }
  ]
}
  • destination
    • botのuserId
    • userIdとはLINEのアカウントを識別するIDで、ユーザー✖️プロバイダで一意になっています
      • つまり、プロバイダが変わると同じユーザーでもuserIdが変わります
  • events
    • Webhookイベントが入っています
      • replyToken
        • イベントへ応答する際に使用するトークンです
        • これが含まれているイベントには返信できます
      • type
        • イベントのタイプです
        • イベントの種類についてはeventの種類で解説しています
      • mode
        • チャネルの状態です
        • botがアクティブかどうかの情報が入っています
      • timestamp
        • イベントが発生した時刻のタイムスタンプです
      • source
        • イベントの送信元情報が入っています
        • typeにどこから送られてきたかが入っています(usergroupなど)
        • 送信元のuserIdやgroupIdも含まれています

メッセージイベント

  • メッセージが送られてきた時に発生するイベントです
  • メッセージには以下の種類があります
    • テキスト
    • イメージ
    • ビデオ
    • オーディオ
    • ファイル
    • 位置情報
    • スタンプ

それぞれのメッセージのjsonはリファレンスで確認できます。

送信取消イベント

メッセージが送信取り消しされた時に発生するイベントです。

中身は以下のような形になっています。

{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "type": "unsend",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "group",
        "groupId": "Ca56f94637c...",
        "userId": "U4af4980629..."
      },
      "unsend": {
        "messageId": "325708"
      }
    }
  ]
}
  • unsend.messageIdに送信取り消しされたmessageIdが格納されています。
  • replyTokenが含まれていないため、このイベントに対して返信することはできません

フォローイベント

Botのアカウントが友達追加されるかブロック解除された時に飛んでくるイベントです。

イベントの中身は以下のような形になっています。

{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
      "type": "follow",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "user",
        "userId": "U4af4980629..."
      }
    }
  ]
}
  • このイベントにはreplyTokenが含まれているため返信できます

フォロー解除イベント

Botがブロックされた時に飛んでくるイベントです

{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "type": "unfollow",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "user",
        "userId": "U4af4980629..."
      }
    }
  ]
}
  • このイベントにはリプライトークンがないため返信はできません

参加イベント

  • botがグループまたはトークルームへ参加した時に飛んでくるイベントです
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
      "type": "join",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "group",
        "groupId": "C4af4980629..."
      }
    }
  ]
}
  • このイベントにはreplyTokenが含まれているため返信できます

退出イベント

  • botがトークルームやグループから退出したさいにとんでくるイベントです
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "type": "leave",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "group",
        "groupId": "C4af4980629..."
      }
    }
  ]
}
  • このイベントにはreplyTokenが含まれていないため返信はできません

メンバー参加イベント

Botが参加しているグループにメンバーが参加した時にとんでくるイベントです

{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "0f3779fba3b349968c5d07db31eabf65",
      "type": "memberJoined",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "group",
        "groupId": "C4af4980629..."
      },
      "joined": {
        "members": [
          {
            "type": "user",
            "userId": "U4af4980629..."
          },
          {
            "type": "user",
            "userId": "U91eeaf62d9..."
          }
        ]
      }
    }
  ]
}
  • 参加したユーザーの情報が配列形式でjoined.membersに格納されています
  • このイベントにはreplyTokenが含まれているため返信できます

メンバー退出イベント

  • Botが参加しているトークルームやグループからメンバーが退出した時にとんでくるイベントです
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "type": "memberLeft",
      "mode": "active",
      "timestamp": 1462629479960,
      "source": {
        "type": "group",
        "groupId": "C4af4980629..."
      },
      "left": {
        "members": [
          {
            "type": "user",
            "userId": "U4af4980629..."
          },
          {
            "type": "user",
            "userId": "U91eeaf62d9..."
          }
        ]
      }
    }
  ]
}
  • left.membersに配列形式で退出したメンバーのリストが格納されています
  • このイベントにはreplyTokenが含まれていないため返信はできません

ポストバックイベント

  • ポストバックとはトーク上に表示されない、「見えないメッセージ」のようなものです
  • トーク上には何も表示されませんが、サーバにデータは飛んできます
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "b60d432864f44d079f6d8efe86cf404b",
      "type": "postback",
      "mode": "active",
      "source": {
        "userId": "U91eeaf62d...",
        "type": "user"
      },
      "timestamp": 1513669370317,
      "postback": {
        "data": "storeId=12345",
        "params": {
          "datetime": "2017-12-25T01:00"
        }
      }
    }
  ]
}
  • postback.dataにdataが格納されています
  • 日時選択アクションの場合はpostback.paramsに日時データが含まれています

メッセージオブジェクトについて

LINE Messaging APIで返信できるメッセージには以下の種類があります

クイックリプライ

クイックリプライは以下の画像のようなメッセージです。
次のメッセージがトークに送信されると選択肢が消えます。

IMG_1978.PNG

テキストメッセージ

IMG_1979.PNG

スタンプメッセージ

IMG_1980.PNG

画像メッセージ

IMG_1981.PNG

動画メッセージ

IMG_1982.PNG

音声メッセージ

IMG_1983.PNG

位置情報メッセージ

IMG_75048DDFCE46-1.jpeg

イメージマップメッセージ

1つの画像の中に複数のタップ領域を設定できるタイプのメッセージです

ボタンテンプレート

画像、タイトル、テキスト、ボタンで構成されたメッセージです

IMG_1985.PNG

確認テンプレート

テキストに加えて、2つのボタンが平行に表示されます

IMG_1986.PNG

カルーセルテンプレート

複数のカラムを横にスクロールする形で表示できます。

IMG_1987.PNG

画像カルーセルテンプレート

カルーセルの全面画像版です

IMG_1988.PNG

Flex Message

CSS Flexible Boxの記法をベースに作れるメッセージで、とても自由度が高いです。
Flex Messageに関しては第二回勉強会で解説します。

IMG_E1A9A475D122-1.jpeg

ディレクトリ構成

本サンプルコードのディレクトリ構成は以下のようになっています

- /
  - api/ 
    - server.js
  - event/
    - follow.js
    - join.js
    - leave.js
    - memberJoined.js
    - memberLeft.js
    - postback.js
    - unfollow.js
    - unsend.js
    - message.js
    - message
      - audio.js
      - file.js
      - image.js
      - location.js
      - sticker.js
      - text.js
      - video.js

  - bot.js
  - config.js
  - vercel.json

実行の流れ

LINEBotで何かイベントが発生した際、今回のサンプルコードでは以下の流れで処理をします。

  • たとえば「こんにちは」というメッセージを送った場合

ユーザーがメッセージを送信する → LINEのサーバに送られる → LINEのサーバからngrokの/webhookにリクエストが飛んでくる → 自分のPCにたてたNode.jsサーバにリクエストが飛んでくる → server.jsが呼び出される → server.jsがbot.jsを呼び出す → bot.jsがmessage.jsを呼び出す → message.jsがtext.jsを呼び出す → text.jsが「Hello, World」というメッセージをmessage.jsに返す → message.jsが返信するメッセージをbot.jsに返す → bot.js返信するメッセージをLINEのサーバに送る → LINEのサーバからユーザーにメッセージが送られる

各ファイルのコード解説

/api/server.js

サーバを起動するコードが書いてあるファイルです。/にGETのアクセスがきたらDeploy succeededとレスポンスし、/webhookにPOSTのアクセスがきたら/bot.jsのindexを呼び出してその実行結果をレスポンスするというコードになっています。

/bot.js

LINEから送られてきたリクエストを処理するコードが書いてあるファイルです。/eventにそれぞれのイベントを処理するファイルが格納されているため、イベントに合わせてそれぞれのファイルを呼び出す処理が書かれています。

/event/follow.js

Botのアカウントが友達追加された時に呼び出されるファイルです。
友達追加ありがとうございます!と返信する処理が書いてあります。

/event/join.js

Botがトークルームやグループへ招待された時に呼び出されるファイルです。
招待ありがと!!と返信する処理が書いてあります。

/event/leave.js

Botがトークルームやグループから退出した時に呼び出されるファイルです。
botがグループから退出しましたとログに出力する処理が書いてあります。

/event/memberJoined.js

Botが入っているグループやトークルームにユーザーが参加した時に呼び出されるファイルです。
ユーザーが参加しました! 参加したユーザー: userIdと返信される処理が書かれています。

/event/memberLeft.js

Botが入っているグループやトークルームからユーザーが退出した時に呼び出されるファイルです。
ユーザーが退出しました... 退出したユーザー: userIdと返信される処理が書かれています。

/event/message.js

メッセージが送られてきた時に呼び出されるファイルです。
テキストが送られてきた場合は/event/message/text.js, イメージは/event/message/image.js, ビデオは/event/message/video.js, オーディオは/event/message/audio.js, ファイルは/event/message/file.js, 位置情報は/event/message/location.js, スタンプは/event/message/sticker.jsがそれぞれ呼び出されます。

/event/message/text.jsでは送られてきたメッセージで条件分岐して返信するメッセージを決める処理が書かれています。/event/message/image.js, /event/message/video.js,/event/message/audio.js, /event/message/file.jsでは/downloadディレクトリにファイルを保存したのち、メッセージを返信する処理が書かれています。
/event/message/location.jsでは受け取った住所を返信する処理、/event/message/sticker.jsには受け取ったスタンプのIDを返す処理が書かれています(特定のスタンプを受け取った時のみあるスタンプを返信する処理も書かれています)。

返信に対応しているメッセージは以下の通りです

以下のメッセージを送信して何が返ってくるか試してみましょう!

  • テキスト
    • こんにちは
    • 複数メッセージ
    • クイックリプライ
    • スタンプメッセージ
    • 画像メッセージ
    • 位置情報メッセージ
    • イメージマップメッセージ
    • ボタンテンプレート
    • 確認テンプレート
    • カルーセルテンプレート
    • 画像カルーセルテンプレート
    • Flex Message
    • プロフィール
    • ここはどこ
      • 個チャ、グループ、トークルームで返信されるメッセージが変わります
  • イメージ
  • ビデオ
  • オーディオ
  • ファイル
  • 位置情報
  • スタンプ

/event/postback.js

ポストバックイベントが飛んできた時に呼び出されるイベントです。

  • ポストバックイベントとは

ポストバックイベントとは、表に表示されないメッセージのようなものです。トーク画面には表示されませんが、サーバへデータが飛んできます。

テンプレートメッセージなどでポストバックアクションが実装されているボタンを押すとポストバックイベントが飛んできます。

/event/unfollow.js

botがunfollow(ブロック)された時に飛んでくるイベントです。
unfollowされました...\nuserId: ${userId}とログに表示される処理が書かれています。

/event/unsend.js

メッセージが送信取り消しされた時に飛んでくるイベントです。
メッセージが取り消されました!\n取り消されたmessageId: ${messageId}と返信される処理が書かれています

config.js

アクセストークンやチャネルシークレットなどのコンフィグ情報を読むこむ処理が書かれています。

アクションオブジェクトについて

テンプレートメッセージのボタンなどを押したときに実行される操作を、アクションオブジェクトというものを用いて記述することができます。

詳しくはこちらのリファレンスに記載されています。

ソースコードを更新する方法

nodemonを使ってホットリロードできるようになっているので、変更を加えたらファイルを保存するだけでサーバが勝手に再起動されて自動で適用されます。

PCをスリープ/シャットダウンしたりVSCodeを閉じるとNode.jsのサーバ、ngrokのセッションが終了してしまうため、その場合はサーバ起動の手順を確認しながらサーバ起動、ngrokの実行、WebhookURLの更新を行ってください。

演習課題1

「こんにちは」と送信したときに返ってくるメッセージを「こんにちは世界」に変えてみましょう。

演習課題2

「おはよう」と送信したら「Good Morning!」と返信するコードを追加してみましょう。

演習課題3

自分のQ2の時間割を確認するbotを作ってみましょう。要件は以下のとおりです。

  • 「時間割」と送信すると、曜日を選択するボタンが出てくる(クイックリプライを使用すると良さげ)
  • ボタンを押すと、その曜日の時間割が送られてくる

演習課題4(宿題)

勉強会の評価アンケートをLINEBotで実装してみましょう(アンケート形式だけを実装すれば良くて、アンケート結果を保存する必要はありません)。
選択肢の実装はボタンテンプレートやクイックリプライを使うと良いかもしれません。
自由記述の実装方法はいくつか考えられますが、思いつかなかったら選択肢の項目を実装するだけでも大丈夫です。

演習課題5(宿題)

今回の勉強会で、LINEBotにできることはだいたいわかったのではないでしょうか。次回までに自分が作ってみたいLINEBotをいくつか考えてみましょう(次回ちょこっと発表してもらうかもです)。

おわりに

皆さんお疲れ様でした。このソースコードを全て理解する必要はないので、まずは「どこをいじったらどう動くのか」を知るためにたくさんコードをいじくりまわしてみましょう。

第2回はLINE Bot Designerの使い方、Flex Messageの作り方、リッチメニューの作り方、PUSHメッセージについて解説する予定です。

第二回はこちら: AizuHack LINEBot勉強会 Vol.2

32
19
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?