LINEBotのリッチメニューエディタがないので自作した

LINEBotで、以下のようなリッチメニューを表示します。今回はそのエディタと表示方法についてです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/31472c51-50d2-2827-f81f-88386b280f11.png)

リッチメニューは、トーク画面に表示されるメニューで、自分で自由に画像を作成できます。
HTMLでいうところのクリッカブルマップに相当し、自作する画像ファイルの範囲内で、四角形で範囲を指定し、そこをタッチしたときに特定の動作を行うことができます。
特定の動作として以下が可能です。

* ポストバックアクション
* メッセージアクション
* URIアクション
* 日時選択アクション

(参考) LINEリファレンス：リッチメニュー
https://developers.line.biz/ja/reference/messaging-api/#rich-menu

ソースコード一式をGitHubに上げておきました。

poruruba/LinebotRichmenu
　https://github.com/poruruba/LinebotRichmenu

#トーク画面へのリッチメニューの設定

リッチメニューは、以下の3種類の設定箇所があり、いずれにも設定した場合、上の方が優先度が高いです。

* Messaging APIで設定するユーザー単位のリッチメニュー
* Messaging APIで設定するデフォルトのリッチメニュー
* LINE Official Account Managerで設定するデフォルトのリッチメニュー

3つ目は、LINE Developersのページから設定可能です。

LINE Official Account Manager
　https://manager.line.biz/

アカウントを選択し、メッセージアイテム→リッチメッセージと選択すると、管理画面が表示されます。ただし、テンプレートが少なかったり、選択範囲が固定されていたりと、使いにくかったので、今回は使いません。今回は、前者2つのMessaging APIで設定するリッチメニューを扱います。

(i) Messaging APIで設定するデフォルトのリッチメニュー
これが一番簡単で、最初に一回だけAPIを呼び出せば完了です。設定したいリッチメニューの識別子(後述)を設定します。
すべての友達に同じリッチメニューが表示されます。

```js:api\controllers\linebot-richmenu\index.js
app.client.setDefaultRichMenu(richmenu_id);
```

app.clientは、LINE Bot用の自作のライブラリ「line-utils.js」です。内部で以下のnpmモジュールを使っています。

line/line-bot-sdk-nodejs
　https://github.com/line/line-bot-sdk-nodejs

(ii) Messaging APIで設定するユーザー単位のリッチメニュー
ユーザごとに異なるリッチメニューを表示します。

```js:api\controllers\linebot-richmenu\index.js
  await client.linkRichMenuToUser(event.source.userId, richmenu_id);
```

例えば、友達になったときに呼び出せばよいでしょう。
以下のような感じです。

```js:api\controllers\linebot-richmenu\index.js
app.follow(async (event, client) =>{
  await client.linkRichMenuToUser(event.source.userId, richmenu_id);
});
```

以上により、トーク画面でリッチメニューが表示されるようになります。

#リッチメニューの作成

で、じゃあリッチメニューはどうやって作成して、どうやってリッチメニューのIDを取得するのか。
それには、HTTP Post等で、設定します。

(参考) LINE Messaging APIリファレンス：リッチメニュー
https://developers.line.biz/ja/reference/messaging-api/#rich-menu

1点注意がありまして、CORS対応が必要なため、ブラウザのJavascriptから直接は呼び出せません。そこで、Node.jsサーバを立ち上げて、Javascriptからの要求を受け取って登録を行うようにします。

Node.js側での実装は、linebot sdkのnpmモジュールですでに関数化されているためそれを呼び出せばよいだけです。

①```createRichMenu(richMenu: RichMenu): Promise<string>```
②```setRichMenuImage(richMenuId: string, data: Buffer | Readable, contentType?: string): Promise<any>```

※他のAPIは以下を参照してください。
https://github.com/line/line-bot-sdk-nodejs/blob/next/docs/api-reference/client.md

①で、クリッカブルの位置情報を含めてリッチメニューとして登録し、リッチメニューIDを取得します。
ただし、このままでは画像ファイルは登録されていないため、続けて②で画像ファイルを登録して完了です。

ちなみに、一度登録したら変更できないため、修正後の新しいリッチメニューおよび画像ファイルを登録したのち、古いリッチメニューおよび画像ファイルを削除することになります。

画像ファイルのフォーマット(JpgかPNGか)を判別するためとStream操作のために、以下のnpmモジュールも使っています。

sindresorhus/file-type
　https://github.com/sindresorhus/file-type

paulja/memory-streams-js
　https://github.com/paulja/memory-streams-js

以下の部分を、環境に合わせて設定してください。LINE Developersコンソールから確認できます。(LINE Developers コンソール： https://developers.line.biz/ )

```js:api\controllers\linebot-richmenu\index.js
const config = {
  channelAccessToken: '【チャネルアクセストークン（長期）】',
  channelSecret: '【チャネルシークレット】',
};
```

リッチメニューのクリッカブルマップに相当する部分は、以下に示すJSONフォーマットである必要があります。

Messaging APIリファレンス：リッチメニューオブジェクト
　https://developers.line.biz/ja/reference/messaging-api/#rich-menu-object

もろもろのリッチメニュー作成・登録作業をWebページから行えるようにエディタを作成しておきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/78cf146f-7101-90b3-65c0-fc326a9a23c9.png)

画像ファイルをアップロードして可視化し、位置情報とアクション内容を追加して、最後にセットで登録することができます。登録が完了すると、リッチメニューIDが払い出されるので、それをLINEBotサーバに設定しましょう。

クリッカブルマップのように、X座標とY座標と、幅と高さを指定し、そこにクリックされたときのアクションを割り当てます。以下のアクションを選択して設定します。
・ポストバックアクション
・メッセージアクション
・URIアクション
・日時選択アクション
入力した範囲(X座標とY座標と幅と高さ)は、画像内に四角枠で示すようにしています。

また、何のリッチメニューを登録したか忘れてしまうので、すでに登録済みのリッチメニューや画像ファイルを参照できるようにしておきました。また、すでに登録済みのリッチメニューから複製して編集登録できるようにもしておきました。

以下の部分は、立ち上げたNode.jsサーバのURLに変えてください。

```js:public\linebot-richmenu-edit\js\start.js
const base_url = "【Node.jsサーバのURL】";
```

#終わりに

LINEBotに関する投稿に関しては、以下も参考にしてください。LINEボットサーバを立ち上げる手順を示しています。
　[LINEボットを立ち上げるまで。LINEビーコンも。](https://qiita.com/poruruba/items/c71c96ca83c7403c2930)


以上