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

実際のところどれくらい使われてるのかはわかりませんが、Google Cloud Printと呼ばれるリモートプリントサービスがあります。Android用のアプリとしてもリリースされているサービスで(実際には印刷プラグインなのでアプリとしては見えない)、通常のVPN越しにLANで結ばれた遠隔地のプリンターにプリントアウトするような仕組みではなく、Googleアカウントで接続されたChromeブラウザ経由で、そのマシンのローカルのプリンタにプリントアウトするサービスです。

その為、例えばプリンタドライバのないマシン(スマートフォン等)であっても、そのプリンタを使えるPC等がそこに存在していれば、遠隔地からプリントアウトする事が可能であり、尚且つそのプリンタを他人と共有できるので、FAX代わりにもなり、またVPNがどうとか気にすることなく印刷も出来、Googleドライブ宛にPDFをアップロードも可能なサービスです。今回はこのGoogle Cloud PrintをGoogle Apps Scriptから利用してみたいと思います。

今回はCloud Print非対応のプリンタという扱いで、PDF Creatorをインストールしてプリンタ登録し、Autosave機能を使って仮想マシン内のデスクトップにPDFを出力するというパターンでやってみたいと思います。Cloud Printとしてプリンタ登録については、公式サイトで詳しく説明がされています。

目次

今回使用するファイルや資料

今回使用するスプレッドシートには、本エントリー内で説明はありませんが、以下の機能が追加されています。

  1. きちんとOAuth2.0認証がなされ、プリンタ登録済みでオンライン状態の場合、「サイドバーのプリンタを選択」に有効なプリンタリストが出てきます。
  2. 有効なプリンタリストを選択して、選択ボタンを押すとデフォルトプリンタとして記憶されます。
  3. ただし、プリンタがオフラインの場合、そのプリンタはリストに出てきません。
  4. テスト印刷の送信は、OAuth2.0認証がなされ、プリンタを選択済みの場合、最後に送信完了のメッセージが出ます。
  5. リフレッシュトークンの取得、およびリフレッシュトークンで自動的にアクセストークンの取得に関する機能が装備されています。
  6. アクセストークンやリフレッシュトークンの値は、ユーザープロパティに格納されており、プロジェクトプロパティではありませんので、見えません。また、ユーザプロパティであるため、そのユーザでないと値が取得できないので、他のユーザが認証を行っても、その人のユーザプロパティに格納されてしまうため、値が上書きされませんので、ご注意ください。
  7. ドメイン登録のボタンはオフになっています。実装する場合には、pdfgene.gs内のsetDomainの関数がそれなので、sidebar.htmlのボタンにイベントリスナーとして追加してください。

※ただ、4.についてはエラー処理が甘いので、OAuth2.0認証がなされていなかったりすると、ボタンを押しても何も起きません。エラーメッセージも返って来ません。

図:プリンタを選んでテスト送信できます

事前準備

自分はプリンタを持っていないので、今回は仮想PDFプリンタであるPDF Creatorをプリンタ登録します。当たり前ですが、これはCloud Print非対応ですが、非対応であっても登録が可能です。Cloud Print対応プリンタの場合、PCも必要ありません。プリンタ自体にGoogleアカウントにサインインさせることができます。メジャーな事務所用大型複合機であるXeroxのDocuCentre-IV C2263なども、CloudPrint対応だったりするので、CloudPrint用にGoogle Appsアカウントがあると便利でしょう(自分も使っています)。

今回のプログラムの環境

ちょっとややこしいので今回はイメージ図を作りました。以下のような環境で動作させています。仮想環境側とMac側の2つのChromeで、Cloud Printに於いて同じアカウントを使っています。

  1. VMware Fusionの仮想環境にはWindows8.1とPDF Creatorをインストールしてあります。ChromeにPDF Creatorをプリンタ登録しています。
  2. Mac側はChrome上でCloud Printにログインしてるだけです。
  3. Google Apps Scriptを実行すると、仮想環境内のChromeに指示が飛び、印刷が実行されます。GAS自体はクラウド上のものなので、Mac側にあるわけではありません。実行元がMac側というだけです。
  4. Androidで印刷指示をしても、仮想環境内のプリンタで印刷がそのまま出来ます。
  5. 但し、PDF CreatorはWindows上でしか動作しないプリンタです。

図:今回のプログラムのイメージ図

PDF Creatorのセットアップ

