質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
LINE Messaging API

LINE Messaging APIは、メッセージの送信・返信ができるAPIです。Web APIを経由しアプリケーションサーバとLINEのAPIでやり取りが可能。複数のメッセージタイプや分かりやすいAPIリファレンスを持ち、グループチャットにも対応しています。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

Q&A

解決済

1回答

2606閲覧

Google Apps Script で LINE のリッチメニューを作成したい

yes___me___

総合スコア1

LINE Messaging API

LINE Messaging APIは、メッセージの送信・返信ができるAPIです。Web APIを経由しアプリケーションサーバとLINEのAPIでやり取りが可能。複数のメッセージタイプや分かりやすいAPIリファレンスを持ち、グループチャットにも対応しています。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

0グッド

0クリップ

投稿2022/12/30 14:19

編集2022/12/30 14:21

前提

Google Apps Scripts で LINE Bot を作っています。
リッチメニューを Messaging API で作成したいです.
LINE のリッチメニューの実装中に以下のエラーメッセージが発生しました。

実現したいこと

  • リッチメニューを width 2500px , height 843px のサイズでリッチメニュー(1つ)を作成

ただし,リッチメニューの個数は1つとしています.

発生している問題・エラーメッセージ

エラーメッセージ Exception: Request failed for https://api.line.me returned code 400. Truncated server response: {"message":"must upload richmenu image before applying it to user","details":[]}

該当のソースコード

GoogleAppsScript

