こんにちは!アナログな町内会運営を変えるべく、「GASで機能拡張した町内会公式LINE」を作りました。たくさんの記事を参考にしながら、オープンソースの文化に触れる中で、助け合いの大切さを実感しつつ、ようやく完成させることができました。
Pay forwardの精神で、これから町内会LINEに追加した機能をシリーズで紹介していきます。初心者なので完璧なコードではないかもしれませんが、少しでも役に立てば嬉しいです!
なお、ブログ通りに作業してもうまく動かない方のために、「ココナラ」でサポートを提供しています。良かったらご覧くださいね♪
今回は複合リッチメニューつまり、タブ付きリッチメニューをGASを用いて実装する方法について紹介する前編です。
参考元:【プログラム配布用】リッチメニューの自由分割&タブ切り替えを実装するチュートリアル【LINE公式アカウント / Messaging API】
Google Apps Script にライブラリを追加しよう
LINE Bot SDKをプロジェクトに組み込み、使える状態にします。
SDKとはソフトウェアを開発するために必要な技術文書やツールなど一式のことで、始めから用意された便利なクラスなどを用いて面倒なコードを書くことなく分かりやすく、簡単にLINE Botの持つ機能にコードからアクセスできるようになります。
ライブラリを追加
→ ライブラリのスクリプトID 参考元より
1KsjhQa6oymhUiACWsAlFTG_XoN8Pnz4px2ekABPjO4tSMX6xRSQMBicy
を入力して検索すると「LineBotSdk」が表示されます。
最新のバージョン(2024/7/14現在はver37)を追加します。
大切なお知らせ:当初、シリーズ「②Google Apps Scriptをさわってみよう」 にてライブラリの紹介をしていましたが、紹介したライブラリのIDが誤っておりました。
もし、2024/7/14以前にLineBotSDK(語尾が大文字)のライブラリを追加された方は、一旦ライブラリを削除し、新たにこちらのLineBotSdk(語尾が小文字)を追加してください。
リッチメニュー用のスクリプトを新規作成
前回使用したスプレッドシートからGoogleAppsを開き、新しいスクリプトを作成します。
以下のコードを入力します。ちょっと行数が多いので、二つに分けて示しますね。
同じスクリプト内に続けて入力してください。
①createRichMenuA,B,C
const bot = new LineBotSdk.client(PropertiesService.getScriptProperties().getProperty('LINEb_TOKEN'));
function createRichMenuA() {
let richmenu = bot.richmenu({
"name": "オリジナルリッチメニュー",
"barText": "メニュー",
"size": { "width": 2500, "height": 1686 },
"selected": true,
"areas": [
bot.area({ "x": 0, "y": 0, "width": 833, "height": 336,
"action": bot.aSwitch({"aliasId": "switch-to-a", "data": "change to A"}) }),
bot.area({ "x": 833, "y": 0, "width": 833, "height": 336,
"action": bot.aSwitch({"aliasId": "switch-to-b", "data": "change to B"}) }),
bot.area({"x": 1667, "y": 0, "width": 833, "height": 336,
"action": bot.aSwitch({"aliasId": "switch-to-c", "data": "change to C"}) }),
bot.area({ "x": 0, "y": 337, "width": 833, "height": 674,
"action": bot.aMessage({"text": 'アンケート' }) }),
bot.area({ "x": 833, "y": 337, "width": 833, "height": 674,
"action": bot.aMessage({"text": 'つかいかた' }) }),
bot.area({"x": 1667, "y": 337, "width": 833, "height": 674,
"action": bot.aMessage({"text": "コミュニティバス"}) }),
bot.area({ "x": 0, "y": 1011, "width": 833, "height": 674,
"action": bot.aMessage({"text": "閲覧"}) }),
bot.area({ "x": 833, "y": 1011, "width": 833, "height": 674,
"action": bot.aMessage({"text": "ごみ収集日一覧"}) }),
bot.area({"x": 1667, "y": 1011, "width": 833, "height": 674,
"action": bot.aMessage({"text": "イベントカレンダー"}) }),
]
})
let res = bot.createRichMenu(richmenu);
console.log(res.toString());
}
function createRichMenuB() {
let richmenu = bot.richmenu({
"name": "オリジナルリッチメニュー",
"barText": "メニュー",
"size": { "width": 2500, "height": 1686 },
"selected": true,
"areas": [
bot.area({ "x": 0, "y": 0, "width": 833, "height": 336,
"action": bot.aSwitch({"aliasId": "switch-to-a", "data": "change to A"}) }),
bot.area({ "x": 833, "y": 0, "width": 833, "height": 336,
"action": bot.aSwitch({"aliasId": "switch-to-b", "data": "change to B"}) }),
bot.area({"x": 1667, "y": 0, "width": 833, "height": 336,
"action": bot.aSwitch({"aliasId": "switch-to-c", "data": "change to C"}) }),
bot.area({ "x": 0, "y": 337, "width": 833, "height": 450,
"action": bot.aMessage({"text": "ボタンB-1"}) }),
bot.area({ "x": 833, "y": 337, "width": 833, "height": 450,
"action": bot.aMessage({"text": "ボタンB-2"}) }),
bot.area({"x": 1667, "y": 337, "width": 833, "height": 450,
"action": bot.aMessage({"text": "ボタンB-3"}) }),
bot.area({ "x": 0, "y": 786, "width": 833, "height": 450,
"action": bot.aMessage({"text": "ボタンB-4"}) }),
bot.area({ "x": 833, "y": 786, "width": 833, "height": 450,
"action": bot.aMessage({"text": "ボタンB-5"}) }),
bot.area({"x": 1667, "y": 786, "width": 833, "height": 450,
"action": bot.aMessage({"text": "ボタンB-6"}) }),
bot.area({ "x": 0, "y": 1122, "width": 833, "height": 450,
"action": bot.aMessage({"text": "ボタンB-7"}) }),
bot.area({ "x": 833, "y": 1122, "width": 833, "height": 450,
"action": bot.aMessage({"text": "ボタンB-8"}) }),
bot.area({"x": 1667, "y": 1122, "width": 833, "height": 450,
"action": bot.aMessage({"text": "ボタンB-9"}) }),
]
})
let res = bot.createRichMenu(richmenu);
console.log(res.toString());
}
function createRichMenuC() {
let richmenu = bot.richmenu({
"name": "オリジナルリッチメニュー",
"barText": "メニュー",
"size": { "width": 2500, "height": 1686 },
"selected": true,
"areas": [
bot.area({ "x": 0, "y": 0, "width": 833, "height": 336,
"action": bot.aSwitch({"aliasId": "switch-to-a", "data": "change to A"}) }),
bot.area({ "x": 833, "y": 0, "width": 833, "height": 336,
"action": bot.aSwitch({"aliasId": "switch-to-b", "data": "change to B"}) }),
bot.area({"x": 1667, "y": 0, "width": 833, "height": 336,
"action": bot.aSwitch({"aliasId": "switch-to-c", "data": "change to C"}) }),
bot.area({ "x": 0, "y": 337, "width": 833, "height": 1349,
"action": bot.aMessage({"text": "ボタンC-1"}) }),
bot.area({ "x": 833, "y": 337, "width": 833, "height": 1349,
"action": bot.aMessage({"text": "ボタンC-2"}) }),
bot.area({"x": 1667, "y": 337, "width": 833, "height": 1349,
"action": bot.aMessage({"text": "ボタンC-3"}) }),
]
})
let res = bot.createRichMenu(richmenu);
console.log(res.toString());
}
②createRichMenuArias、updateRichMenuArias、uploadRichmenuImageA、B、C、setDefaultRichMenu
// エイリアス作成
function createRichMenuArias() {
deleteRichMenuArias(); // 既存のエイリアスを削除
bot.createRichMenuArias("switch-to-a", "リッチメニューAのID");
bot.createRichMenuArias("switch-to-b", "リッチメニューBのID");
bot.createRichMenuArias("switch-to-c", "リッチメニューCのID");
}
// エイリアス削除
function deleteRichMenuArias() {
bot.deleteRichMenuArias("switch-to-a");
bot.deleteRichMenuArias("switch-to-b");
bot.deleteRichMenuArias("switch-to-c");
}
// エイリアス変更
// function updateRichMenuArias() {
// bot.updateRichMenuArias("switch-to-a", "リッチメニューAのID");
// bot.updateRichMenuArias("switch-to-b", "リッチメニューBのID");
// bot.updateRichMenuArias("switch-to-c", "リッチメニューCのID");
// }
function uploadRichmenuImageA() {
const file = DriveApp.getFileById("リッチメニューAの画像ID");
const blob = Utilities.newBlob(
file.getBlob().getBytes(),
file.getMimeType(),
file.getName()
);
bot.setRichMenuImage("リッチメニューAのID", blob);
}
function uploadRichmenuImageB() {
const file = DriveApp.getFileById("リッチメニューBの画像ID");
const blob = Utilities.newBlob(
file.getBlob().getBytes(),
file.getMimeType(),
file.getName()
);
bot.setRichMenuImage("リッチメニューBのID", blob);
}
function uploadRichmenuImageC() {
const file = DriveApp.getFileById("リッチメニューCの画像ID");
const blob = Utilities.newBlob(
file.getBlob().getBytes(),
file.getMimeType(),
file.getName()
);
bot.setRichMenuImage("リッチメニューCのID", blob);
}
// デフォルト表示
function setDefaultRichMenu() {
bot.setDefaultRichMenu("リッチメニューAのID");
}
// // デフォルト取り下げ
// function deleteDefaultRichMenu() {
// bot.deleteDefaultRichMenu();
// }
今回、リッチメニューB、Cは各自お好みの項目を設定してください。
現在は、該当のボタンを押すと「ボタン〇-〇」と発言する設定にしてなってます。
この「ボタン〇-〇」に対応するアクションをそれぞれ設定すると、いわゆる「自動応答」ができます。
各リッチメニューのIDを取得しよう
デプロイができたので、リッチメニューのスクリプトに戻ります。
createRichMenuAを実行します。
すると、コンソールに情報:richMenuId:”richmenu- ~ ”が表示されます。
この「richmenu-~」の部分をコピーし、コード内の「リッチメニューAのID」4カ所に貼り付けます。
同様に、createRichMenuB、createRichMenuCを実行し、それぞれ3カ所に貼り付けます。
「デプロイ」しよう
「デプロイ(Deploy)」には「配備する、展開する」という意味があり、IT業界で「デプロイ」というと、「実行ファイルをサーバ上に配置し、システムをユーザが利用できる状態にすること」を指します。
デプロイとは【3分でわかる】ビルドやリリースとの違い|IT用語
作成したリッチメニューをLINEのデフォルト画面に反映させるということは、ザックリ言うと「LINEの画面(=webページ)に反映させる」ということです。
Webページとして閲覧できるようにするためには、「デプロイ」という作成したスクリプトに対してWebアプリURLを発行する作業が必要です。
WebアプリURLを発行することでこのWebページにアクセスできるようになります。
新しいデプロイ
右上の「デプロイ」→「新しいデプロイ」を開きます。
種類の選択右の歯車アイコンからウェブアプリを選択
アクセスできるユーザー:全員 を選択し、デプロイ。
ウェブアプリのURLをコピー
→ LINE Developersの自身のチャネル
→ Webhook設定でWebhook URLにペースト
→ 更新
→ Webhookの利用 ON
これでOK!
まとめ
今回は新たなスクリプトの作成に伴い、ライブラリの追加とWebhookの設定を行いました。
今後、ウェブページに関するスクリプトの変更を反映しようとするたびに「デプロイ」の更新が必要になりますので、頭の片隅に覚えておいてくださいね!
次回は後編として前回作成したリッチメニュー画像を紐づけ、LINEの画面に反映させる作業を行います。
どうぞお楽しみに!