LINE Botの作り方と作ってみた時にマジかと思ったことと作るときに使ってほしいサンプルと・・・っていうたくさんの話


初めに

この投稿は以下の構成となっております

  • 作り方
  • マジかと思ったこと →作ってて僕がまじかよと思ったこと ここはこうしてほしかったなーと思ったこと
  • LINE Bot作るときに使ってほしいサンプル →1から作るの面倒だからある程度まで作ってあるASPのRestAPIとService

作り方

  1. ボットアカウント作成
    1. LINE BUSINESS CENTERにログイン
      ログインは自分のLINEアカウントで入れます
      LINEのパスワード思い出すのに小一時間かかった・・・
    2. アカウントリストからビジネスアカウント作成
    3. MessagingAPIを始めるを選択
    4. アカウントを作成
      名前を付けたり画像を選択したり
      業種は自分のじゃなくてそのアカウント(Bot)についてだからね

      こういうのができればOK!
  2. ボットの設定をする
    1. できたボットのLINE@MANAGERをクリック
    2. アカウント設定→Bot設定からAPIを利用するをクリック
      この時トークとか使えなくなりますよ!って警告が出るけど、これはBot用のアカウントがってことで、普段自分が使ってるアカウントのことではないからねw
      僕も一番最初はビビって確認ボタン押せなかったww
    3. Webhook送信を利用するにチェック(重要!)
      自動応答メッセージを利用しないにチェックしててもWebhook先APIからリプライは送れます
      メニューのメッセージに設定できる場所があって、そこにあるメッセージを利用するかどうかっていうのです
  3. ボットの設定をするその2
    1. Botの設定のとこにある「LINE Developersで設定する」を選択

      こういうのが出て来ると思う
    2. ISSUEをクリックしてチャンネルアクセストークンを取得 こいつはBotを一意に識別するトークン
      これはWebhook先のAPIからリプライを飛ばすときとか、画像や動画が通知された時にそのバイナリデータを取得するときに使ったりする
    3. Webhook URLに作ったAPIのURLを追加 APIが完成したらここに指定しよう!

完成!!!!

え?API側は?って人はリファレンスを見よう!日本語だしどちゃくそ丁寧!
僕がBot作ったときはC#、ASPで作った!
別にリクエストが受け取れるなら何でもいい!!!!

リクエストは こんな感じ
通知は全部一つのAPIにでかいリクエストが送られてきて、その中のtypeを見て何のイベントか判断します
テキストが送られてきた時も、画像を送るときも、友達追加したときも、ブロックしたときもAPIは全部一つ!
ただ、eventオブジェクト配下のtypeが違ってて、リクエスト内でそのtypeで処理を分岐させます

画像や動画のバイナリデータはここから取る
イベントタイプがmessageの時でさらにmessageオブジェクト配下のtypeがimageやvideoだった時にContentに対してAPIを投げるとバイナリデータが取れます

リプライを返す時はここ!
一度に返せるリプライは最大5つまで(爆撃はできないのね・・・やろうと思ったらPush通知のほうが必要かな?)

プッシュ通知はここ
だけどお金がかかる!
プッシュ通知がしたかったら有料!
でも逆にプッシュ通知しないなら無料で作れる!!!!

マジかと思ったこと

ユーザから受け取った画像をそのままリプライで返せない

マジか~~~~~~~

僕がLINE Botで作ったのはLINEから受け取った画像からAzureのCognitiveServiceを使って顔情報を取得、そのまま画像を加工してリプライを返す・・・というものだった
ユーザから通知を受けとった際に、イベント種別より画像、動画、音声等々のバイナリデータをContentから取得します
で、CognitiveSerciceに渡すのもバイナリデータ、BitmapとかGraphicsで画像を加工するのもバイナリデータ・・・
なのにリプライを返す時にはバイナリじゃなくURL!
いったんどこかに保存しないといけないし、それが外部から見える位置にないといけない・・・
まぁ画像が返ってくるAPI作っておけば画像自体は見えなくてもいいんだけど
仕方ないのかなぁ・・・

Postback送信時にメッセージ用のリクエストも飛んでくる

マジか~~~~~~~~~~~~~~

これ何かっていうとConfirmやCarousel等をリプライで返すとユーザにボタンを押してもらえるテンプレートが通知できます
このボタンを押したときにpostbackでデータを受け取れるんだけど、ボタンを押したときにユーザに発現させるテキストについても
APIが動いちゃって2つリクエストを受け取ることになる・・・
だからテキストで反応するBotを作るときは要注意

LINEから飛んでくるリクエストを確認するためにAPIを公開する必要がある

まじか~~~~~~~~~~~~~~!!!!!!!!!

