これまでブログにて、Google Apps Scriptを用いた様々なアプリケーションやテクニックを紹介してきましたが、その多くはある程度Google Apps Scriptが出来る前提でのものでした。その為、入門者向けの内容ではなく、コードの説明も主にポイントになる点と、コード内のコメントでどのようなものを書いてるのかを読み取るものになっています。その中でGoogle Apps Scriptでウェブアプリケーションを作る方法をまとめて欲しいという話があったので、現時点で最新の作り方をまとめてみました。

今回使用するクラス等

概要

Google Apps Scriptにはウェブアプリケーションを作り表示する為のサービスとして2種類のタイプのクラスが用意されています。どちらもウェブアプリケーションとして出力した結果は同じなのですが、その動作原理が異なるので、利用目的などに応じて使い分けると良いでしょう。また、ウェブアプリケーションとして公開する為の手順がとても重要なので、この手順はよく把握しておく必要性があります。コード変更時に嵌まるポイントの1つです。

また、HTML内ではjQueryといったライブラリやangularjsといったフレームワーク等、現在はかなり自由に使えるようになっています。速度も高速化されていますので、かつてのようにサニタイズされてライブラリが動かないだとか、遅いといった事がありません(それらの古いモードは現在廃止されました)。

用意の仕方

Google Apps Scriptのスクリプトのみではウェブアプリケーションは作れません。必ず表示する為のHTMLファイルが必要です。とはいえ、ドライブにHTMLファイルを用意するのではなく、スクリプトエディタの画面上で用意します。

  1. スクリプトエディタのメニューよりファイル⇒新規作成を開く
  2. HTMLを選択し、名前をつける
  3. HTMLファイルが作られるので、その中にHTMLやCSS、JavaScriptを記述してゆく

createHtmlOutputFromFile

非常にポピュラーなウェブアプリケーションを作る為のメソッドです。用意したHTMLをアウトプットするだけです。doGet()関数で呼び出すのがお決まりになっていますので、以下のコードで呼び出すだけです。一番よく使う形式です。以下の事例だとindex.htmlを呼び出しています。自分のコードでは、これに加えて、.setSandboxMode(HtmlService.SandboxMode.IFRAME)というものをつけていますが、これは今現在は省略可能です。

createTemplateFromFile

少し変わったウェブアプリケーションを作るためのメソッドです。同じく用意したHTMLをアウトプットします。doGet()関数で呼び出すのがお決まりになっていますが、特徴的なのがこれは動的に呼び出せるという点です。

  1. スクリプトレットというものを利用してGAS側のコードをHTML側から実行する事が可能です。
  2. GAS側で取得したデータをHTML側変数で受け取る事が可能である
  3. evaluate()という関数を必ず使う。

スクリプトレットとは、<?= kinoko(); ?>といった形で記述をし、この場合、kinoko関数実行するといったものになります。また、output.append(“キノコ”)関数も使え、HTML内に文字列を出力させる事が可能です。また、<?!= ?>という記述もあり、この場合強制的に実行する強引なやり方です。HTML側でGAS側の実行結果を変数に受け取るようなシーンで使用します。

viewportの指定

HTML Serviceでは、HTML側にスマフォ対応で利用するviewportのメタタグを記述しても無視されます。このメタタグはGAS側で出力する前にオプション指定する必要があります。

.addMetaTagでviewportを指定することが可能です。この指定をしない場合、スマートフォンに最適な表示にはならないので、スマフォ用アプリを作成する場合には必須の項目です。

ウェブアプリケーションとして公開

これらのメソッドを使っても、最終的に「ウェブアプリケーションとして公開」をしなければ、ウェブページは表示されません。また、このウェブアプリケーションとして公開はいくつかのハマりポイントがありますので注意が必要です。公開の仕方は以下の手順。

  1. スクリプトエディタのメニューより、「公開」⇒「ウェブアプリケーションとして公開
  2. 次のユーザとしてアプリケーションを実行で誰の権限で動かすかを指定する。自分かアクセスしてるユーザの二択。後者の場合、ユーザはGoogleアカウントを持ってる必要があります。
  3. アプリケーションにアクセスできるユーザを指定する。自分のみ、全員、全員(匿名含む)の三択。但し、全員の場合はGoogleアカウントが必要で、匿名含むの場合は、Googleアカウントなしでアクセス可能です。
  4. 最後に導入すると、ウェブアプリケーションのURLが取得できます。このURLでアクセスをします。URLの最後がexecが本番用、devがテスト用で、テスト用は最新のコードをテストのリンクを踏むと表示されますが、変更したコードがそのまますぐに反映されてしまうので、テスト用のURLで運用しないように。

嵌まるポイント

