【GAS/LINE】リッチメニューをMessaging APIで作りてぇ…!

こんにちは、luthです
ノンプログラマーですが、仕事でも、
GAS(Google App Script)で軽いツール(ほぼオモチャ)をいくつか導入して、
面倒をなくそうと日々奮闘中です

で、家庭内でもオモチャを導入しようと、
お手軽導入のGAS × LINEでbot作りに励む中、
いくつか壁に当たった箇所が…

一つが、「リッチメニューをGASから作る」方法

ユーザーがリッチメニューをタップした時にリッチメニューを別のものに切り替えたり、
事前にタップ領域の値を関数で仕込んでおいたり、
規定のタップ領域でない大きさを設定したりと、
Messaging APIで作るリッチメニューには付加価値が多いです!


他の多くの記事でやるような
「公式アカウント側」から作成する手法ではなく!
今回は、GASからリッチメニューを作る方法を、
サンプルコードと共にご紹介します!

リッチメニューをGASから作りてぇ!

今回想定する流れは...
リッチメニュー作成・ID取得

確認

リッチメニューに画像ファイルを紐付け

ユーザー1人にリッチメニューを紐付け

>> これでリッチメニュー表示可能に <<


ユーザーとリッチメニューの紐付き解除

リッチメニューの削除

公式リファレンスにはGAS用のサンプルコードはないですが、参考にしつつ…

また、こちらのコードも参考にさせていただきました

*GitHubにも公開中

//以下の変数を前提としている
//同じスクリプトプロジェクト内に記述

var url_richmenu = 'https://api.line.me/v2/bot/richmenu';
var url_richmenu_data = 'https://api-data.line.me/v2/bot/richmenu/';
var url_user = 'https://api.line.me/v2/bot/user';

//以下にLINE MessagingAPIのアクセストークンを記述
var access_token = { /*LINE Developers アクセストークン*/ };

まずはリッチメニュー作成

/**
 * リッチメニューを作成し、固有IDを返す
 * タップ領域は、全体2500*1686px、6分割での例
 * また、タップ領域のサイズ・アクション例を2つ載せている
 * 
 * @return {Object} json.richMenuId - LINEから返されたリッチメニュー固有のID
 */
function makeRichmenu_largeSize({
  var url = url_richmenu;

  var areas = [];

  //タップ領域の例 その1
  areas[0] = {

    //領域の大きさ
    'bounds': {

      //左から0px地点から
      'x'0,

      //上から0px地点から
      'y'0,

      //幅833px
      'width'833,

      //高さ843px
      'height'843,
    },

    var now = new Date();
    var time = Utilities.formatDate(now, 'JST'"HH:mm");
    var nextYear = now.setFullYear(now.getFullYear() + 1);

    //ユーザがタップ時のアクション
    'action': {
      //メッセージアクション
      'type''message',

      //ユーザがタップ時に、botへ送信する内容
      'text''おなかすいた、もう' + time + 'だよー',
    }
  };

  areas[1] = { /*...*/ };
  areas[2] = { /*...*/ };
  areas[3] = { /*...*/ };
  areas[4] = { /*...*/ };

  //タップ領域の例 その2
  areas[5] = {

    //領域の大きさ
    'bounds': {

      //左から1666px地点から
      'x'1666,

      //上から843px地点から
      'y'843,

      //幅834px
      'width'834,

      //高さ843px
      'height'843,
    },

    //ユーザがタップ時のアクション
    'action': {

      //日時選択アクション
      'type''datetimepicker',

      //ユーザがタップ時に、botへ送信するポストバックイベントとしてのラベル
      //GAS側で検索キーとして利用できる
      'data''keyword',

      //モード datetimeで「日付+時間」
      'mode''datetime',

      //(省略可)初期値 形式は"YYYY-MM-dd'T'HH:mm"で
      'initial': Utilities.formatDate(now, 'JST'"YYYY-MM-dd'T'HH:mm"),

      //(省略可)許容する最大値 形式は"YYYY-MM-dd'T'HH:mm"で
      'max': Utilities.formatDate(nextYear, 'JST'"YYYY-MM-dd'T'HH:mm"),

      //(省略可)許容する最小値 形式は"YYYY-MM-dd'T'HH:mm"で
      'min': Utilities.formatDate(now, 'JST'"YYYY-MM-dd'T'HH:mm"),
    }
  };

  var postData = {

    //タップ領域全体のサイズ
    'size': {

      //幅2500pxで
      'width'2500,

      //高さ1686pxで
      'height'1686,
    },

    //デフォルトのリッチメニューにするかどうか
    'selected'false,

    //リッチメニュー管理用の名前 ユーザには非公開
    'name': { /*リッチメニュー名*/ },

    //トークルームメニューに表示されるテキスト
    'chatBarText': { /*メニュー*/ },

    //タップ領域群
    'areas': areas,
  };

  var headers = {
    'Content-Type''application/json; charset=UTF-8',
    'Authorization''Bearer ' + access_token,
  };

  var options = {
    'method''post',
    'headers': headers,
    'payload'JSON.stringify(postData),
  };

  var json = UrlFetchApp.fetch(url, options);
  json = JSON.parse(json);
  return json.richMenuId;
}

なお、作成したリッチメニュー内の値(new Date()で作った日付とか)は、
あくまで「リッチメニュー作成時点」で算出される値であり、
「リッチメニューをタップした時点」ではないのでご注意を!

作成が成功すると、LINEからのリターン(上記での変数json)はparseすると以下のような連想配列になっています

richMenuId/* リッチメニュー固有のID文字列 */ }

