Flex Message を使ってリッチUIなLINEボットを作る

先日公開された LINE Messaging API の Flex Message を使ってQiitaの投稿を表示するLINEボットを作ってみました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35192/6c84097b-2c66-b7b0-685b-da3b6132a5b1.png" width="200px">

# **LINE Messaging API とは**

LINEのボットを作成するためのAPIです。
ユーザーから話しかけられた時に応答メッセージを送ったり、任意のタイミングでプッシュメッセージを送ったりできます。
メッセージにはテキストやスタンプといったシンプルなメッセージのほかに、Template Message や Flex Message のようなリッチなUIでやりとりできるメッセージもあります。

- [Messaging API](https://developers.line.me/ja/docs/messaging-api/)
- [APIリファレンス](https://developers.line.me/ja/docs/messaging-api/reference/)

# **Flex Message とは**

2018年6月12日に公開された機能で、テキストや画像など複数の要素を自由にレイアウトできるメッセージです。

<img src="https://developers.line.me/media/messaging-api/using-flex-messages/bubbleSample-77d825e6.png">

今までもテンプレートメッセージというのがあり、比較的リッチなUIを作成することができましたが、予め用意されたレイアウトしか使えない為、自由度がありませんでした。
Flex Message はこれを自由にレイアウトできるようになったものです。

- [Flex Messageを使う](https://developers.line.me/ja/docs/messaging-api/using-flex-messages/)
- [Flex Messageの要素](https://developers.line.me/ja/docs/messaging-api/flex-message-elements/)
- [Flex Messageのレイアウト](https://developers.line.me/ja/docs/messaging-api/flex-message-layout/)

# **作ったもの**

Qiita API を呼び出して最新投稿やユーザーの投稿を Flex Message で表示するボットです。
Python3.7で作りました。

https://github.com/tag1216/linebot-qiita

## メニュー

<img src="https://qiita-image-store.s3.amazonaws.com/0/35192/38d237f2-c1db-1401-edd6-eb4da35a4b81.png" width="200px">

Flex Message とは直接関係ありませんが、LINEにはリッチメニューというものがあり、トーク画面に画像やアイコンのメニューを表示することができます。
リッチメニューを使うことで、ユーザーはテキストを入力しなくてもボットとやりとりすることができるようになります。

今回はLINEで用意されているアイコンでメニューを作成したのでシンプルな見た目ですが、自分で作成した画像をメニューに使うこともできます。

- [リッチメニューを使う](https://developers.line.me/ja/docs/messaging-api/using-rich-menus/)

## 最新投稿

<img src="https://qiita-image-store.s3.amazonaws.com/0/35192/6c84097b-2c66-b7b0-685b-da3b6132a5b1.png" width="200px">

リッチメニューの「最新投稿」をタップすると最新の投稿を10件表示します。
ここではカルーセルコンテナを使用しています。
カルーセルコンテナは複数のバブルコンテナを横方向に並べたものです。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35192/28212a0d-0b24-a3d6-4bb4-e3dd1a8ac633.png" width="200px">

## ユーザー情報

<img src="https://qiita-image-store.s3.amazonaws.com/0/35192/301ab0aa-cbe6-9a23-a731-06de6e808959.png" width="200px">

リッチメニューの「ユーザー」をタップするとユーザー情報を表示します。
ここではバブルコンテナを使用しています。
バブルコンテナは一つのメッセージバブル(吹き出し)を構成するコンテナで、header/hero/body/footerの4つのブロックから構成されています。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35192/ded9d385-6546-68e4-aceb-a78b87f317c0.png" width="200px">

## アクション

Flex Message 内のボタン/画像/テキストにはユーザーがタップした時のアクションを定義できます。
アクションを定義することで要素をタップした時にテキストメッセージを送ったり、URIを開いたりできます。
最新投稿の表示ではユーザーアイコンにアクションを定義してユーザー情報を表示できるようにしています。

# **使ったもの**

## [Flex Message Simulator](https://developers.line.me/console/fx/)

LINEが提供している Flex Message の表示を確認できるシミュレータです。
JSONで定義した Flex Message メッセージをPCブラウザ上で確認できます。
いくつかのサンプルも提供されています。

<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/35192/e39a6470-e4ca-eae1-890e-5d3e993b31da.png">

<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/35192/dc784d3c-d7a5-f8b2-7a44-b74f3108439e.png">

## [ngrok](https://ngrok.com/)

ローカルで起動しているサービスを外部からアクセスできるようにするツールです。

LINEボットを実機から確認するにはサーバーを用意しなくてはなりません。
しかし今回のようにお試しで作ったものをサーバーにデプロイするのは面倒です。
こんな時はngrokを使うとローカルで起動したアプリを実機から動かすことができます。

## [line-bot-sdk-python](https://github.com/line/line-bot-sdk-python)

LINEボットのPython用SDKです。

LINEとボット間の通信ではJSONを使用しています。
例えば Flex Message を送るには以下のようなJSONになります。

```json
{
  "type": "bubble",
  "header": {
    "type": "box",
    "layout": "vertical",
    "contents": [
      {
        "color": "#aaaaaa",
        "size": "lg",
        "text": "tag1216",
        "type": "text",
        "weight": "bold"
      }
    ]
  },
  "hero": {
    "type": "image",
    "size": "lg",
    "url": "https://qiita-image-store.s3.amazonaws.com/0/35192/profile-images/1473686636"
  }
}
```

SDKを使うとJSONのデータに対応したモデルクラスが用意されているので、以下のようなコードになります。

```python
    BubbleContainer(
        header=BoxComponent(
            layout='vertical',
            contents=[
                TextComponent(
                    text=user.id,
                    weight='bold',
                    color='#aaaaaa',
                    size='lg'
                )
            ]
        ),
        hero=ImageComponent(
            size='lg',
            url=user.profile_image_url
        )
    )
```

IDEを使っていると補完でスラスラ書けるようになります。

ただし Simulator を使ってデザインした場合、これをSDKのモデルに書き直すのは面倒です。ソースも長くなります。
このような場合にはテンプレートエンジンを使ってJSONに値を埋め込み、結果をSDKのモデルに変換したほうが良さそうです。
JSONからモデルを構築するには`new_from_json_dict()`というメソッドが用意されています。

https://github.com/line/line-bot-sdk-python/blob/master/linebot/models/base.py

# **最後に**

LINEボットというとテキストを中心としたメッセージでやりとりするイメージがあります。
会話を楽しんだりするボットならそれもいいですが、実用的なボットを目指すならコマンド入力のようなことをユーザーに強いるのは望ましくありません。
そんな時は Flex Message やリッチメニューの活用を検討してみてください。