Pickerでファイルやフォルダを選択する画面を装備する

G Suiteでは、Google Driveを中心として様々なアプリ同士が連結しています。ファイルを選択したりアップロードしたり、そのための選択画面が用意されていてお互いでそれらを利用しています。この機能をGoogle Pickerと呼びます。

Google Apps Scriptや通常のウェブサイトのJavaScriptでこのGoogle Driveでの選択ダイアログを装備する事が可能になっています。今回はGoogleスプレッドシート上で利用するのを想定して装備をしてみます。一度使えるようになると今後手放せなくなる機能です。

図:こんな感じのダイアログが使えます

2021年3月31日を持って、Picker APIでアクセスできるのは、Google Drive内のみとなり、PhotoやMapなどはaddViewで追加ができなくなりました。

事前準備

今回使用するスプレッドシート

今回のエントリーではアップロード機能やマップなどの他の機能には触れていません。もっとも基本的なファイルの選択とフォルダの選択にフォーカスしています。別途APIキーが必要ですが、コード内に記述する必要はありません。

使い方はメニューに表示される「チョイス」の中に3種類のファイル選択・フォルダ選択画面を用意しています。

プロジェクトを移動

今回の発表直前の2019年4月8日より、Google Apps ScriptからCloud Platform Projectへ直接アクセスが出来なくなりました。これまでにデプロイしてるものについては、これまで通り「リソース」⇒「Google Cloud Platform API ダッシュボード」からアクセスが可能です。

今回の変更はスプレッドシート上で動かすスクリプトやGoogleの拡張サービスを利用しないタイプのスクリプトであれば特に問題はありませんが、「Apps Script API」や「Google Picker API」、「Cloud SQL接続」などGCP上のAPIを利用する場合には以下の手順を踏んで、Google Apps Scriptにプロジェクトを連結する必要があります。これまでは、自動的にGCP上にGoogle Apps Script用のプロジェクトが生成されていたのですが、今後は自分の組織(もしくはGCPプロジェクト)上で作成されたプロジェクトでなければならないということです。詳細はこちらのページを見てください。

連結する手順は以下の通り

  1. Google Cloud Consoleを開く
  2. 左上にある▼をクリックする
  3. ダイアログが出てくるので、新規プロジェクトを作るか?既存のプロジェクトを選択する。この時、G Suiteであれば選択元は「自分のドメイン」を選択する必要があります。
  4. プロジェクト情報パネルから「プロジェクト番号」をコピーする
  5. 対象のGoogle Apps Scriptのスクリプトエディタを開く
  6. 「リソース」⇒「Cloud Platform プロジェクト」を開く
  7. 4.で入手した番号をプロジェクトを変更のテキストボックスに入れて、プロジェクトを設定ボタンをクリックする
  8. 無事に移動が完了すればメッセージが表示されます。
  9. この時、元の自動作成されたプロジェクトはシャットダウンされて消えます。これで設定完了です。

今回のこの変更だと1つ作ったプロジェクトに集約する必要があるので、クォータについてプロジェクト毎のカウントだったので問題なかったものが、集約されることで、クォータに引っ掛かる可能性があります。

図:プロジェクト番号をコピーしておきます

図:プロジェクトを他のプロジェクトに紐付けしました。

図:GCPの拡張サービスを使うには手順が必要になった

APIキーの準備

今回の機能は、Google Cloud ConsoleよりGoogle PickerをONにした上で、認証情報にてAPIキーを作成する必要があります。また、GAS内ではなく一般のサイト上で使う場合には、APIキーではなくOAuth2クライアント認証が必要になるので、クライアントキーとクライアントシークレットなどが必要になります。

今回は、Googleスプレッドシート上で使用するのでAPIキーのみでOKです。取得方法については、こちらのエントリーにて取得して下さい。取得したらメニューより、「チョイス」⇒「APIキー登録」から登録してください。スプレッドシートのスクリプトプロパティにdevkeyとして値が保存されます。

共通するコード

Google Pickerを利用するための共通のコードです。Google PickerはHTML Serviceで実現している点といくつかの情報をHTML側へ渡してあげる必要があります。

GAS側コード

  • filemanは単純にHTML ダイアログボックスを表示するだけのコードです。Picker.htmlにPickerに関するコードを記述する事になります。
  • teleponはPicker側で選択したファイルのIDを受け取って、ダイアログで表示するだけの関数です。
  • getPickerInfoが今回の主役。ここでは、保存してあるAPIキー(devkey)、アクセストークン(token)、そしてPicker表示領域の縦横のサイズを送ります。

この時、filemanで設定してるダイアログのサイズとgetPickerInfoで規定してるPickerのサイズは同じにしましょう。getPickerInfo側の数値がfilemanで指定してる値より大きいと、はみ出してしまいます。