作ったリッチメニューを確認

まずは確認から

/**
 * MessagingAPIから作成したリッチメニューを取得
 * 
 * @return {Object} json - 取得したリッチメニュー一覧
 */
function getRichmenus({
  var url = url_richmenu + '/list';

  var headers = {
    'Authorization''Bearer ' + access_token,
  };

  var options = {
    'method''get',
    'headers': headers,
  };

  var json = UrlFetchApp.fetch(url, options);
  json = JSON.parse(json);
  return json;
}

LINEからは、以下のように返ってきます

{
  "richmenus": [
    {
      "richMenuId"" /* リッチメニュー固有のID文字列 */ ",
      "size": {
        "width"2500,
        "height"1686
      },
      "selected"false,
      "name""なまえ",
      "chatBarText""めにゅー",
      "areas": [
        {
          "bounds": {
            "x"0,
            "y"0,
            "width"2500,
            "height"1686
          },
          "action": {
            "type""message",
            "text""てきすと"
          }
        }
      ]
    }
  ]
}

画像ファイルを紐付け

今回は、既にGoogle Driveにアップロード済の画像ファイルを利用する前提で進めます
ファイルサイズや最低幅などを守れていないファイルだと弾かれるので、要注意!

また、画像ファイルは一度リッチメニューに設定すると、
上書きアップロードできない仕様なので、
リッチメニューに紐付ける画像ファイルを変える際は、
リッチメニューを作り直すところからになります

リッチメニューIDは作成用関数や、確認用関数から取得してくださいね

GoogleDriveのファイルIDはファイルの共有リンクにあります
「https://drive.google.com/file/d/<ファイルID>/view?usp=sharing」
「https://drive.google.com/open?id=<ファイルID>

/**
 * 作成済リッチメニューに画像ファイルを紐づけ
 * GoogleDriveに格納している画像ファイルを、PNGファイルとしてアップロードする例
 * 
 * @param {string} richmenuId - リッチメニュー固有のID
 * @param {string} drive_fileId - GoogleDriveのファイルID
 * @return {Object} json - 結果
 */
function setImage_Richmenu(richmenuId, drive_fileId) {
  var url = url_richmenu_data + '/' + richmenuId + '/content';

  //GoogleDriveからファイルIDで画像ファイルを開く
  var image = DriveApp.getFileById(drive_fileId);

  //開いた画像ファイルをPNG形式・BLOBに変換
  var blob = image.getAs(MimeType.PNG);

  var headers = {
    'Content-Type''image/png',
    'Authorization''Bearer ' + access_token,
  };

  var options = {
    'method''post',
    'headers': headers,

    //payloadにBLOBをそのまま乗せる
    'payload': blob,
  };

  var json = UrlFetchApp.fetch(url, options);
  json = JSON.parse(json);
  return json;
}

作成したリッチメニューを、特定ユーザーにセット

画像ファイルまで紐付けられれば、ユーザーに設定できるようになります
事前に、リッチメニューIDと、LINEユーザー固有のIDを取得しておきましょう!

なお、リッチメニューの表示優先度は以下の通りです

リッチメニューの表示優先順位は高い順に以下のとおりです。
1. Messaging APIで設定するユーザー単位のリッチメニュー
2. Messaging APIで設定するデフォルトのリッチメニュー
3. LINE Official Account Managerで設定するデフォルトのリッチメニュー
(LINE Messaging API 公式リファレンスより)

今回の「ユーザーに紐づけるリッチメニュー」は、上記の1. に当たります

/**
 * リッチメニューを特定のユーザ1人にセット、即時で反映される
 * 
 * @param {string} uid - LINEユーザ固有のID
 * @param {string} richmenuId - リッチメニュー固有のID
 * @return {Object} json - 結果
 */
function setRichmenu_toOneUser(uid, richmenuId) {
  var url = url_user + '/' + uid + '/richmenu/' + richmenuId;

  var headers = {
    'Authorization''Bearer ' + access_token,
  };

  var options = {
    'method''post',
    'headers': headers,
  };

  var json = UrlFetchApp.fetch(url, options);
  json = JSON.parse(json);
  return json;
}

ユーザーに紐付くリッチメニューを確認

LINEユーザーにリッチメニューを紐づけられたか確認するには、
ユーザーに紐付くリッチメニューIDを取得します

/**
 * 特定のユーザ1人にセットされているリッチメニューを取得
 * 
 * @param {string} uid - LINEユーザ固有のID
 * @return {Object} json.richMemuId - 紐付いているリッチメニューID
 */
function getRichmenu_ofOneUser(uid) {
  var url = url_user + '/' + uid + '/richmenu/';

  var headers = {
    'Authorization''Bearer ' + access_token,
  };

  var options = {
    'method''get',
    'headers': headers,
  };

  var json = UrlFetchApp.fetch(url, options);
  json = JSON.parse(json);
  return json.richMemuId;
}

LINEからはこんなレスポンスがJSONで来ます

richMenuId/* リッチメニュー固有のID文字列 */ }

