LINE Messaging APIのリッチメニューを操作するためのAPIが公開されました。リッチメニューを自由自在かつ用途に応じてダイナミックに変更できるなど、超絶進化を遂げたので使わない手はありません。
(公式)リッチメニューを使う - LINE Developers
https://developers.line.me/ja/docs/messaging-api/using-rich-menus/
さて、このAPIの使い方は上のURLの通りなのですが、ちょうどPythonの実装作って試してみたのと公式SDKにまだ含まれていなかったので、せっかくなので公開します。例外処理などは一切行っていませんので、その辺は適宜やっていただければと。
GitHubにも放流しました。コード見ればわかるという方はこちらからでも。
https://github.com/uezo/richmenu
依存ライブラリのインポート
ユーティリティクラス用にrichmenu.py
を作成したら、json
とrequests
をimportします。LINEのSDKは使っていません。
import json
import requests
リッチメニューのデータモデルの作成
そんなに複雑じゃないのでクラスを作らなくてもいいかな・・・と思ったのですが、エリアを追加するとき見やすい方がいいので、そのためのadd_area
を備えた以下のクラスを作成します。
class RichMenu:
def __init__(self, name, chat_bar_text, size_full=True, selected=False):
self.size = {"width": 2500, "height": 1686}
if not size_full:
self.size["height"] = 843
self.selected = selected
self.name = name
self.chat_bar_text = chat_bar_text
self.areas = []
def add_area(self, x, y, width, height, action_type, payload):
bounds = {"x": x, "y": y, "width": width, "height": height}
action = {"type": action_type}
if action_type == "postback":
if isinstance(payload, list):
action["data"] = payload[0]
if len(payload) > 1:
action["text"] = payload[1]
else:
action["data"] = payload
elif action_type == "uri":
action["uri"] = payload
else:
action["text"] = payload
self.areas.append({"bounds": bounds, "action": action})
def to_json(self):
dic = {"size": self.size, "selected": self.selected, "name": self.name, "chatBarText": self.chat_bar_text, "areas": self.areas}
return json.dumps(dic)
リッチメニュー操作用クラスの作成
APIの操作は一通りラッピングしているはずです。リッチメニューの登録は生のAPIだとメニューの定義の登録→画像のアップロード・・・と2段階になりますが、せっかくなのでregister
メソッド一発で登録できるようにしました。あと、テスト用にたくさん登録すると削除が面倒なので、一括削除のremove_all
メソッドも用意しておきましたのでご利用ください。
class RichMenuManager:
def __init__(self, channel_access_token, verify=True):
self.headers = {"Authorization": "Bearer {%s}" % channel_access_token}
self.verify = verify
def register(self, rich_menu, image_path=None):
url = "https://api.line.me/v2/bot/richmenu"
res = requests.post(url, headers=dict(self.headers, **{"content-type": "application/json"}), data=rich_menu.to_json(), verify=self.verify).json()
if image_path:
self.upload_image(res["richMenuId"], image_path)
return res
def upload_image(self, rich_menu_id, image_path):
url = "https://api.line.me/v2/bot/richmenu/%s/content" % rich_menu_id
image_file = open(image_path, "rb")
return requests.post(url, headers=dict(self.headers, **{"content-type": "image/jpeg"}), data=image_file, verify=self.verify).json()
def download_image(self, richmenu_id, filename=None):
url = "https://api.line.me/v2/bot/richmenu/%s/content" % richmenu_id
res = requests.get(url, headers=self.headers, verify=self.verify)
if filename:
with open(filename, "wb") as f:
f.write(res.content)
else:
return res.content
def get_list(self):
url = "https://api.line.me/v2/bot/richmenu/list"
return requests.get(url, headers=self.headers, verify=self.verify).json()
def remove(self, richmenu_id):
url = "https://api.line.me/v2/bot/richmenu/%s" % richmenu_id
return requests.delete(url, headers=self.headers, verify=self.verify).json()
def remove_all(self):
menus = self.get_list()
for m in menus["richmenus"]:
self.remove(m["richMenuId"])
def apply(self, user_id, richmenu_id):
url = "https://api.line.me/v2/bot/user/%s/richmenu/%s" % (user_id, richmenu_id)
return requests.post(url, headers=self.headers, verify=self.verify).json()
def detach(self, user_id):
url = "https://api.line.me/v2/bot/user/%s/richmenu" % user_id
return requests.delete(url, headers=self.headers, verify=self.verify).json()
def get_applied_menu(self, user_id):
url = "https://api.line.me/v2/bot/user/%s/richmenu" % user_id
return requests.get(url, headers=self.headers, verify=self.verify).json()
使ってみる
事前にLINE DevelopersでChannel Access Tokenを確認しておくのと、LINE@Managerでリッチメニューを有効にしておく必要があるようです。準備が整ったらexample.py
を作成して先ほど作ったクラスをimportします。
from richmenu import RichMenu, RichMenuManager
次に、チャネルアクセストークンを使ってRichMenuManagerのインスタンスを生成。もしrequestsのバージョンが古いなどでSSL関連のエラーが出る場合は、コンストラクタの第2引数にverify=False
を渡して見てください。(自己責任でお願いします)
# Setup RichMenuManager
channel_access_token = "YOUR_CHANNEL_ACCESS_TOKEN"
rmm = RichMenuManager(channel_access_token)
続いて、リッチメニューの定義を作成します。上下に4分割して、テキスト、URL、ポストバック、ポストバック(メッセージつき)の4種類のアクションを実行するエリアを作成しました。
# Setup RichMenu to register
rm = RichMenu(name="Test menu", chat_bar_text="Open this menu")
rm.add_area(0, 0, 1250, 843, "message", "テキストメッセージ")
rm.add_area(1250, 0, 1250, 843, "uri", "http://imoutobot.com")
rm.add_area(0, 843, 1250, 843, "postback", "data1=from_richmenu&data2=as_postback")
rm.add_area(1250, 843, 1250, 843, "postback", ["data3=from_richmenu_with&data4=message_text", "ポストバックのメッセージ"])
ここまできたらいよいよLINEにリッチメニューを登録します。この段階ではまだ登録されるだけでどのユーザーにも表示されませんのでご安心ください。また、実行前にメニューの画像を準備するのをお忘れなく。なおこの画像はきっかり2500*1686 or 843じゃないとダメで、自動で拡大してくれません。
# Register
res = rmm.register(rm, "/path/to/menu.png")
richmenu_id = res["richMenuId"]
print("Registered as " + richmenu_id)
リッチメニューIDが取得できたら成功です。最後にユーザーに紐付けすることで、直ちにユーザーの画面に反映されます。これは本当に「直ちに」で、APIを呼び出した瞬間に画面が切り替わるので見ていておおってなります。
# Apply to user
user_id = "LINE_MID_TO_APPLY"
rmm.apply(user_id, richmenu_id)
自分のアカウントであれば画面で確認できますが、他人のアカウントにちゃんと反映できたかは以下で確認できます。
# Check
res = rmm.get_applied_menu(user_id)
print(user_id + ":" + res["richMenuId"])
その他、登録済みメニュー一括取得、メニュー画像のダウンロード、適用解除、削除、登録済みメニュー一括削除は以下のように呼び出すことができます。
# Others
res = rmm.get_list()
rmm.download_image(richmenu_id, "/path/to/downloaded_image.png")
res = rmm.detach(user_id)
res = rmm.remove(richmenu_id)
rmm.remove_all()
おわりに
リッチメニューを動的に切り替えるようなLINE BOTはまだあまり見たことがないので、それだけでもお友達に差をつけられるかもしれませんね。ただ、以下のような要検討事項があると思いますので、よくUXを試してみる必要がありそうです。
- 動的に変更しても、元の状態に戻すトリガーが発生するとは限らない(途中で会話を放棄とか)
- どのユーザーにどのメニューが適用されているかは自身で管理が必要
それでは、エンジョイLINEBOT開発!