※本記事はプロモーションを含みます
目次
Google Apps Script(GAS)はスプレッドシートの自動化処理を組むツールです。作業が終わったことや現在のステータスをシート上の利用者にどう伝えるかで悩む場面がよくあります。最も手軽な通知方法として Browser.msgBox() や ui.alert() が挙げられます。ただし、これらはダイアログが画面中央に現れるので、ユーザーのキーボード入力やスクロール操作を完全に止めてしまいます。というのは、確認ボタンを押すまでシートの閲覧や編集が一切できなくなるからです。なので、頻繁に走るデータ取得やバックグラウンド処理の完了通知としてはストレスになりがちです。スプレッドシートの画面右下に控えめなポップアップを一定秒数だけ表示するトースト機能を使えば、ユーザーの手を止めることなく自然な形で状態を共有できます。
モーダルダイアログで作業を止めないための通知手段
スプレッドシート上で動くスクリプトにおいて、ユーザーへのフィードバックは非常に重要です。というのは、何も表示されないと、ボタンを押したあとに処理がまだ動いているのか、すでに終わったのか、あるいはエラーで固まったのかをユーザーが判断できないからです。なので、利用者が不安になって同じボタンを何度も連打してしまい、二重実行によるデータの不整合や不要なAPIクォータ消費を引き起こす事故が後を絶ちません。
ただし、そこで毎回モーダルダイアログを表示させて「OK」をクリックさせると、不満の声が上がります。というのは、定期的な更新作業や連続したデータ入力を行っている現場からは「毎回答えさせられるのが鬱陶しい」「作業のテンポが崩れる」と言われるからです。なので、複数人で共同編集しているシートの場合、作業中に突如としてポップアップが割り込んでくる体験は快いものではありません。
トースト通知は、こうした課題を解消できる機能です。スプレッドシートの右下隅に数秒間だけ小さなカード型UIが浮き上がり、時間が経つと自動的にフェードアウトして消えます。画面内のセル選択やスクロール、データ入力を一切阻害しません。なので、バックグラウンドでの集計完了や外部APIからの差分取り込みといった「作業を止めるほどではないが、終わった事実だけは知っておいてほしい」というケースに最も合致します。
ユーザーが画面をじっと見ていなくても、視界の端で完了の気配を察知できる絶妙な控えめさがあります。なので、日々の定常業務に組み込む通知インターフェースとして重宝します。まずはこのトースト通知を表示させる基本のコードから確認しましょう。
toastメソッドの呼び出しと引数の指定ルール
toast() メソッドは、スプレッドシートにトースト通知を表示させる処理で使います。このメソッドは SpreadsheetApp の Spreadsheet オブジェクトが持っています。Ui クラスではなくスプレッドシートそのものに対して呼び出す形になります。
const ss = SpreadsheetApp.getActiveSpreadsheet();
ss.toast("データの同期が正常に完了しました。", "完了", 5);
上記のコードを実行すると、アクティブなスプレッドシートの画面右下に黒っぽいボックスが立ち上がります。ボックスには「完了」というタイトル太字と、「データの同期が正常に完了しました。」というメッセージ本文が並びます。なので、およそ5秒後に自動で閉じます。
この toast メソッドはオーバーロードされており、引数の渡し方によって3つの形式が存在します。最もシンプルな形式は、第1引数にメッセージ文字列だけを渡す ss.toast("処理が完了しました"); です。ただし、この場合はタイトル部分が空欄になります。なので、デフォルトの表示時間(おおむね3秒程度)で自動的に消去されます。
第2引数を指定するとタイトルを設定できます。なので、第3引数を渡すことでトーストの表示時間(秒単位の数値)を明示的にコントロールできます。例えば完了メッセージを少し長めに読ませたいときは 10 を指定します。ただし、テンポよく流したいときは 2 や 3 に設定するといった調整が可能です。
引数の扱いにおいて知っておくべき特殊な挙動として、表示秒数に負の数(例えば -1)を渡すか、あるいは null を指定した場合の動作があります。秒数に負の値を指定すると、このトーストは自動では消えません。というのは、ユーザーが手動でトースト右上の「×」ボタンを押すか、別のトーストによって上書きされるまで画面右下に残り続けるからです。なので、重要度の高い警告や、「ここまでの集計結果を確認してください」といった確実に目を通してほしい連絡を残したい場合には、あえて負の数を渡して居座らせる設計も有効です。
ただし、メッセージ文字列やタイトルに長文を指定しすぎると、トーストの幅に合わせて文字が途中で省略されたり、視認性が著しく落ちたりします。トーストは、あくまで短文による状況伝達を目的としたUIです。なので、エラーの詳細なスタックトレースや数行にわたるログを流し込む用途には適していません。詳細な内容はログシートや実行ログに出力しましょう。トースト側には「同期完了(詳細はログシート参照)」のように要約を短く載せるのが適切な使い分けです。
長いループ処理や進捗表示で直面する表示遅延と上書き
トーストの使い道として真っ先に思い浮かぶのは「重い処理の進捗バー代わり」です。例えば数百行のデータを1行ずつ処理していくループの中で、10行ごとに「10/100件処理完了」「20/100件処理完了」とトーストを更新していけば、利用者は進行状況が把握できて安心できるように思えます。
ただし、GASの描画更新の仕組みを意識せずにループ内で単純に ss.toast() を呼び出すと、期待通りに動いてくれません。というのは、スクリプトがループを回している間はスプレッドシートのUI描画キューが保留されるからです。なので、スクリプトの処理が完全に終わった最後の瞬間に、最後のトーストだけがポンと1回表示されて終わってしまう事態が頻発します。
この描画遅延を回避してリアルタイムに進捗トーストを表示させたい場合は、トーストを呼び出した直後に明示的なスプレッドシートの反映命令を挟む必要があります。一般的には SpreadsheetApp.flush() を呼ぶことで保留されている変更をUI側に強制フラッシュさせます。ただし、トースト自体の描画に関しては Utilities.sleep() などと組み合わせても、ブラウザ側のWebSocket通信の都合で完全に同期して滑らかに動かないケースがあります。
さらに根本的な問題として、スプレッドシートのトースト領域は画面右下の「1枠」しか用意されていません。というのは、複数のトーストが下から順に積み重なっていくようなスタック型通知ではないからです。なので、新しいトーストが呼ばれた瞬間に前のトーストが即座に上書きされて消える仕様になっています。
なので、ミリ秒単位で高速に回るループ内で毎回 ss.toast() を実行すると、チカチカと激しく点滅を繰り返すだけで文字が一切読めなくなります。というのは、ブラウザ側に余計な描画負荷をかけてかえってスクリプト全体の実行速度を落とす原因になるからです。もし進捗通知としてトーストを採用するのであれば、全体の処理件数をあらかじめカウントしておきましょう。そして、全体の20%、40%、60%といった大きめの区切りに達したときだけ SpreadsheetApp.flush() と共に呼び出すか、時間間隔をチェックして最低でも3秒以上経過している場合のみ更新するといった間引き処理を挟むのが現実的な落としどころになります。
時間駆動トリガーや外部連携で呼び出したときの制限と回避策
トースト通知を組み込む上で最も多くの人が引っかかるポイントは、「スクリプトがどのコンテキストで実行されているか」という実行環境の差異です。トーストはスプレッドシートを開いているブラウザの画面が存在して初めて成立するUIコンポーネントです。
ボタンのクリックやカスタムメニューから実行される手動操作、あるいはシートの編集を検知するシンプルトリガー(onEdit)やインストール可能編集トリガーであれば、問題なくトーストが表示されます。というのは、操作しているユーザーの画面が存在するからです。ただし、以下のようなシチュエーションではトーストが動作しない、あるいはエラーになります。
第一に、時間主導型(タイムトリガー)による定期バッチ実行です。深夜の午前2時にタイマーで動くスクリプトの中で SpreadsheetApp.getActiveSpreadsheet().toast(...) を呼び出しても、通知は虚空に消えます。というのは、その瞬間にスプレッドシートを開いているブラウザが存在しないからです。厳密にはスクリプト側で実行時例外を吐いて止まることは少ないものの、誰も見ていない画面に通知を送ろうとする無意味なコードになります。なので、時間駆動トリガーでは getActiveSpreadsheet() の取得自体が不安定になるケースもあるため、トースト関連のコードが想定外の挙動を招くリスクもあります。
第二に、Webアプリケーション(doGet や doPost)として外部から叩かれた場合や、Googleフォームの送信トリガー、外部サービスからのWebhook連携などです。これらもバックグラウンドでGASエンジンが単独稼働している状態です。なので、スプレッドシートのDOMやUIセッションと紐付いていません。
第三に、ライブラリ経由での呼び出しや別スプレッドシートの参照です。SpreadsheetApp.openById("...") で別のスプレッドシートのインスタンスを取得して、そのオブジェクトに対して toast() を呼び出しても、自分の開いている画面には表示されません。ただし、そのシートを誰かがブラウザで開いていたとしても、別アカウントのセッションへ横断的にトーストを割り込ませるような使い方はセキュリティおよびアーキテクチャの都合上できません。
こうした制限に対処するためには、スクリプトの実行経路を意識した分岐が必要です。手動実行と自動トリガーで共通のロジック関数を使い回す設計にしている場合は、UIセッションが取得できるかどうかを安全に判定しましょう。画面が存在しないコンテキストではトーストの呼び出しを静かにスキップするか、代替として console.log() やChat/Slack通知、メール送信へとルーティングを切り替える防御的なコード設計が求められます。
現場で破綻しないトースト通知の設計パターン
トースト通知を実際の現場向けツールに組み込む際は、単に「成功しました」と出すだけでは足りません。失敗時の通知や他のUIパーツとの役割分担を明確にしておくことが運用の安定につながります。
トーストが最も輝くのは、「ユーザーが待たずに作業を続けたい正常系の完了報告」です。ただし、データのバリデーションエラーや外部APIとの通信失敗、権限不足による更新失敗といった「異常系」の通知にトーストを使ってしまうと、表示秒数が切れたあとに利用者がエラーの発生自体に気づきません。なので、壊れたデータのまま後続業務を進めてしまう危険性があります。
したがって、以下のような役割分担を徹底するのが基本方針となります。
正常終了時はトーストを使って、右下に3秒〜5秒だけ「同期が完了しました」と出して作業を邪魔しないようにしましょう。軽微な注意(例えば「数件の空行をスキップしました」など)は、負の秒数を指定したトーストで画面右下に残して、ユーザーが確認して閉じる猶予を与えます。ただし、スクリプトが途中で落ちた場合や致命的な不整合が起きた場合は、トーストではなく SpreadsheetApp.getUi().alert() によるモーダルダイアログを使いましょう。作業を強制停止させて画面中央で明示的にエラー内容を読ませるのが安全です。
また、トースト通知はブラウザのタブがアクティブでない場合、ユーザーの視界に入らない点にも留意が必要です。というのは、重いスクリプトを走らせた直後にユーザーが別のタブに切り替えて別の作業を始めてしまった場合、スクリプトが数秒後に完了してトーストを出しても、タブに戻ってきたときにはすでに表示秒数が経過して消え去っていることがあるからです。なので、「あれ、ボタンを押したのに何も起きていないのかな?」と勘違いされるケースがあります。
もしある程度待ち時間が発生する処理でトーストを使うのであれば、処理開始時に ss.toast("データ集計中... そのままお待ちください", "処理中", -1); として常駐トーストを出し、完了時に ss.toast("集計が完了しました。", "完了", 5); で上書きして自動消滅させるパターンが非常に有効です。というのは、こうしておけば、途中で別タブに移動して戻ってきたユーザーも、右下に「処理中」が出たままであれば作業が継続していると分かるからです。なので、完了トーストに切り替わっていれば無事に終わったと視覚的に一目で確認できます。