HTML側コード

Picker.html側のコードです。ここでは、Pickerの構築、呼び出し、選択時の挙動などを記述してゆきます。詳細はそれぞれの項目で。ここでは共通する部分だけを記述しています。

  • 外部ライブラリとしてapi.jsをロードさせています。
  • ボタンのデザイン用として、addon-cssを利用しています。
  • gapi.loadにてGoogle Picker APIを呼び出しています。Cloud ConsoleでAPIを有効にしておかないと機能しません。
  • originは今回は、google.script.host.originで取得させています(HTML Serviceでだけ使えるコマンドです)
  • ファイル選択ボタンをクリックすると、getOAuthTokenが実行され、GAS側のgetPickerInfoが呼び出されます。その後、データを取得して、createPickerが実行される事になります。

origin設定について

Google Pickerを利用する上でつまづくポイントとして、このorigin設定があります。これはセキュリティの観点から指定したドメイン以外からはロードさせないためのもので、Picker APIを利用する上では必須の項目です。

Google Spreadsheet上で使う場合には、https://docs.google.comとなります。Google Sites上で貼り付けて使う場合には、https://sites.google.comとなります。また、単独でウェブアプリケーションとして使う場合には、https://script.google.comとなります。今回、originの値はgoogle.script.host.originで取得した値を使っています。

但し、1つのスクリプトを例えばウェブアプリケーション単体とSitesで共用する場合には、動かない事もあります。その場合の回避策は以下のコードをgetPickerInfoに追記し、HTML側で取り出してあげると良いです。

GAS側コード

SitesApp.getActiovePage().getUrl()は旧Google Sitesでないと使えないので注意。新Google Sitesに対応させる場合には、originの初期値をhttps://sites.google.comとし、try文の中では、ScriptApp.getService().getUrl()にてURLを取得させるように改変すると良いです。

※ちなみにこのsetPriginの値ですが、スプレッドシートからの呼び出し時は「https://docs.google.com」、HTML Service上のウェブアプリケーションからの呼び出し時は「https://script.google.com」をセットする必要があります。自前のサーバの場合は自前のサーバのドメインを指定しないと、Picker APIを呼び出せません。

HTML側コード

getPickerInfo側からの値はcreatePickerの引数であるdataに入ってきます。data.originでその値を取り出してセットしてあげるわけです。この後のPickerの項目で、.setOriginに直接この値を引数に入れてあげれば良いのです。

ファイル選択画面

Google Pickerはオプション項目が非常に多彩で、組み合わせによってダイアログに様々な機能の追加や制限を付けることが可能です。詳細はリファレンスを見ながら自分にあったダイアログを構築する必要があります。今回は、2種類のダイアログを用意してみました。1つ目はスプレッドシートだけを表示し選択出来るようにしたもの。2つ目は詳細に細かく設定項目を追加したものです。

スプレッドシートのみを表示する

表示をスプレッドシートに制限する表示方法です。フォルダ等は出てこなくなります。制限を外すと、通常のシンプルなファイル選択画面になります。違いはそこだけです。

HTML側コード

解説

  • createPickerのdocsViewにて表示するファイルのMIME TYPEを指定し、制限を加えています。GoogleスプレッドシートのMIME TYPEを今回は指定していますが、別のものも指定できます。こちらを参照してください。
  • docsViewにてフォルダ表示オフやフォルダ選択オフを指定しています。
  • 変数pickerでは、値を色々セットしています。setLocaleでjaを指定しないとUIが日本語表示されません。
  • pickerでのset項目は.addView、setOAuthToken、setOrigin、setDeveloperKey、setCallback、setSizeは必須項目です。
  • .enableFeature(google.picker.Feature.NAV_HIDDEN)を指定しているので、上部のナビゲーションバーは非表示になります。
  • setCallbackで指定した引数は次のpickerCallbackの関数を指定します。ファイルを選択時に発動します。
  • pickerCallBackでは、取得したファイルの情報を取得し、GAS側のtelepon関数に渡して上げています。
  • pickerCallbackに於いて、actionで受け取った情報からはurl、id、ファイル名などが取得可能です。取得できるデータはこちらを参照しましょう。

図:Googleスプレッドシートのみを表示させている

ファイルに制限は掛けず所有者のファイルのみ表示する場合

スプレッドシートのみに制限するのではなく、アクセスしている所有者のファイルだけを表示といったことも可能。その場合はdocsviewの組み立て方は以下の通りです。

setOwnedByMeを入れてあります。ファイルは全種類表示されます。

共有ドライブサポート

ファイルの表示に於いて、「共有ドライブ内のファイル」も表示したい場合には、new google.picker.PickerBuilder()以下にオプションとして、「.enableFeature(google.picker.Feature.SUPPORT_TEAM_DRIVES)」を追加する事で、リストに共有ドライブ内のファイルも表示されるようになります。