仮想マシン内のWindowsにPDF Creatorをセットアップしますが、ここでは軽く流します。今回これを使う一番の理由はAutosave機能で、印刷時に問い合わせなく、事前に指定しておいたフォルダにPDFを生成してくれるので都合が良いという理由からです。

  1. PDF Creatorをダウンロードしてインストールを完了させる。
  2. デスクトップにできたPDFCreatorのショートカットをダブルクリックして起動。
  3. Profile Settingに入る
  4. Autosaveをクリックして、Enable Automatic Saveをチェック。保存先を指定(今回はデスクトップ)。Add TokenはなにもしなくてOK.
  5. 印刷時にPDF Archtectとかいうプログラムが勝手に起動したりするので、同じセッティング画面のActionを開き、Openのチェックを外すと、静かにPDFを生成してくれます。

これでセットアップ完了です。インストール自体がちょっと時間が掛かりますが、セットアップ作業自体は対して難しくありません。

図:自動保存機能で本物のプリンタらしく実験できます。

Chromeにプリンタを追加

PDF Creatorがインストールできたら、この仮想PDFプリンターをChromeに登録します。以下の手順で登録しましょう。

  1. 仮想マシン側のChromeを起動し、右上の点マークをクリックして、設定を開きます。
  2. 一番下まで進み、詳細設定を表示をクリック
  3. Googleクラウドプリントの項目で「管理」をクリックする
  4. 従来のプリンタにて、「プリンタを追加」をクリックする
  5. ここで、Googleアカウントにサインインします。
  6. 追加したいプリンタ一覧が出てきますので、PDF Creatorのみチェックしてプリンタを追加をクリック。
  7. 準備できました」と出たらOK。プリンタの管理をクリックします。
  8. 共有ボタンを押すと、他人と共有できます。ドライブのようにメアドを入れて送るだけ。この共有アドレスは、Google Groupのアドレスでも行けるので、グループ側で管理すれば、グループアドレスを共有に追加するだけで、その人も使えるようになります。

図:PCに登録されてるプリンタが一覧に出てきます。

図:Android側Cloud Printアプリにも一覧で出てきます。

図:PDF Creatorが登録されアクティブになりました。

図:共有画面でメアドやグループアドレスを入れるとその人も使えるようになります。

印刷テスト

ここまでの段階ですでに、Cloud Printとして使えるようになっています。この状態で、他のマシン(例えばOS Xのマシン等)のChromeに同じアカウントでログインし、Chrome上で適当に印刷をしてみます。例えばGoogle Driveにあるスプレッドシートを開いて、以下の手順で印刷してみます。

  1. 事前にそのマシンでもCloud Printの設定画面よりプリンタの追加の下にログインで、ログインをしておきます。これをしないと、プリンタの一覧に出てきません。
  2. マイデバイスに登録済みプリンタの一覧が出てきます。
  3. スプレッドシートのメニューより、「ファイル」⇒「印刷」をクリック
  4. そのまま印刷ボタンをクリック
  5. 印刷の詳細設定画面が出るので、送信先の「変更」ボタンを押します。
  6. プリンタ選択画面の一番下にGoogleクラウドプリントが現れるので、選ぶか?すべてを表示をして、PDF Creatorを見つけてクリック。
  7. 印刷ボタンをクリックします。
  8. すると仮想マシン上のChromeが受信して、PDF Creatorが起動し印刷。デスクトップにPDFファイルが生成されました。

図:プリンタ指定画面の様子

図:プリンタ側Chromeの印刷ジョブの様子

Androidの場合

最近のAndroidでは、クラウドプリントは設定アプリの中の印刷の項目に存在し、単独のアプリという状態ではありません。印刷項目にいるということは、全アプリから登録済みプリンタに対して印刷ジョブを投げることが可能です。もちろん、プリンタジョブを確認したり、プリンタの追加もAndroid上で可能になっています。

印刷時は、例えばChromeアプリであれば、「共有」⇒「印刷」で指定のプリンタでプリントアウト可能です。この辺がスマートフォン独特ですね。

図:Androidから印刷中

プログラムを組む

概要

さて、これで無事に印刷の準備はすべて完了しました。あとは、Google Apps Scriptで例えば色々とスプレッドシートのデータをスクリプトから指定のプリンタへ自動で投げるというコードを記述します。例えばこれにスクリプトトリガーなどを組み合わせて、真夜中に1日に申請のあったデータ類から個別にスプレッドシートを作成し、個別にPDF化して、自動で印刷なんてものを組んだときに、翌朝出勤すると紙の用紙で申請書が出来上がってる、なんて事が可能になります(普通溜め込まずに随時印刷するとは思いますが)。