1function createRichMenu(){ 2 var url = 'https://api.line.me/v2/bot/richmenu'; 3 4 var areas = []; 5 6 //タップ領域の例 その1 7 areas[0] = { 8 9 //領域の大きさ 10 'bounds': { 11 12 //左から0px地点から 13 'x': 0, 14 15 //上から0px地点から 16 'y': 0, 17 18 //幅2500px 19 'width': 2500, 20 21 //高さ843px 22 'height': 843, 23 }, 24 25 //ユーザがタップ時のアクション 26 'action': { 27 //メッセージアクション 28 'type': 'message', 29 30 //ユーザがタップ時に、botへ送信する内容 31 'text': '在室確認', 32 } 33 }; 34 35 var postData = { 36 37 //タップ領域全体のサイズ 38 'size': { 39 40 //幅2500pxで 41 'width': 2500, 42 43 //高さ843pxで 44 'height': 843, 45 }, 46 47 //デフォルトのリッチメニューにするかどうか 48 'selected': true, 49 50 //リッチメニュー管理用の名前 ユーザには非公開 51 'name': '在室管理' , 52 53 //トークルームメニューに表示されるテキスト 54 'chatBarText': 'MENU' , 55 56 //タップ領域群 57 'areas': areas, 58 }; 59 60 var headers = { 61 'Content-Type': 'application/json', 62 'Authorization': 'Bearer ' + ACCESS_TOKEN, 63 }; 64 65 var options = { 66 'method': 'post', 67 'headers': headers, 68 'payload': JSON.stringify(postData), 69 }; 70 71 var json = UrlFetchApp.fetch(url, options); 72 json = JSON.parse(json); 73 return json.richMenuId; 74} 75let response = createRichMenu(); 76console.log(response); 77 78function setImage_Richmenu() { 79 var richmenu_Id = response; 80 var url = ' https://api-data.line.me/v2/bot/richmenu/' + richmenu_Id + '/content'; 81 82 //GoogleDriveからファイルIDで画像ファイルを開く 83 var image = DriveApp.getFileById(drive_fileId); 84 85 //開いた画像ファイルをPNG形式・BLOBに変換 86 var blob = image.getAs(MimeType.PNG); 87 88 var headers = { 89 'Content-Type': 'image/png', 90 'Authorization': 'Bearer ' + ACCESS_TOKEN, 91 }; 92 93 var options = { 94 'method': 'post', 95 'headers': headers, 96 97 //payloadにBLOBをそのまま乗せる 98 'payload': blob, 99 }; 100 101 var json = UrlFetchApp.fetch(url, options); 102 json = JSON.parse(json); 103} 104console.log('finish!'); 105 106function getRichmenu(){ 107 var richmenu_Id = response; 108 var url = 'https://api.line.me/v2/bot/user/all/richmenu/' + richmenu_Id; 109 var headers = { 110 'Authorization': 'Bearer ' + ACCESS_TOKEN, 111 }; 112 113 var options = { 114 'method' : 'post', 115 'headers': headers, 116 }; 117 118 var json = UrlFetchApp.fetch(url, options); 119 json = JSON.parse(json); 120 121} 122

試したこと

下記のサイトを基に制作しました.
https://note.com/luth/n/ne6d340cec623

リッチメニューの ID が実行するごとに変わるのでオブジェクトとして設定しましたが,うまくいきませんでした.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

おそらく、それぞれの関数を1回1回別個に実行しており、そのうち「 getRichmenu 」をエディタで実行した場合に上記のエラーが出て「登録できない」と悩まれているのだと推測します。

エラーが発生する原因

エディタ上で getRichmenu を指定して実行した時の処理の流れは、下記のようになっています。
ポイントは、75・76行目が関数の外にある点です。
① 最初に、75行目 の let response = createRichMenu() が実行され、リッチメニューのレイアウトがアップロードされます。そして createRichMenu 関数からリッチメニューのIDが返され、グローバルスコープで宣言された変数 response に格納されます。

② 76行目が実行され、リッチメニューのIDがコンソールに表示されます。

③ 104行目が実行され、「finish!」という文字列がコンソールに表示されます。

④ getRichmenu 関数本体が実行されます。(登録したリッチメニューをユーザーに紐付ける処理)


→ しかし、④を実行する時点では、① で発行したリッチメニューIDに紐づいた画像データがアップロードされていません。この結果、質問文にあるようなエラーが発生します。
getRichmenu を実行する前に、setImage_Richmenu 関数をエディタから実行されているかもしれません。
しかし、リッチメニューID は https://api.line.me/v2/bot/richmenu への POST 毎に異なるIDが発行されます
すなわち、getRichmenu 関数を実行したときに75行目で発行されるリッチメニューIDと、setImage_Richmenu を実行したときに75行目で発行されるリッチメニューIDは別のIDになるため、各関数を別々に実行するとうまく設定できません。

対応

各関数を別々に実行する場合は、console に表示されるリッチメニューIDをコピペして、コードに直接貼り付けて実行するという運用でもよいですが、面倒だと思います。
別案として、リッチメニューの登録から画像アップロード、ユーザー設定まで一括して行うやり方が考えられます。

コード例

createRichMenu

setImage_Richmenu

getRichmenu
の各関数を main という関数にまとめ、1つの実行フェーズ内で順番に実行するようにします。それぞれの関数に、取得したリッチメニューIDを引数として渡すことで、リッチメニューIDの整合性がとれるようにしています。

(関数外にある 75・76行目は削除)
(質問文内のコード 80行目 URLの先頭にある半角スペースを削除)
(その他細かいところを修正しています)

実行する際は、エディタから main 関数を指定して実行してください。main以外の関数(createRichMenu や setImage_Richmenu など)を個別に実行する必要はありません。

js

1const drive_fileId = '**********'; // メニューに使用する画像ファイルのIDを指定 2const ACCESS_TOKEN = '***********'; // bot のアクセストークンを指定 3 4function main() { 5 try { 6 const richMenu_Id = createRichMenu(); 7 setImage_Richmenu(richMenu_Id); 8 getRichmenu(richMenu_Id); 9 } catch (e) { 10 console.log(e.stack); 11 } 12} 13 14function createRichMenu() { 15 var url = 'https://api.line.me/v2/bot/richmenu'; 16 17 var areas = []; 18 19 //タップ領域の例 その1 20 areas[0] = { 21 22 //領域の大きさ 23 'bounds': { 24 25 //左から0px地点から 26 'x': 0, 27 28 //上から0px地点から 29 'y': 0, 30 31 //幅2500px 32 'width': 2500, 33 34 //高さ843px 35 'height': 843, 36 }, 37 38 //ユーザがタップ時のアクション 39 'action': { 40 //メッセージアクション 41 'type': 'message', 42 43 //ユーザがタップ時に、botへ送信する内容 44 'text': '在室確認', 45 } 46 }; 47 48 var postData = { 49 50 //タップ領域全体のサイズ 51 'size': { 52 53 //幅2500pxで 54 'width': 2500, 55 56 //高さ843pxで 57 'height': 843, 58 }, 59 60 //デフォルトのリッチメニューにするかどうか 61 'selected': true, 62 63 //リッチメニュー管理用の名前 ユーザには非公開 64 'name': '在室管理', 65 66 //トークルームメニューに表示されるテキスト 67 'chatBarText': 'MENU', 68 69 //タップ領域群 70 'areas': areas, 71 }; 72 73 var headers = { 74 'Content-Type': 'application/json', 75 'Authorization': 'Bearer ' + ACCESS_TOKEN, 76 }; 77 78 var options = { 79 'method': 'post', 80 'headers': headers, 81 'muteHttpExceptions': true, 82 'payload': JSON.stringify(postData), 83 }; 84 var json = UrlFetchApp.fetch(url, options); 85 if (json.getResponseCode() !== 200) { 86 throw new Error(json.getContentText()); 87 } 88 89 json = JSON.parse(json); 90 console.log('リッチメニューの登録が完了しました。') 91 console.log(`richmenuId:${json.richMenuId}`) 92 return json.richMenuId; 93} 94 95//let response = createRichMenu(); //関数内に移動のため削除 96//console.log(response); //関数内に移動のため削除 97 98function setImage_Richmenu(richmenu_Id) { //引数を追加 99 100 // var richmenu_Id = response; // 削除 101 var url = 'https://api-data.line.me/v2/bot/richmenu/' + richmenu_Id + '/content'; // URL の先頭のスペース削除 102 103 //GoogleDriveからファイルIDで画像ファイルを開く 104 var image = DriveApp.getFileById(drive_fileId); 105 106 //開いた画像ファイルをPNG形式・BLOBに変換 107 var blob = image.getAs(MimeType.PNG); 108 109 var headers = { 110 'Content-Type': 'image/png', 111 'Authorization': 'Bearer ' + ACCESS_TOKEN, 112 }; 113 114 var options = { 115 'method': 'post', 116 'headers': headers, 117 'muteHttpExceptions': true, 118 //payloadにBLOBをそのまま乗せる 119 'payload': blob, 120 }; 121 var json = UrlFetchApp.fetch(url, options); 122 if (json.getResponseCode() !== 200) { 123 throw new Error(json.getContentText()); 124 } 125 126 console.log('画像のアップロードが完了しました。'); 127} 128// console.log('finish!'); 削除 129 130function getRichmenu(richmenu_Id) { // 引数追加 131 // var richmenu_Id = response; // 削除 132 var url = 'https://api.line.me/v2/bot/user/all/richmenu/' + richmenu_Id; 133 var headers = { 134 'Authorization': 'Bearer ' + ACCESS_TOKEN, 135 }; 136 137 var options = { 138 'method': 'post', 139 'headers': headers, 140 'muteHttpExceptions': true, 141 }; 142 143 var json = UrlFetchApp.fetch(url, options); 144 if (json.getResponseCode() !== 200) { 145 throw new Error(json.getContentText()); 146 } 147 148 console.log('リッチメニューの設定が完了しました。'); 149}

投稿2022/12/31 10:14

編集2023/01/02 03:36
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yes___me___

2022/12/31 23:14 編集

qnoir 様 丁寧にご回答いただきまして誠にありがとうございます. 別々に関数を動かしてしまったためにうまく回せなかったことをご教示いただき,改善したところ実際にリッチメニューを作成することができました.また,エラー処理の対応まで付け加えていただきありがとうございました. リッチメニューの ID についてしっかり把握できていなかったことに原因がありました. 不躾な質問にご対応いただきましてありがとうございました.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問