さてハマりポイントなのですが、以下のような感じです。

  • G SuiteことGoogle Appsの場合、外部との共有を管理者が許可していない場合、匿名でウェブアプリケーションは実行出来ませんし、外部に公開は出来ません。
  • 公開済みの場合、再度公開を実行すると最新のコードをテストという項目があり、URLの最後に/devが付きます。公開していない状態でも最新コードで表示されます。
  • 但し上記のそれはデベロッパーモードであり、コードの変更が直ちに反映されてしまうので、一般公開のURLとして使わない事。execの場合、新しい版で公開し直さない限り、コードは反映されません(但し、HTML部分のみで、GAS部分は反映されてしまいます)。
  • きちんと公開した場合はURLの最後に/execが付き、これを貼り付けるガジェットのURLや一般公開のURLとして使うこと。
  • 一度公開したら、ウェブアプリケーションのURLは変わらない。
  • コードを変更した場合、execのURLに反映させる為には、プロジェクトバージョンを変更し新規作成にしなければコードが反映しません。
  • 何度もプロジェクトバージョンを新規作成してると、版が積み上がります。これらはファイル⇒版を管理の中で確認が出来、過去の版を廃止する事が可能です。過去の版でウェブアプリケーションを表示する場合は、プロジェクトバージョンを古いものにして公開すればOK.
  • 但し、過去のプロジェクトバージョンのコードに戻す事は不可能。変更履歴から復元は可能ですが、全て変わってしまうので、細かく保存しましょう。
  • ウェブアプリケーションを無効にするをクリックすると、ウェブアプリケーションが停止します。停止しないと版を廃止する事はできません。
  • ウェブアプリケーションとして公開は、プロジェクトオーナーでなければ出来ません。これはスプレッドシートのオーナーとはイコールではありません。複数プロジェクトを設置した場合、片方が自分が作ったものではない場合、そのプロジェクトを自分が削除したりウェブアプリケーションとして公開する内容を変更したりは出来ません。
  • 忘れがちですが、コードを書いて、一度doGet()などを実行し、承認をしておきましょう。これをしないと動きません。
  • シートにアクセスするような場合、ウェブアプリケーションの場合は、SpreadsheetApp.getActiveSpreadsheet()でアクセスは出来ません。SpreadsheetApp.openById(“シートのID”)でなければ、シートのデータは取得できません。但し、スプレッドシート上のダイアログとして使う場合は、取得が可能です。
  • メールを送信するMailAppを使っている場合、Fromの送信者アドレスはウェブアプリケーションとして公開した人のアドレスになります。このアドレスは任意のアドレスに変更は出来ません(但し、その人のメアドにエイリアスを設定してる場合には、MailAppのオプションにfrom: ‘eye4brain@xxx.gr.jp’といった形でFromを変更は出来ますが、あくまでもエイリアスです)。
  • HTML Serviceで出力したHTML上では、ページ内リンクのアンカーは利用する事ができません。つまり、アンカーだけではページ内でジャンプが不可能です。

アクセス権限

前項のハマりどころをもう少し深く掘り下げてみます。このアクセス権限が結構クセモノで、混乱するポイントなのですが、シートのアクセス権限(特に書き込み)とウェブアプリケーションのアクセス権限は別物という事です。以下の表のような感じになります。

よって、スプレッドシートの書き込み権限が自分のみであっても、実行権限が自分で、ウェブアクセスの権限が全員ならば、自分以外の人であっても、自分の権限を持って書き込みが可能です。一方で実行権限がアクセスしてる人の場合、ウェブにアクセスは出来ますが、シートの書き込み権限が無いことになるので、書き込めません。

この時、スプレッドシートの編集履歴は「自分」しか残りません。自分の権限で書き込みをさせている為です。逆を言えばシートは非公開で閲覧させたくないが、ウェブは使わせたいなんて時は実行権限を自分にしておくと良いでしょう。

ユーザ各々の実行権限で書き込みをする為には、以下のような設定にします。

この場合、スプレッドシートに個別にユーザに編集権限を加える、もしくは全員編集可にしておく必要があります。編集権限はグループアドレスでもOKです。この時のシートの編集履歴はそれぞれの人のメアドが記録される事になります。但し、各々のユーザはウェブアプリケーションアクセス時に1度だけ、実行承認をしなければなりません。また、後にコードを追記して新しいAPIを使った場合も、承認画面が改めて出ることになります。

テクニックと注意点

外部のJSやCSSを読み込み

嵌まるポイントの1つなのですが、HTML Serviceで外部JavaScriptやCSS類などを呼び出す場合、http://www.xxx.com/test.jsといった形で呼び出すことは出来ません。httpではなくhttps://でなければならないというルールがあります。https://が使えるのであれば、//www.xxx.com/test.jsという形で頭をつけずに指定して呼び出すことも可能です。