詳細な設定を追加したファイル選択画面

通常のドライブ上でのファイル選択ダイアログのような画面を作るためには、更に詳細な設定を追加してあげる必要があります。今回はフォルダも表示させた上で、Googleスプレッドシートのみを選択するような画面にしてあげています。複数のdocsViewを追加してる点に注意。

HTML側コード

解説

  • docsshareという項目に2つ目の「共有されたフォルダ」を表示させる為のdocsViewを追加しています。
  • recentViewだけは非常に特殊です。公式リファレンスにない項目で、このような指定をすると「最近使用したファイル」が表示できます。公式では「最近選択したファイル」しか項目がありません。裏技の一つです。
  • pickerでは複数の.addViewでナビゲーションバーにViewを追加してあげています。ナビゲーションバーをオフにしていると意味がありませんので注意。
  • 今回はさらに.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)にて、ファイルの複数選択を許可させています。
  • ファイルの複数選択を可能にした為、pickerCallback側も複数のファイル情報を取り出せるようにルーチンをループで取り出しています。
  • ui.alertで改行表示させるために、IDに続けて"\\n"というエスケープシーケンスを入れてあります。
  • CtrlキーやShiftキーを押しながらクリックすると、複数ファイルが選択出来るようになります。

図:CtrlキーやShiftキーで複数選択が出来ますよ

フォルダ選択画面

フォルダの選択を可能にするコードです。こちらはシンプルに作っています。但し、フォルダ選択画面なのにファイルが選択できては困るので、制限を加えています。

HTML側コード

解説

  • createPickerのdocsViewにて.setMimeTypes('application/vnd.google-apps.folder')とし、フォルダのみを表示させています。
  • フォルダの選択を可能にするために、同じく.setSelectFolderEnabled(true)を追加しています。
  • 他はファイル選択の場合と同じです。

こうする事で、フォルダのみを表示しフォルダのみが選択できるようになるので、ファイルを選択するような事にはなりません。また、こちらの設定も詳細な設定を追加すれば、共有フォルダを選択させたりスター付きだけを表示させたりなど、多彩な追加が可能です。

その他のテクニック

2022年改定された内容

しばらくPicker APIを使っていなかった間に、少しPicker APIのロードする仕様が変更されていたようです。

  • 冒頭の呼び出すライブラリがapis.google.com/js/api.jsに変更されています。
  • その読み込みが終わったら、onApiLoadで初期化をし、続けて、onPickerApiLoadを呼び出すようになっています。

もし、現在利用してるPicker APIがうまく動いていないケースでは上記のように冒頭の部分を書き直す事で、動作するようになります。また、その際に一部、変なスクロールバーの有無が気になる点があったので、以下のCSSも追加しています。

サイドバーからPickerを起動して値を取得する

自分はサイドバーにアプリの設定関係をよく用意していますが、ここに例えばテンプレートのスプレッドシートのIDを入れるシーン等に於いて、Google Pickerを呼び出してIDを取得したいケースがあります。しかし、Pickerのダイアログとサイドバーは全く別のプロセスである為、直接的にやり取りをする事はできないため、PickerでファイルのIDを取得しても、それをダイレクトにサイドバー側に渡す事が不可能です(プッシュして送り込めない)

このようなケースの場合、PickerのIDを格納する場所をグローバル変数やスクリプトプロパティに格納し、呼び出したサイドバー側のメソッドは、無限ループでその値が変化するまで待機させておく必要があります。

  • saveSettingでPickerを呼び出し、スクリプトプロパティの初期値を0にしています
  • Picker側でsaveTargetIdにてスクリプトプロパティに対象のファイルのIDを格納します。
  • saveSetting側はWhileにてフラグがtrueになるまで無限ループで監視しつづけます。
  • 値が0から変更されたら、サイドバー側にターゲットのIDを返してあげる。

図:直接通信が出来ないので仕組みが必要

レスポンシブ対応

Google Pickerのダイアログは、最低サイズは 566 * 350となっており、またスマートフォンで利用するにはちょっと不便なPC向けの仕様になっています。また、ウィンドウに合わせての調整もできないのですが、CSSを適用する事でサイズを調整する事が可能です。

このCSSを加えておくことでフルスクリーン表示となります。

Pickerのダイアログに要素は追加できない

Pickerで表示されるダイアログですが、あの中身は同一ドメイン上の内容ではなくiframeで外部のドメインの内容を表示してるものになります。よってqueryselectorを使って内容を取得したり、逆にPicker Dialogに対してJavaScriptを利用し要素を追加するといったことは出来ません

何かダイアログに対してオプションを用意したくなりますが、現実的には出来ないので、ご注意ください。

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)