クラウドプリントですが、事前にOAuth2.0認証を必要とするため、スプレッドシートからの事前準備が必要になります。

事前準備

Developer ConsoleよりOAuth2.0クライアントIDが必要になります。

  1. いきなりですが、ウェブアプリケーションとして公開します。
  2. 公開するとURLが出て来るので、execのURLを控えておきます。
  3. スプレッドシートのスクリプトエディタを開き、メニューより「リソース」⇒「Googleの拡張サービス」を開きます。
  4. Googleデベロッパーコンソールをクリックします。
  5. 認証情報をクリックします。
  6. 最近は、自動でOAuth2.0クライアントIDが作成されてるようで、すでにもう出来上がっています。App Scriptというものをクリック。
  7. このままでは使えないので、承認済みJavaScript生成元にhttp://script.google.comを入力
  8. 続けて承認済みのリダイレクトURIに2.で手に入れたURLを入力。
  9. 表示されてるクライアントIDクライアントシークレットを入手します。

ソースコード

StackOverFlowにてGoogle Cloud Printを実現するコードが公開されているのですが、あれはあのままでは使えません。また、Google Apps ScriptのOAuth2認証ライブラリを使っているのですが、これも古くて使えません。エラーを吐きます。ですので資料としてPDFを作成のエントリーで記述した、OAuth2.0認証フローを装備します。OAuth2.0認証フローの装備そのものは、そちらを参照してください。

まずは、PDFを作成のエントリーのコードで変更した箇所を下に示します。

OAuth認証コード変更した部分

変更点は

  • 認証用URLの出力に於いて、scopesにhttps://www.googleapis.com/auth/cloudprintを追加しました。
  • OAuth2のアクセストークンを取得するに於いて、変数tokenの取得部分。返ってくるresponseが仕様変更なのかオブジェクトで返ってくるので、tokenResponse[“access_token”]に変更しました。
  • ユーザプロパティに格納では、HIROという名前のユーザプロパティにtokenを格納するようにしました。これはプロジェクトプロパティからは見えません。

クラウドプリントコード

続いてクラウドプリントのコードですが、以下のような感じになります。

若干変更を加えています。この中でプリンターに細かな印刷指定を行うセクションがticketと呼ばれる部分で、枚数や方向などを指定できるようです。これらのオプション項目に関してはこのページに記載されています。ticketのversion指定は、1.0と2.0の2つがあり、Xerox DocuCentre C2263でクラウドを介さずにプリントする時には、version2.0を指定してくださいという指示があるので、それに従って使い分けます。以下のような感じで指定をします。

getPrinterList()では、JSONで登録済みプリンターの様々なデータが以下のような形で返ってきます。

このうち、重要なのはid:の部分で、ここにプリンターIDが入っています。また、プリンター名は、descriptionかdisplaynameから取得ができます。これを元に例えば実際にプリントをさせるとなると、GASに以下のコードで、このprintGoogleDocument()に投げてあげます。

これで、testprintを実行すると、CloudPrintを設定してる、今回で言えば仮想マシン側のChrome経由で、PDF Creatorが起動してPDFファイルになってデスクトップに出力されます。普通のプリンターであれば、紙に印刷されて出て来るわけです。また、今回はPDF化するルーチンを使いまわしていますが、PDF化したものをこのルーチンの流れに組み込めば、自動化が完成するという仕組みです。

実際にリリースする場合には、リリース直前で一度版を変えてウェブアプリケーションとして公開を実行しておきましょう。実はこれが重要で嵌りどころです。開発中もGAS側コードを変えたら、随時この作業を行うと嵌まらずに済みます。

あとはできれば、スプレッドシート側にプリンターの選択画面やら、選択したプリンターのIDを格納しておくような仕組みを設ければBESTです。

OAuth認証の実行結果

さて、プリントアウトを実施するには、OAuth2.0認証をしなければなりません。この部分はすでにGoogle Apps ScriptでPDFを作成するのコーナーで紹介済みなので、サイドバーから認証を実施し、以下のような画面がでればOKです。また、取得したAccess Tokenがきちんと取得できており、プリンタがオンラインの状態であれば、印刷する事が出来ます。紙がまだ重要視されてる日本では特に有用でしょう。紙での印刷物でなければ絶対に受け取らない経理課のお姉さんもこれなら納得です。

図:認証時の承認画面にプリンタの管理が登場

リフレッシュトークンの取得と新しいトークンと交換