個人でレンタルサーバをファイルの置き場にしている場合、共用SSLなどがない場合には呼び出せませんのでご注意を。呼び出し方そのものは、外部のファイルの呼び出し方と全く一緒です。headタグ内に記述しましょう。

  • ※外部に公開してるGoogle Driveのフォルダであれば、直リンクで呼び出すことも可能です。Direct Link Generatorなどを利用してURLを取得してみましょう。
  • また、createTemplateFromFileを使ったケースの場合、GAS内でJavaScriptやCSSを独立して管理して呼び出すことも可能です。

HTML側とGAS側で通信する

Google Apps Script側と生成したウェブアプリケーションは、サーバーとクライアントの関係にあります。その為そのままでは、HTML側からGoogle Apps Script側に命令やデータを送ったり、またGoogle Apps Script側からHTML側へ返してあげる事が出来ません。しかし、Google Apps Scriptではこの相互通信をする手段として特別な関数を用意しています。以下に示すもの以外にも、google.script.url関数やgoogle.script.history関数なんてものも新規に追加されています。

  • ※これらの関数は非同期で実行されてしまいますので、基本的に順番に実行はされません。
  • ※これらの関数はHTML側で記述します。

google.script.run関数

Google Apps Script側に用意してる関数を一方的に実行する関数です。引数で値や配列などを渡してあげる事が可能です。一方的に実行して完了してしまうので、返り値を受け取るといった事は出来ません。以下のような構文で実行します。

google.script.run.withSuccessHandler関数

この関数は上記の関数とは異なり、返り値を受け取る事が可能です。withSuccessHandlerで成功時、withFailureHandlerで失敗時の処理をそれぞれ定義でき、同時に定義することも可能です。返り値を受け取って、HTML側で引き続き返り値の処理をする事が出来ます。例えば以下のような記述をします。

スクリプトプロパティを共通化する

1シート2プロジェクト体制の場合、スクリプトプロパティも個別になり具合が悪い事があります。その場合、3プロジェクトにしてあげて、3つ目のプロジェクトのスクリプトプロパティを1つ目、2つ目から読み書き出来るようにしてあげれば、共通化する事が可能です。以下の手順で共通化をしましょう(ライブラリ化する作業です。詳細は参照してみてください。)

  1. 3つ目のプロジェクトをつくり、スクリプトエディタにて読み書きする為の関数を用意する
  2. スクリプトエディタのメニューより「ファイル」⇒「版を管理」を開く
  3. 適当な名前をつけて、新しいバージョンを保存をクリック
  4. 続けてメニューより「ファイル」⇒「プロジェクトのプロパティ」を開く
  5. スクリプトIDを控えておく
  6. 1つ目のプロジェクトおよび2つ目のプロジェクトをそれぞれ開く
  7. スクリプトエディタのメニューより「リソース」⇒「ライブラリ」を開く
  8. ライブラリを追加に5.のスクリプトIDを入れて、追加ボタンをクリック
  9. バージョンを指定して、識別子を作ります。識別子は英語で他のライブラリと重複しない名前で適当につけます。自分はsetmanとつけてます。
  10. 既存のスクリプトプロパティを呼び出して書き込むコードをライブラリの関数を呼び出す形に書き換える。この時呼び出し方は、setman.kinoko(“value”)で、3つ目のプロジェクトのkinokoという関数にvalueを渡せるようになります。

図:こうしてライブラリ化しておくと参照が可能になる

ちなみに、自分が3つ目のプロジェクトでスクリプトプロパティを読み書きさせてるコードは以下の通り。

Cloud Consoleプロジェクトも共通化する

1シート2プロジェクト体制の場合、Google Cloud Console側のプロジェクトも個別になります。これでは、Cloud Console側で設定した各種APIの設定や認証情報も個別になってしまうので、二度手間になります。そこで、以下の作業をする事で、1つ目のプロジェクト側に紐つける事が可能になります。(Cloud Consoleを弄ってみるを参照してください。)

図:プロジェクト確認ダイアログ

ページ内リンクについて

Google Apps ScriptのHTML上では、<a href=”#hoge”>のようなページ内リンクが利用出来ません。クリックをしても何も起きず、また、URLをコピーして開いても、真っ白です。こんな場合、jQueryを使う事でこのアンカーについてページ内リンクのように移動できるようにする事が可能です。

ただし、上記の場合、hrefが#で始まる何かをクリックした場合の挙動をコントロールしているので、別にアンカーに対してイベントリスナーでコマンドを割り当ててるとオカシナ挙動になるので、注意は必要です。

共有してみる: