この記事は455 回閲覧されました。

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

本エントリーは入門者向けとは言え、あくまでもGASでウェブアプリケーションを作るのが初めてという人向けなので、専門用語等やJavaScriptに関する説明は割愛します。いずれ、Google Apps Script自体の入門者向けのエントリーも書いてゆこうと思います。

目次

今回使用するクラス等

概要

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

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

用意の仕方

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

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

図:HTMLファイルは複数作れます。

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側の実行結果を変数に受け取るようなシーンで使用します。

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

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

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

図:ここ重要なポイントです。しっかり設定しましょう。

図:ウェブアプリケーションの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を変更は出来ますが、あくまでもエイリアスです)。

図:これまで公開した版の管理画面

アクセス権限

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

図:アクセス権限と書き込み権限の関係

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

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

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

図:ユーザの権限でアクセスと書き込みをさせる

この場合、スプレッドシートに個別にユーザに編集権限を加える、もしくは全員編集可にしておく必要があります。編集権限はグループアドレスでも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側で引き続き返り値の処理をする事が出来ます。例えば以下のような記述をします。

また、返り値を受ける書き方ですが、別の関数にするのではなく、以下のような書き方も可能です。

上記の場合、onSuccessだった場所に無名関数をつくり、無名関数の引数retでGAS側の返り値を受け取って内部で処理をしています。exportlogはGAS側の関数の実行を意味しています。

また、この関数は以下のようなルールがあります。

  1. withFailureHandlerは別につけなくても良い
  2. GAS側でreturnすれば、HTML側へ値を返すことが出来る。
  3. returnで返す場合、配列などは必ずJSON.stringify(array)という形で加工して渡して上げる必要がある。
  4. 3.の場合、HTML側はJSON.parse(array)で受け取る事になる。
  5. withSuccessHandlerの引数は成功時に実行する関数名。onSuccessがそれでさらにそのonSuccessの引数dataがGAS側からreturnの返り値を受け取るものです。
  6. 但し受取側はJSON.parseをしなくても良い。obj.messageのようにJSONから値を取る形で処理を継続してもOK
  7. HTML側からGAS側へ渡す場合通常はJSON.stringifyせずとも渡せますが、オブジェクトの場合はJSON.stringifyする必要性があります。その場合、GAS側はJSON.parseで配列として受け取れます。
  8. 引数は複数渡すことが可能です。
  9. formなどの値を送る場合には、そのままノードまるごと渡せるのですが、複数の引数として渡す事は出来ません。必ずノード単独です。
  10. 主にこの関数はcreateHtmlOutputFromFileで使用します。

また、トリッキーな方法として以下のような形で生成時に値を渡してしまう手段もあります。

上記のケースでは、HTML側にdoIt()という関数を用意しておいて、予め用意したdataという変数の値をJSON.stringifyで加工、HTMLを生成時に自動的に変数まるごと渡して、doIt関数で処理をさせる事が可能です。ただ、あまりこれをやるメリットは薄いです。

また、createTemplateFromFileの場合は、GAS側の変数や処理の中身をHTML側でスクリプトレットにて取得が可能です。

こうする事でHTML側でスクリプトレットの強制実行タグでtestmanにpotatoという名前付き範囲の値を取得させる事が可能です。もちろんここの部分は変数名でもOKです。他にも以下のようなコードをheadタグ内で記述する事で、createTemplateFromFileの場合には、テキスト文字列を取得が可能です。

これはcssというHTMLファイル内にcssの記述をしたものをHeadタグ内で呼んでいるもので、CSSの記述をまるごと別のHTMLファイルから呼び出せます。詳しくは、Google Apps Script上でCSSやJavaScriptを別々に管理する方法を参照してみてください。

google.script.host関数

この関数はちょっと特殊な関数で、次の項目で紹介するスプレッドシートのダイアログで使う場合に併用するものです。おもに、GAS側で表示してるダイアログを閉じたり、そのダイアログのサイズを変更したりする為に使います。

通常のウェブアプリケーションとして公開してるシーンでは使いません。

特定の人にだけウェブアプリケーションを使わせる

さて、ここで気がつくと思うのですが、ウェブアプリケーション自体のアクセスを細かく制御できないか?という話ですが、それはシステム上出来ません。ウェブアクセスは「自分のみ」か?「全員アクセス可」のどちらかしかありません。となると特定の人にだけウェブアプリケーションを使わせたいのに、このままだと誰でもURLを知って入れば使えてしまう事になります。

そんな時は自分でロジックを組みます。自分もこのロジックを使っていますが、以下のポイントを持って作りましょう。

  1. スプレッドシートにメアドを記録した承認リストシートを用意します。ここに記述されてるメアドの人のみにアクセス可とします。
  2. フォームのメイン部分は全体を<div id=”mainform”style=”display:none”></div>などで括ってしまいます。最初はフォームを表示しないようにします。
  3. GAS側にGetUser()という関数を用意。アクセスしてきてるユーザのメアドを取得し判定するコードを記述します。メアドが承認リストある場合にはOKを、ない場合にはNGを返します。
  4. HTML側に最初に実行する関数として、google.script.run.withSuccessHandler(onSuccess).GetUser();を記述しておき、onSuccessはGetUserからの返り値を受取り、NGの場合には2.のdivにinnerHTMLで「アクセス不可」の文字を入れてしまう。OKのときはdocument.getElementById(“mainform”).style.display = “block”で表示してあげるなどのロジックを組む。

こんな具合です。これで特定の人のみウェブアプリケーションを使えるようになります。承認リストの管理が必要になりますけれどね。具体的なコード例は以下の通り。

GAS側のコード

HTML側のコード

返されたHTML側はonSuccess側で以下のような処理を記述しておきます。

これで、承認リストにはないユーザにはアプリケーションを表示せず、リストに乗ってる人はアプリケーションを利用できるようになるわけです。

スプレッドシートのダイアログで使う

すでにメッセージボックスあれこれにて紹介済みなのですが、スプレッドシート上で呼び出すダイアログにも、HTML Serviceで生成したウェブアプリケーションをダイアログとして呼び出す事が可能です。標準のダイアログは素っ気なく出来ることも限られているのですが、HTML Serviceで作ったダイアログは、自由度が高くあらゆるものをダイアログに詰めて、処理させる事が出来るので、重宝します。以下のようなコードを記述します。

図:HTML Serviceで作ったダイアログ

ライブラリの関数は直接呼び出せない

HTML側からgoogle.script.runでGAS側の関数を実行したり、実行結果を受け取れるわけなのですが、関数類を他のシート等でライブラリ化している場合、GAS側でライブラリを導入していても、直接ライブラリの関数を呼び出す事は出来ません。あくまでもGAS側に用意されてる関数しか実行は出来ない仕組みになっています。ですので、ライブラリ化してる場合には、ライブラリの関数をラッピングしてGAS側で用意してあげる必要があります。

MDvtU0ospspq31f4ArmUs9G_JV1dIyBf4は自分が作ったライブラリのプロジェクトキーですが、この中にあるuidgene()という関数はランダムな数値を生成する関数ですが、例えば、以下のようなコードを実行しても呼べません。ore3という名前をつけてあります。

この場合、GAS側に関数を用意するか?ラッピングした関数として以下のような形で用意すれば呼び出す事が可能です。HTML側はこのoreore()を呼び出して挙げればOKです。

サイトに埋め込み

Google Sitesに埋め込みする

作成したウェブアプリケーションをGoogle Sites新しいGoogleサイトは埋め込みは未対応)に埋め込む事が可能です。Google Sites上でもコードを記述して埋め込む方法とスプレッドシートなどの上に作成したコードを元に生成したものを埋め込む方法の2つがありますが、ここでは後者の方法を記述します。以下の手順で埋め込みましょう。

  1. ウェブアプリケーションとして公開した際に、最後にexecが付くURLをコピーしておく。
  2. Googleサイトの該当のページを開き編集モードにする
  3. メニューより、「挿入」⇒「Appスクリプト」を選択
  4. 下のほうにある「または、サービスとして既に公開されている Apps Script の URL を貼り付け:」のテキストボックスに1.のURLを入れて、選択ボタンを押す。
  5. Appスクリプトガジェットとして挿入されるので、サイズやフレームの表示などを調整する。
  6. 編集モードを終わらして保存する。
  7. ウェブアプリケーションが表示される。

自分もこの方法で各種申請用フォーム類などは表示するようにしています。直で1.のURLのページを表示させるようにしても良いのですが、ページURLが変わったりした場合に面倒なので、sitesの固定のページに貼り付けて閲覧してもらっています。縦長のフォームの場合はスクロールバーが出るのが嫌であれば、結構大きめの高さを入れるようにしましょう。

図:埋め込み画面でURLを入力する

それ以外のサイトに埋め込みする

Google SitesはURLを指定すれば簡単に埋め込めるようになっていますが、例えば外部のサイト(社内で運用してるWordpressのイントラであったり、ローカルのindex.htmlなど)には通常埋め込みが出来ません。これはGoogle Apps Scriptで生成したウェブアプリケーションはデフォルトで「X-Frame-Options」という項目が入っており、外部サイトのiFrame内からは呼び出しが出来ない様になってるためです。ちなみにその場合Chrome Debuggerには以下のエラーが表示されます。

Refused to display ‘ここにURL’ in a frame because it set ‘X-Frame-Options’ to ‘SAMEORIGIN’.

そこでHTML Serviceに用意されてるオプションを指定して出力をすると、外部のサイトにてiFrameタグで埋め込みをすることが可能です。XFrameOptionsModeと呼ばれるもので、以下のようなコードで指定します。

いつものコードに.setXFrameOptionsModeをつけ、引数にHtmlService.XFrameOptionsMode.ALLOWALLを入れるだけです。これで、iFrameタグでexecと最後につくウェブアプリケーションのURLを指定すれば、WordpressなどのサイトにAppスクリプトガジェットとして呼び出す事が可能です。ただし、作成者以外では表示画面の上に何やら英語の妙なメッセージが出ますが、これは仕様です。

※.setXFrameOptionsModeをつけることにより、iframe内にGoogle Apps Scriptのフォームを呼び出せるようにはなりますが、同時に他人が別の場所でiframe内に呼び出せる事にもなるので、クリックジャッキング対策が別途必要になる事があります。

実際に普通のGoogleアカウントで試してみましたが、匿名ユーザの閲覧も許可した所、以下のような形(リッチなGUIのアプリ参照)で表示ができました。匿名ではない指定をした場合には、Googleアカウントが必要です。また、自社ドメインのユーザのみの場合、当然外部のユーザは閲覧する事は出来なくする事が可能です。

図:上のように埋め込みが可能です。

複数のプロジェクトを用意する

Google Apps Scriptでは1つのスプレッドシートに1つしかdoGet()は置けないので、複数のウェブアプリケーションをそのままでは作ることができません。その為、例えば申請用ページをスプレッドシート上のGASで作り、承認用には別のシートか?単体のGASファイルを作って同じスプレッドシートを参照させるなんて形で作る事になります。しかし、Google Apps Scriptは1つのスプレッドシートに複数のプロジェクトを作る事が出来るようになっています。

それぞれのプロジェクトは

  1. 完全に独立したプロジェクトである
  2. それぞれのプロジェクトにdoGet()を置いた場合、それぞれ別のURLとしてウェブページを表示する事が可能。
  3. 但し、シートのデータは共有出来る。
  4. スクリプトプロパティも独立となるので、こちらは共有は出来ない。

といった仕組みになっています。つまり1シート2プロジェクトで2つのウェブアプリケーションを作る事が可能になっています。別々にファイルを用意するのではなく、プロジェクトを2つ作成して、別々にコーディングをすれば良いという訳です。新しいプロジェクトを作る場合には

  1. スクリプトエディタを開く
  2. メニューより「新規作成」⇒「プロジェクト」を選択
  3. 次回以降、スクリプトエディタを開くと、どのプロジェクトを編集するか?確認するようになります。

※ちなみに、Developer Consoleのプロジェクトに対しては通常、1つのGoogle Apps Scriptのプロジェクトが対になって対応していますが、こちらは同じプロジェクトに対して2つ以上のGoogle Apps Scriptのプロジェクトを紐付けする事が可能です。

画面遷移について

Google Apps ScriptではHTMLファイルを複数作る事は可能なのですが、doGet()は1個しか設置出来ません。よって、ウェブアプリケーションとして表示出来るのは、1つのプロジェクトで1つだけです。その為、シングルページアプリケーションしか作れません。つまり、他のウェブサイトなどで見られるような画面遷移というものが出来ませんので、jQueryなどを使ってダイアログを表示したり、サイドバー的なものを用意して1ページ内で収めるようなコードを書かなければなりません。

しかし、createTemplateFromFileを使ったケースの場合、過去にも紹介しましたが複数のHTMLファイルを呼び出すような感じで、擬似的に画面遷移を作る事が可能です。あくまでもシングルページなのですがHTMLをごっそりチェンジ可能なので、複数の画面遷移的なものを作ってみたい場合は、挑戦してみましょう。

Framework7を使った画面遷移を装備する事が可能です。また、HTML5のsectionタグを使った画面遷移というテクニックもおすすめです。

関連リンク

Pocket
このエントリーをはてなブックマークに追加
Bookmark this on Yahoo Bookmark
Pocket