取得したAccess Tokenは1時間で使えなくなってしまいます。その為このままでは自動化はできません。再度、OAuth2.0認証を手動で実行しなければなりません。これでは不便です。以下のような関数の追加と変更を加えると、最初の認証時にrefresh_tokenも取得でき、またそのrefresh_tokenを使って新しいTokenを取得できます。

OAuth2.0認証コードの変更点

認証用URLの出力部にて、URLに新しく‘&access_type=offline&approval_prompt=force’を加えています。これで認証実行時に「オフラインアクセスが可能」といった認証が出るはずです。これを追加しないと、refresh_tokenが取得できません。

また、OAuth2のアクセストークンを取得するの部分では、返ってきたレスポンスのうち、tokenResponse[“refresh_token”]で、refresh_tokenを取得し、refreshというユーザプロパティに新しく格納しています。この値を次のコードで利用します。

図:毎回必ず認証時はこれが出るようになります

トークンリフレッシュの実行

tokencheck()関数では、tokeninfoのURLにGETで投げて、ret.errorが取得できれば「NG」を返すようにしています。そうでなければ「OK」を返すようにしています。プログラム中でこの関数を実行して、OKならそのままクラウドプリントに投げて、NGならば次のgetNewToken()関数を実施して、再度新しいTokenを取得するようにします。

getNewToken()では、POSTの組み立てが少し変わっています。payloadの中身がgrant_type=refresh_tokenとなり、refresh_token=に取得済みのrefresh_tokenの値をつなげます。再度返ってきたAccess Tokenをユーザプロパティに格納しています。この時新しいリフレッシュトークンというものは返ってきません。同じrefresh_tokenを使って、何度でも新しいAccess Tokenが取得できるようになっています。

ただし、tokencheck()してからOKだったからといって続行したら、ギリギリアウトでしたというケースも無くはないので、プリントを一旦実行してみて、エラーになったら、getNewToken()を実行して、再度プリント実行を再帰的に呼び出すといったほうが良いと思います(無限ループにならないように、getNewToken()でエラーになったら、breakするようにしましょう)。エラーの取得方法は例えば次のような感じ。

実行時エラーの取得

getPrinterList()を実行しても、tokenが取れていなくても、そのまま素通りしてしまいます。ただしHTMLでエラーが分かるので、エラー内容は以下のような感じ。

なので、これをスクレイピングします。H2タグの中身が良さそうなので、以下のような感じでコードを追記します。

すると、Logger.logには、「Error 403」という値が取得できます。Error 403の場合はtoken認証ができていない証拠なので、これを条件にしてgetNewToken()を実行するといったような感じです。

問題がなければ、プリンターリストを色々どうにかするルーチンを実施して、ユーザにプリンタを選んでもらうようなダイアログを表示するというのが良いでしょう。Error 403ならば、新しくgetNewTokenでトークンを取得し直して、自分自身をもう一度実行するように、getPrinterList()を実行するといった手順です。getNewToken側では、try{}catch(e){}でエラーが出たら、NG判定を出してあげて例えば以下のようにすると、無限ループせずに済みます。

こんな感じにすると良いでしょう。リフレッシュトークンに関するドキュメントはこちらを参照してください。

ポイント

  • 事前にスクリプト内でOAuth2.0認証をしておかなければならない。
  • その為、ScriptApp.getOAuthToken()だけでは、プリントアウトする事ができない。
  • Cloud PrintのOAuth2.0認証時に使うScopeは、https://www.googleapis.com/auth/cloudprintです。printではありません。
  • JavaScriptから使うときには、このページにあるように、https://www.google.com/cloudprint/client/cpgadget.jsを必要とします。
  • Google Apps Script自体には印刷に関するメソッドがない為、プリンタを操る手段は実質これだけになります。
  • Access Tokenは1時間でexpireしてしまうので、実際にはプリント実行時には、access tokenがexpireしていないかチェックするコードと、expireしている場合には、refresh Tokenを使って新しくAccess Tokenを取得するコードの2つが必要になります。
  • ScriptApp.getOAuthToken()では今回の有効なAccess Tokenは取得できません。今回のAccess TokenはGASとしてではなく、ブラウザ上で取得してる別物です。
  • 相手のプリンターがオフラインで、尚且つきちんとAccess Tokenが取得できている場合、印刷を実行するとどうなるかというと、印刷ジョブにプールされたままになり、結果も印刷したという結果になります。相手のプリンターがオンラインになり、相手のChromeが起動すると自動的に印刷が始まります。
  • 一度セットアップが完了すると、プリンタと接続してるChromeを起動していなくても相手のマシンがONならばプリントアウト出来ました。何か後ろで動いてるんでしょうね。

関連リンク

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