まぁCurlコマンドで確認すれば済む話なんですけどね・・・
LINEからWebhookでAPI飛ばしてもらおうと思うと
* 外部サーバから見えるAPIである必要がある
* HTTPSである必要がある
っていう・・・
Curlも一回作っちゃえばいいんだけど・・・
僕はAzureにWebApp乗っけて確認してました
発行から選んでポチーでAPIが公開できるからかーんたん♪
でもおかげで使用料1万~2万円くらいが簡単に飛んできました・・・

LINE Bot作るときに使ってほしいサンプル

作りました
https://github.com/ShassBeleth/LineBotTemplate
MasterブランチPullしてください

開発環境

Visual Studio 2017
C# 7.0

実装

  • Webhookを受け取るController
  • 各イベント種別毎に使えるオブジェクトや変数を制限してメソッド作成
  • リプライ用Service、プロフィール取得用Service、Content取得用Service
  • リプライのサンプル、Confirm、Carousel、Buttonのサンプル

使い方

  • ServiceとModelの中は基本的に触らなくていいはず
  • Controllerクラス内のTODOを検索するとチャンネルアクセストークンを入れる場所があるからそこにBusinessCenterからとってきたトークンを突っ込む
  • APIの公開とBotのWebhookに設定

これでとりあえず動くはず
で、あとはもっかいControllerのTODOで検索すると〇〇の時はここに実装 ってのがあるからサンプル見ながら好きなように実装する!

WebhookController.cs
/// <summary>
/// チャンネルアクセストークンの取得
/// </summary>
/// <returns>チャンネルアクセストークン</returns>
private string GetChannelAccessToken() {

  string token = "";

  // TODO ここに実装方法を記述
  // 例:app.configから取得 定数クラスから取得等

  return token;

}

これね

で、URLとマッピングしてるPostメソッドは基本的に触らない
リクエストの内容毎に分岐してるから
分岐した先にあるメソッドではそのイベントで使えるパラメータだけが引数として渡されてる

WebhookController.cs
/// <summary>
/// 追加時イベント
/// 友達登録、ブロック解除時、グループ追加時、トークルーム追加時
/// </summary>
/// <param name="channelAccessToken">チャンネルアクセストークン</param>
/// <param name="replyToken">リプライトークン</param>
/// <param name="timestamp">Webhook受信日時</param>
/// <param name="sourceType">イベント送信元種別</param>
/// <param name="sourceId">イベント送信元ID</param>
private async Task ExecuteJoinEvent(
  string channelAccessToken ,
  string replyToken ,
  string timestamp ,
  RequestOfWebhook.Event.Source.SourceType sourceType ,
  string sourceId
) {

  Trace.TraceInformation( "Join Event Start" );
  Trace.TraceInformation( "Channel Access Token is : " + channelAccessToken );
  Trace.TraceInformation( "Reply Token is : " + replyToken );
  Trace.TraceInformation( "Timestamp is : " + timestamp );
  Trace.TraceInformation( "Source Type is : " + sourceType );
  Trace.TraceInformation( "Source Id is : " + sourceId );

  // TODO ここにイベント内容を記載
  // 以下サンプル
  await this.ReplyTextMessageSampleEvent( channelAccessToken , replyToken , "追加されました" );

  Trace.TraceInformation( "Join Event End" );

}

例えばこれは友達登録とかしたときに飛んでくる追加イベント
ここでリクエストパラメータとして使いたいのはリプライを飛ばすためのリプライトークンreplyTokenとどこに追加されたかのイベント送信元種別sourcetypeとイベント送信元IDsourceId
こういうのを制限してLINE Botつくろーって時に来もしないパラメータ見る必要を極力少なくしてみました

リプライを飛ばすときはReplyMessageServiceを使う

WebhookController.cs
/// <summary>
/// テキストサンプル
/// </summary>
/// <param name="replyToken">リプライトークン</param>
/// <param name="channelAccessToken">チャンネルアクセストークン</param>
/// <param name="text">テキスト</param>
/// <returns></returns>
private async Task ReplyTextMessageSampleEvent(
  string replyToken ,
  string channelAccessToken ,
  string text
) => await new ReplyMessageService( replyToken , channelAccessToken )
  .AddTextMessage( text )
  .Send();

こんな感じにServiceクラスをnewして、それに送るリプライ分Addメソッドつないで、最後にSendメソッドを呼ぶ
こんだけ!

今後

一通りAPIを網羅してテンプレートとして使えるものにしたいね
入力チェックとかもしてないし
後、リプライ送るときにAddせずにSendメソッドが呼べないようにしたい
他にはー・・・カラムを追加するときとかルール無視でModelの配列渡したりとかできるからできないようにしたいね
改良はまだまだこれから
またLINE Bot触りたくなったら続きやる

最後に

Qiita初投稿でつたない文章だと思いますが、最後までご覧いただきありがとうございました
LINE Bot作るのすごい簡単だったのでみんなも是非作ってみてほしい!