Help us understand the problem. What is going on with this article?

GoogleスプレッドシートにあるURLをLIFF化する

概要

今まで手作業でLINE Developer portalからLIFFを作成していたのですが、効率化+複数人管理対応のためにスプレッドシート管理にしたよ、という記事です

背景

社会人バドミントンサークルをLINE公式アカウントを利用して運営しており、集客の仕組みでLIFFを利用しています。
これまでのフローでは、主催者(私)が練習申し込み用のWebアプリから練習会を設定し、URLを発行します。URLは?date=2020-01-01のようにパラメータで管理され、それをダッシュボードから手動でLIFF化して利用していました。

今までそのフローで何とかやっていたのですが、自分のコミットが保証できなくなってきたことに伴い運営メンバーを追加したことで、作業を自動化しつつ誰でもできるようにする必要が出てきました。そこで今回はスプレッドシートを利用して、作成する仕組みを作りました。

使うもの

Google スプレッドシート
Google Apps Script
LINE Frontend Framework v1 サーバーAPI

成果物

A列に記載されたURLをLIFF化してB列に出力するようなGASを書きました。
実行前
image.png
実行後
image.png

A列からデータを読み出し

スプレッドシートを作成し、スクリプトエディタを起動します
まず、元となるURLを取り出します

urltoliff.gs
function urltoliff() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('シート1');
  let range = sheet.getRange('A2');
  //A2セルに入ったURLを受け取る
  let url = range.getValue();
}

LIFF サーバーAPIからLIFFIDを取得する

ドキュメントはこちら
https://developers.line.biz/ja/reference/liff-v1/#bluetooth-referring-device

まずLINE Developersからプロバイダーとチャンネルを作成する必要があります。私はもともと持っていたLINE Login API用のチャンネルを利用して行いました。

チャンネルIDとチャンネルsecretの確認

チャンネルのダッシュボードに入ったらBasic settingsから、Channel IDChannel secretをメモっておきます。下部にYour Client IDというのもあるのですがそれは今回使わないので注意してください。ここでしばらくハマっていました。
図1.png

チャンネルアクセストークンを取得する

LINE Login向けのチャンネルではロングタームのチャンネルアクセストークンは発行できないため、別途accesstokenをLINE側に投げて取得しておく必要があります。
GASから外部へpostする場合は、UrlFetchApp.fetch();を利用して行います
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app

LINEのドキュメントでは以下のようにPOSTすればアクセストークンがもらえるそうです

curl -v -X POST https://api.line.me/v2/oauth/accessToken \
-H "Content-Type:application/x-www-form-urlencoded" \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id={channel ID}' \
--data-urlencode 'client_secret={channel secret}'

これをGASで書き直すと以下のようになります

function getAccessToken(){
   let payload =
   {
     'grant_type':'client_credentials',
     'client_id':{channel ID},
     'client_secret':{channel secret}
   };

   let options =
   {
     "method" : "post",
     'contentType': 'application/x-www-form-urlencoded',
     "payload" : payload
   };

  let response= sendHttpPost("https://api.line.me/v2/oauth/accessToken",options);
  return response.access_token;
}

function sendHttpPost(endpoint,options){
   let response = UrlFetchApp.fetch(endpoint, options);
   return JSON.parse(response.getContentText());
}

これでgetAccessToken();を呼べばAccesstokenが手に入るようになりました。

ここまででコードは以下のようになりました

urltoliff.gs
function urltoliff() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('シート1');
  let range = sheet.getRange('A2');
  //A2セルに入ったURLを受け取る
  let url = range.getValue();
  //アクセストークンを取得
  let token = getAccessToken();
}
function getAccessToken(){...}
function sendHttpPost(endpoint,options){...}

LIFFの作成

LIFFを作成する場合は以下のようなリクエストを投げれば作れるとのことです

curl -X POST https://api.line.me/liff/v1/apps \
-H "Authorization: Bearer {channel access token}" \
-H "Content-Type: application/json" \
-d '{
  "view":{
    "type":"full",
    "url":"https://example.com/myservice"
  },
  "description": "Service Example",
  "features": {
    "ble": true
  }
}'

これをGASでは以下のように書き直せます

function createLIFF(token){  
  let payload=
  {
    "view":{
      "type":"full",
      "url":"https://example.com/myservice"
    },
    "description": "Service Example",
    "features": {
      "ble": true
    }
  }

  let options = 
  {
    "headers" : {
      "Authorization":"Bearer "+token
      },
      "method":"post",
    "contentType":"application/json",
    "payload" : JSON.stringify(payload)
  }

  let response = sendHttpPost("https://api.line.me/liff/v1/apps",options);
  return liffResponse.liffId;
}

ポイントは、shellでは -d で渡しているためURLエンコードせず生のjsonで渡す必要がある点です。トークンの時のようにそのままpayloadを渡すとデフォルトでURLエンコードされてしまうため、URLエンコードしたくないものについては、payloadをJSON.stringify()してから文字列で渡す必要があります。以下公式ドキュメントにも書いてありますがここでしばらくハマりました
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetchurl,-params

ここまででコードは以下のようになりました

urltoliff.gs
function urltoliff() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('シート1');
  let range = sheet.getRange('A2');
  //A2セルに入ったURLを受け取る
  let url = range.getValue();
  //アクセストークンを取得
  let token = getAccessToken();
  //LIFFIDを取得
 let liffid = createLIFF(token);
}
function getAccessToken(){...}
function sendHttpPost(endpoint,options){...}
function createLIFF(token){...}

スプレッドシートに出力する

最後に取得したLIFFをスプレッドシートに出力します。
サーバーAPIから得られるIDはURL全体ではないので、LIFFアプリとして起動するよう、接頭にhttps://liff.line.me/を追加して出力します

urltoliff.gs
function urltoliff() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('シート1');
  let range = sheet.getRange('A2');
  //A2セルに入ったURLを受け取る
  let url = range.getValue();
  //アクセストークンを取得
  let token = getAccessToken();
  //LIFFIDを取得
 let liffid = createLIFF(token);
 
  //LIFFアプリURLを出力する
 let liffRange = sheet.getRange('B2');
  liffRange.setValue('https://liff.line.me/' + liffid);
}
function getAccessToken(){...}
function sendHttpPost(endpoint,options){...}
function createLIFF(token){...}

以上でLIFFアプリをスプレッドシートから作成可能です。
LIFFは仕様上1チャンネルで30LIFFアプリしか作れないため、このまま量産していくとすぐ飽和してしまいます。
サーバーAPIでは取得や削除のAPIも用意しているため、それは次で紹介します。

GASでpostリクエストする際の参考等にもしていただけたら嬉しいです。

utautattaro
世界中の端末で自分の書いたコードを走らせることが夢です
https://utautattaro.com
playcanvas
"PlayCanvasは、ブラウザ向けに作られたWebGL/HTML5ゲームエンジンです。PlayCanvas運営事務局は日本国内でのPlayCanvasの普及を目的に活動しています"
https://playcanvas.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away