アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

Google Apps Script 事始め Webアプリ編

この記事は アクトインディ Advent Calendar 2016 8日目になります。 どうぞよろしくお願いします。

業務でかじっていたGoogle Apps Script (GAS) について軽くまとめました。意外と色々なことができるんですね。
今まで知らなかったWebアプリ化の部分に焦点をあててご紹介します。

概要

G Suite (旧名 Google Apps)を拡張するスクリプトです。Google Sheets, Docs, Forms等のサービスのカスタマイズや自動化、アドオン作成に利用されます。
https://developers.google.com/apps-script/

スクリプトエディタ

Google Apps Script (GAS)用のオンラインエディタです。
https://script.google.com/

Googleドライブからも作成できます。新規>その他>アプリを追加、から検索してGoogle Apps Scriptを追加。
スクリプトエディタはコードを書く環境であり、「プロジェクト」としてファイルをまとめたり各種オプションを設定する場所でもあります。
スクリプトは.gs拡張子でプロジェクトの中で管理されます。

スクリプトの種類

スタンドアローン

Googleドライブに置かれる独立したスクリプトです。後述するバインドスクリプトで無いものです。
https://developers.google.com/apps-script/guides/standalone

以下、最低限動くサンプルです。

コード.gs

function myFunction() {
  Logger.log('test');
}

Google Appsバインド

Sheets, Docs, Forms等のファイルにバインドされたスクリプトです。
https://developers.google.com/apps-script/guides/bound

データファイルのメニューから、ツール>スクリプトエディタを選ぶと出てきます。
getActiveSpreadsheet(), getActiveDocument(), getActiveForm()といった独自の関数が使えてファイルIDをいちいち調べる必要がない、シートにカスタム関数を定義できるなどの特徴があります。

またシンプルトリガーという単純なイベント(onOpen(), onEdit()など)を利用できます。
https://developers.google.com/apps-script/guides/triggers/

コード.gs (Google Sheetsに紐付いている場合)

function getCells() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var data = sheet.getDataRange().getValues();

  for (var i = 0; i < data.length; i++) {
    Logger.log('A列: ' + data[i][0]);
    Logger.log('B列: ' + data[i][1]);
  }
}

Webアプリ

スタンドアローンスクリプトも、バインドスクリプトも、Webアプリとして公開できます。
https://developers.google.com/apps-script/guides/web

公開するにあたって以下の条件があります。

  • doGet()doPost() 関数が定義されていること。
  • その関数が、 HTML service HtmlOutput オブジェクト または Content service TextOutput オブジェクト を返すこと。

Webアプリ公開時に、バージョン番号、スクリプトの実行時ユーザー(スクリプト作成者 or スクリプト実行者)、スクリプトを実行可能なユーザーを指定できます。
スクリプトエディタで「ウェブ アプリケーションとして導入…」から指定します。

コード.gs

function doGet(e) {
  var params = JSON.stringify(e); //入力を受けとり、
  return HtmlService.createHtmlOutput(params); //JSONで出力
}

GASのユーザーインターフェイス

バインドされたスクリプトにはカスタムメニュー、ダイアログ、サイドバーといったUI要素が使用可能です。 スタンドアローンスクリプトでも、画面をHTMLで作り込むことができます。
※どちらのスクリプトでも、用途によっては画面を作らずにスクリプトエディタを実行時インターフェイスとする、またはトリガーを設定する、でも十分な場合も。

UI用にHTMLを扱う場合は、HTML Serviceを利用します。※以前はUI生成用にUi Serviceというものもありましたが現在は廃止されています。
https://developers.google.com/apps-script/reference/html/

実行時モード

以前は、実行時のモード(サンドボックスモード)にNATIVE, EMULATEがありましたが、現在はIFRAMEモード一択です(速度改善、外部JS利用などの柔軟性)。

setSandboxMode(HtmlService.SandboxMode.IFRAME);

IFRAMEの条件:

  • リンクのtarget属性は _top_blank
  • 外部リソースの読み込みは http ではなく https で行う
  • IE9など古いブラウザは対象外。※HTML5のsandbox属性を利用するため

内部リソースの読み込み

スクリプトエディタのプロジェクトにHTMLファイルのみ追加可能です。
テンプレートなどで利用します。

スクリプトでテンプレート用HTMLを読み込む例

  t = HtmlService.createTemplateFromFile('index');

ではJSやCSSはどうしたらいいでしょうか?
この場合はそれぞれのJSやCSSをHTMLのパーツとして用意して、テンプレートにScriptletsというGAS用のテンプレート言語で読み込む形になります(ちょっと強引)。
HTMLの一部なので、中にはstyleタグやscriptタグを入れておく必要があります。

HTMLは スクリプトエディタの ファイル>新規作成>HTML ファイル から登録します。

読み込み用関数の定義

function include(filename) {
  return HtmlService.createHtmlOutputFromFile(filename)
      .getContent();
}

HTMLにパーツを読み込む

<?!= include('index.css'); ?>
<?!= include('index.js'); ?>

外部リソースの読み込み

テンプレートHTMLにふつうにタグを記述するだけです。要HTTPS。

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

Webアプリのテンプレまとめ

以上をまとめてみるとこのようになります。

コード.gs

function doGet(request) {
  t = HtmlService.createTemplateFromFile('index'); //index.htmlをテンプレートに使う
  t.title = 'タイトルを設定します';
  Logger.log( t.getCode() ); //テンプレートの実際の出力コードを確認できる
  return t.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

function include(filename) {
  return HtmlService.createHtmlOutputFromFile(filename)
      .getContent();
}

index.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <title><?= title ?></title>
    <?!= include('index.css'); ?>
  </head>
  <body>
  <h1><?= title ?></h1>

  <p id="content">Content ... </p>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <?!= include('index.js'); ?>
  </body>
</html>

index.css.html

<style>
body {
  background-color: #f0f0f0;
}
</style>

index.js.html

<script>
$(document).ready(function () {
  $('#content').text( 'Content ... Loaded.' );
});
</script>

文書をデータソースにしてWebアプリを作る

上記の雛形を、文書(例ではスプレッドシート)のバインドスクリプトとして適用する場合はこんなかんじになります。

  1. メニューから、ツール>スクリプトエディタを選ぶ
  2. プロジェクトにHTMLを登録する
  3. コード.gs を下記の例を参考に修正する
  4. テンプレートのどこか (index.js.html等) で data を受け取って処理する
  5. スクリプトエディタで「ウェブ アプリケーションとして導入…」を指定する

コード.gs

function doGet(e) {
  t = HtmlService.createTemplateFromFile('index');
  t.title = 'スプレッドシートをWebアプリ化';
  t.data = JSON.stringify( getCells() );
  return t.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

function getCells() {
  //var sheet = SpreadsheetApp.getActiveSheet();
  var id = 'XXXXXXXXXXXXXXXXXXXX'; //Webアプリ化するとIDを自動で取れなかったので調べて記述しておきます
  var sheet = SpreadsheetApp.openById(id);
  var data = sheet.getDataRange().getValues();

  return getJSON(data);
}

//このへん適当です…
function getJSON(data) {
  var json = [];

  for (var i = 0; i < data.length; i++) {
    json.push({"a": data[i][0], "b": data[i][1]});
  }

  return json;
}

データを受け取る例

  var foo = { data: JSON.parse(<?= data ?>) };
  // このあと受け取ったデータを処理する

後半ざっくりですが、以上です。