特定ユーザーに紐付けたリッチメニューの、紐付き解除をする

リッチメニューの紐付きを解除するのみで、
リッチメニュー自体は残ります

/**
 * 特定のユーザ1人にセットしているリッチメニューを解除、即時で反映される
 * 
 * @param {string} uid - LINEユーザ固有のID
 * @return {Object} json - 結果
 */
function releaseRichmenu_fromUser(uid) {
  var url = url_user + '/' + uid + '/richmenu';

  var headers = {
    'Authorization''Bearer ' + access_token,
  };

  var options = {
    'method''delete',
    'headers': headers,
  };

  var json = UrlFetchApp.fetch(url, options);
  json = JSON.parse(json);
  return json;
}

リッチメニューを削除

特定のリッチメニューをIDで指定して削除します

/**
 * リッチメニューを削除
 * 特定ユーザに紐づけている場合は、ユーザが再度トークルームに入室した際に反映
 * 
 * @param {string} richmenuId - リッチメニュー固有のID
 * @return {Object} json - 結果
 */
function deleteRichmenu(richmenuId) {
  var url = url_richmenu + '/' + richmenuId;

  var headers = {
    'Authorization''Bearer ' + access_token,
  };

  var options = {
    'method''delete',
    'headers': headers,
  };

  var json = UrlFetchApp.fetch(url, options);
  json = JSON.parse(json);
  return json;
}


いかがでしたでしょうか
今回紹介しなかったリッチメニュー向け機能も、
Messaging APIの公式リファレンスと、
上記スクリプトの転用で作れると思います


さ、もっと生活から面倒をなくさなきゃ…

この記事が気に入ったらサポートをしてみませんか?