Google Apps for Workは日本でいったいどれくらいの企業が採用しているのかわかりませんが、月500円/人で利用できるクラウド型イントラ兼グループウェアとしてみた時、コストパフォーマンスは非常に高いと思います。そこへGoogle Apps Scriptが扱えるのであれば、拡張性やその自由度も飛躍的に高まるということで、自分も仕事上で利用しています。とは言え、オーバースペックだから、特定のメンバー以外は特定機能だけ使ってもらえばと言っても、アプリケーション毎の制限はAdminで設定可能なのですが、極めて細かい制限を設定出来るという訳ではありません。

そんな中、先日、Google Apps Script Execution APIがリリースされた事もあり、以前紹介したRPi2でGoogleスプレッドシートへアクセスにて、Node.jsを使ったデータの取得をもう一歩すすめて、Execution API + Node.jsを使っての読み書き、尚且つ、Electronでアプリ化してみようと思いました。OAuth2.0認証を利用しますので、アプリのユーザはGoogle Appsのアカウントがなくとも、特定のスプレッドシートの読み書きが可能になります。

Google Apps Scriptネタではありますが、今回はElectronアプリの作り方的なまとめになっています。今回は簡単なおみくじアプリを作ってみます。別途応用編にて、簡易タイムレコーダの作成とパッケージ化についてまとめたいと考えています。

目次

使用する素材類およびメソッド類

Electronとは?

Electronとは、Node.js + JavaScript + HTML5の組み合わせで、オープンソースウェブブラウザのChromiumを土台としてアプリケーションとしてパッケージにし、クロスプラットフォームで動かせるようにしてくれる便利なツールです。ベースの開発環境そのものはNode.jsそのものなので、Node.jsの様々な拡張機能を扱えるだけでなく、Electron特有の機能によってよりデスクトップアプリケーションとして動くように作ることが可能です。

JavaScriptオンリーでデスクトップアプリが、しかもWindows, Mac OS X, Linux向けに無改造でリリースが出来る、Node.jsを利用してる為、通常のJavaScriptでは出来ない「ローカルファイルへのアクセス」や「クロスサイト」なアクセスが可能になってるのも特徴です。ウェブは得意だけれどローカルアプリケーション作成はちょっと・・・という人が、スキルそのままにアプリケーションを作れるのは一石二鳥です。

また、JavaScriptですので、クライアントサイド(GUIを担当)では、数々のJavaScriptライブラリを利用する事が可能になっています。よって、リッチなGUIを簡単に構築出来るだけでなく、フレームワークを利用したりも可能。

似たような仕組みとして、NW.jsというものがあります。Electronと比較した時に一長一短なので、どちらが優れているとは言えないのですが、そのあたりを比較した方がいらっしゃいますので、こちらのサイトを一度覗いてみて、どちらを使うかを決めても良いかと思います。

事前準備

作成に当たっては事前準備が必要です。ここで必要な準備は、お使いのマシンにNode.jsのインストールとElectron開発環境を整える事になります。基本、Mac OS Xでの利用を前提に話を進めますが、インストール自体は簡単なので、WindowsであってもLinuxであっても殆ど変わりません。インストールしたパスだけ注意しておいて下さい。

Node.jsとその他をインストール

コマンドラインでのインストール(homebrewを使った手法)もありますが、ここでは手軽に、インストールパッケージを利用します。以下の手順でパッケーを入手しダウンロードしましょう。また、Node.jsで利用する、今回使う予定のモジュールもインストールしておきましょう。

Node.jsをインストールする

現在、最新版はv5.6.0となっています。以下の手順でnode.jsをインストールします。

  1. Node.jsからnode-v5.6.0.pkgをダウンロードする。Windowsならnode-v5.6.0-x86.msiとなります。
  2. ダブルクリックで実行して、インストールを進める。
  3. 最後にインストールしたパスが表示されて終了。

screenshot_342

図:インストール自体は超カンタン

ここで一応、ターミナルを起動して、node.jsおよびnpmのバージョンを確認しておきましょう。Windowsの場合は、コマンドプロンプトになります。

  1. ターミナルを起動する
  2. node -vコマンドにて、バージョンを確認する
  3. npm -vコマンドにて、バージョンを確認する

screenshot_344

図:バッチリ最新版になってるのを確認した。

追加モジュールをインストール

今回作成するプログラムで使用する追加モジュールをインストールします。npmコマンドを使用してインストールするのですが、今後色々なシーンで必要になるコマンドなので覚えておきましょう。以下のようなコマンドで実行をします。

この時、オプションとして -gを指定しておくと、直接実行が可能になります。無い場合には自分のホームディレクトリのフォルダにインストールされます。なので、自分の場合必要な物はこのコマンドにオプションをつけてインストールしています。ちなみに、npm install xxxxxの場合、ネットからダウンロードしてインストールしますが、直接特定のフォルダ内にあるパッケージをインストールする場合には、そのフォルダまで移動してから、npm installと実行するだけで、中に入ってるpackage.jsonを読み取ってインストールしてくれます。

GoogleのNode.js Quickstartによると、2つのモジュールが最低でも必要との事なので、ターミナルより2つをインストールします。

Raspberry Piの回ではedit-google-spreadsheetをインストールしていましたが、今回は使用しません。

screenshot_345

図:npmでモジュールをインストール中

Electronとその他をインストール

Electron本体をインストール

Electron自体もnpmの追加モジュールになっています。よって、node.jsの追加モジュールと同様にインストールするのですが、自分の場合エラーが出て嵌まりました。よって、その解決法も含めてここに記述します。electronはsudoでインストールしますのでご注意を(Windowsにsudoはありませんので、sudoは不要です)。

現在最新版は、v0.36.8となっています。バージョンの確認は、ターミナルにてelectron -vで確認が出来ます。

screenshot_347

図:ちゃんとv0.36.8である事を確認した。

本体インストール時にエラーが発生したら

上記のコマンドでインストールをしたら、エラーが発生して、electronモジュールをインストール出来ないケースがあります。通常はsudoでインストールを実行していればエラーは出ないのですが、あるケースではこれでもダメです。其の時には、以下のコマンドをターミナルより実行して、electron-v0.36.8-darwin-x64.zipがダウンロードされる~/.electronフォルダのパーミッションを変更して上げましょう。参考:Failed at the electron-prebuilt@0.25.3-2 install script ‘node install.js’

errorelectron

図:electronインストールエラー発生しちゃった

追加モジュールをインストールする

electronはこの段階で既に作成が出来るのですが、配布する為にはパッケージ化が必要です。その為のモジュールをインストールしておく必要性があります。

これで、アーカイブ&パッケージ化するためのモジュールがインストールされ、準備万端です。

Google Apps Script側の準備

Electronの開発環境は整ったので、次にGoogle Apps Script側の準備をします。この部分はGoogle Apps Scriptを外部のJavaScriptから実行するでもまとめているので、ここでは簡略化して説明を進めます。

OAuthクライアントIDを取得する

今回使用するスプレッドシートをコピーしたら、Developer Consoleで以下の作業を行い、OAuthクライアントIDとクライアントシークレットを取得します。

  1. メニューより「リソース」⇒「Googleの拡張サービス」を開きます。
  2. 出た画面の下にある「Googleデベロッパーコンソール」をクリックします。
  3. 概要画面が出たら、「Google Apps Script Execution API」を検索して、有効にします。
  4. 次に認証情報を開き、「新しい認証情報」をクリックし、「OAuthクライアントID」を選択します。
  5. アプリケーションの種類は「その他」を選択し、作成します。
  6. 適当な名前を入れます。今回はElectronという名前をつけました。
  7. これで作成すると、クライアントIDが発行されます。
  8. 一旦そのダイアログを閉じて、OAuth2.0クライアントIDのリストがありますので、Electronと名前の付いたレコードの右にfiledownloadのアイコンがあるので、クリックする
  9. OAuthクライアントIDとクライアントシークレットが含まれたjsonファイルがダウンロードされるので取っておく。後で使用します。名前はclient_secret.jsonという名前で保存しました。

oauthnodejs

図:今回はJSONファイルの形で利用します。

JSONファイルの中身は以下のようなもので、アクセストークン、リフレッシュトークン、失効する時間が記載されています。

expiry_dateが失効時間でおよそ1時間でこのアクセストークンは使えなくなります。その時は、リフレッシュトークンを使って新しいアクセストークンを取得する必要があります。

適当に関数を作成する

今回は入門編という事で、おみくじアプリを作ります。スプレッドシートにはおみくじデータが、dataシートに入っています。これをランダムに取得するようなコードを書き、APIを叩くとそれらのうち1つが返ってくるというものです。以下のようなGASのコードを書きました。環境に合わせて変数sheetのシートIDを書き直すのを忘れずに。

これで、omikujiという関数が出来ました。

実行可能APIとして導入する

つづいて、スクリプトエディタ上でこのスクリプトの関数を実行可能APIとして導入します。実行可能APIとして導入はソースコードを修正するたびに、導入を実行しなければいけませんので、注意が必要です。

  1. スクリプトエディタのメニューより、「公開」⇒「実行可能APIとして導入」を実行します
  2. 適当にバージョンの説明を入力して、更新ボタンを押すと現在の API IDが取得できます。アクセスできるユーザは全員で良いでしょう。

screenshot_351

図:おみくじAPIがこれで完成です。

Electronアプリの作成

Electronでアプリを作る場合、Node.jsの流儀に従う事になるのですが、Electron特有の流儀というものもあるので、ちょっと複雑です。また、Node.jsの流儀はちょいと癖があって、Electronでアプリを作る場合、Node.js側(メインプロセスと呼ぶ)にHTML側(レンダラプロセスと呼ぶ)からアクションを送って、返り値をどうこうするといったプロセスだけでも結構大変でした。この辺りも含めて、解説してみたいと思います。

空のプロジェクトとファイルを作成

まずはホームディレクトリ(Macだとユーザのフォルダ)内に、プロジェクトのフォルダとファイル(package.json)を作成します。また、同じフォルダ内にプログラムの塊になるindex.jsとインターフェースとなるindex.html、Developer Consoleで入手したclient_secret.jsonを入れます。まずは、ターミナルを起動して、以下のコマンドを入力します。

1行目で、omikujiというディレクトリを作りました。2行目でそのディレクトリの中に移動して、npm init -yでpackage.jsonが作成されます。同じ、omikujiディレクトリの中に、テキストエディタ等で空っぽのindex.js、index.htmlを作成し保存、また、予め入手していたclient_secret.jsonを入れます。コレでプロジェクト開始の準備はOKです。

screenshot_353

図:プロジェクト作成とファイルの配置

package.jsonの中身は以下のようなものですが、デフォルトでindex.jsがmainとして指定されています。以前はmain.jsだったのですが。よって、このindex.jsがプログラムの中心となります。

index.js

Electronアプリの最も中心となるのがこのindex.jsの作成です。今回の主要な部分は、Google Developerのサンプルコードを改造して使用しています。OAuth認証用コードと、Google Apps Script側にある「omikuji関数」を叩き、結果をHTML側へと渡す形になっています。

ソースコード

script.jsの中身は以下のとおりです。

解説

★追加モジュールの宣言

requireと続けてモジュールの名前をつけて変数に入れています。こうする事でNode.jsは事前にnpm installしておいたモジュールをプログラムで利用する事が出来るようになります。デフォルトで用意されてるモジュールもありますが、今回は別途追加した

  1. googleapis
  2. google-auth-library

の他に、Electron特有の追加モジュールとして必須なモジュールとして以下の2つを必ず宣言します。

  1. app
  2. browser-window

また、Node.js側とHTML側とでやり取りをするのに利用するipcモジュールを今回は導入しています。それが、ipcMain = require(‘electron’).ipcMain;です。

★Google appsとスコープ関係

scriptIdには、Google Apps Script上で「実行可能APIとして導入」後に表示されるAPI IDを入れます。スプレッドシートのIDではありませんので注意!また、SCOPEは本プログラムに於いて利用するGoogleのサービスを指定します。今回はSpreadsheetAppしか使っていないので、スコープとしてhttps://www.googleapis.com/auth/spreadsheetsを入れています。この辺りについては、Google Apps Scriptを外部のJavaScriptから実行するに詳しくまとめています。

★app.onとmainWindowについて

mainWindowをグローバル変数として宣言して起きます。続けて、app.onという項目が出てきますがこれが、Electron特有の仕組みです。この辺りのコードはお決まりとして必ず記述します。特に変わった記述をする必要性はありません。但し、mainWindowに対してnew BrowserWindowしてる部分。オプションとして縦横のサイズとautoHideMenuBarという設定を追加しています。デフォルトでメニューバーが表示されるので、falseで非表示にしています(但し、Mac OS Xでは無視されます)。

このオプション項目は非常に沢山あるので、オプション項目を見て追加しましょう。ウィンドウの挙動に関するものがズラっと列挙されています。

※オプションとして、mainWindow.webContents.openDevTools();の1行を入れておくと、Chromiumのデバッガーツールが最初使えるようになるので、開発中は入れておくと良いでしょう。

※尚、デバッガーツール上記の1行をいれずとも、OSXならCommand + Option + iキー、WindowsならばCtrl + Shift + iキーで表示が可能です。

★ipcMain.onについて

HTML側からipc通信で送られてきたら受け取る側がコレ。asyncと名前がついています。相手はこの名前でこのコード宛にデータを送り、受け取った側はそれまでずっと待機しています(この辺りがNode.js特有の癖ですね)。受け取るとプログラムが動き、認証用スクリプトが動くようになっています。

似たようなモジュールとして、remoteというモジュールがありますが、こちらはNode.js側やHTML側を直接双方から操作するものとの事。まだ使ったことないですが。

★OAuth認証関係のスクリプトについて

この辺はGoogle Developerに掲載されてるものです。authorize(), getNewToken(), storeToken()はほぼそのまま利用しています。しかし、getNewToken()については少々改造しています。元のコードがNode.jsアプリとして動かした時を想定してるものであって、このままではElectronでは動かせないからです(readlineのquestionという文字列の出力と入力待ちが動かない為です)。

ここはほぼスクリプトを削除して、mainWindow.webContents.send(‘async-url’, authUrl );  にて、ipc通信を行い、HTML側のasync-urlに対してauthUrlを送り込んでいます。JavaScript側でダイアログ表示、入力待ちをさせ、認証コードを受け取らせるようにしています。

※但しこのスクリプトはrefreshTokenを使ってexpireした時に新しいアクセストークンを取得するコードが欠けてる為、そのコードを追加してあげないといけません。

★callAppsScriptについて

ここがGoogle Apps Script Execution APIを叩くメインのスクリプトです。今回は引数なしでomikujiという関数を叩き、resp変数でreturnされてきた値を受け取っています。その後失敗した場合のエラー処理が入っています。

最終行にあるmainWindow.webContents.send(‘message’, unsei ); がHTML側へipc通信で通知し、HTML側はこれを受け取ったらalert表示するようになっています。

index.html

今回のアプリケーションはおみくじアプリですので、ボタンが1個あるだけです。よって非常にシンプルなボタンと、押した時にNode.js側に問い合わせと返り値をダイアログで表示する簡単なプログラムが入ってるだけです。

ソースコード

解説

★冒頭部分

Node.jsのメインファイルであるindex.jsを呼び出すために、<script src=”index.js”></script>として追記しています。また、jQueryUIやCSS関係の呼び出しの他に、script.jsを呼び出していますが、この中身は、var $ = jQuery = require(“./js/jquery-2.1.4.min.js”);のみです。jQuery本体だけは、このような特殊な呼び出し方をしないと動作してくれないので、このような書き方になっています。

★IPC通信を行う

Electronでは、HTML側でもNode.js側のようにモジュールをrequireする事が可能です。ここで、Node.js側でも使ってるipcモジュールをrequireしてipcRenderer.onでNode.js側からの通信を待機させる事が可能です。逆に送る時は、ipcRenderer.sendに名前を付けて上げるとNode.js側のipcMainが受け取ります。

★その他

最初の1回、認証を実行し認証コードを入れさせるためのダイアログを表示するようにしています。その部分が一番したのコード送信ダイアログの部分。jQueryにてダイアログで表示する時のコードが入っています。また、Node.js側から送られてくる認証用URLを動的に<p id=”authman”></p>に書込も行っています。

実行と結果

コードの記述が完了したらテスト実行していましょう。以下のコマンドで実行する事ができます。今回のプロジェクトフォルダはomikujiなので、そのフォルダの中にまではいかずにホームフォルダ直下の状態で実行します。ターミナルやコマンドプロンプトを起動してすぐ実行してみましょう。

無事に問題がなければ、Electronアプリとして起動します。但し、本コードの場合、最初の1回は、OAuth2認証作業があるため、以下の作業を要求されます。

  1. OAuth2認証作業ダイアログが起動し、URLをクリックするよう要求されるので、クリックする
  2. 自分のGAアカウントでログインをすると、認証用のコードが発行されるので、コピーする
  3. ダイアログのテキストボックスにそれをペーストして、送信ボタンを押す
  4. 問題がなければ、これで続けてExecution APIが実行されて、おみくじが返って来る
  5. index.jsと同じフォルダにアクセストークンファイル(script-nodejs-quickstart.json)が格納される。
  6. 次回以降はそのまま起動するだけです。

oauthelectron omikujipon

図:左は認証コード要求画面。右はおみくじを引いてみた画面

screenshot_354

図:同じアプリをOSXでビルドしてみた

注意事項

  • OAuth2.0の最初の認証はGoogle Appsのアカウントを持つ人間が認証を実行し、script-nodejs-quickstart.jsonを取得しなければなりません。
  • 今回のElectronアプリはrefresh_tokenの処理がない為、一定時間を経過するとOAuthトークンがexpireしてしまいます。その為、その都度、script-nodejs-quickstart.jsonを廃棄する必要性があります。
  • script-nodejs-quickstart.jsonは、index.jsと同じフォルダに生成されますが、本質的にはどこか別の場所に配置しておいたほうが尚良いです。ただしその場合、ディレクトリやファイル生成の権限がないとエラーになりますので、注意が必要です。
  • ElectronはGUIアプリケーションですので、認証時取得コードやURLの表示はコマンドプロンプトに出力しても意味がありませんし、readline.questionが使えない為、取得コードを入力ができません。その為、jQuery DialogでURLの表示と入力を促す処理を追加しています。
  • Node.js側とHTML側との通信には、ipcを使用しています。よって、Node.js側でのmainWindow作成時オプションとして、nodeIntegration:falseといったオプションを指定してしまうと、使えなくなってしまいます。
  • 今回はDialog生成にjQueryを使用していますがそのままでは、Electronアプリでは利用ができません。そこで、var $ = jQuery = require(“./js/jquery-2.1.4.min.js”);といった形でライブラリを読みこませる必要があります。jQuery UIやCSS類はその必要性はありません。
  • OSXの場合、メニューバーの非表示はできません。また、Windowsの場合、デフォルトでメニューバーが表示されているので、これをmainWindow作成時オプションとして、‘autoHideMenuBar’:trueを追加する事で非表示にする事が出来ます。
  • testAsync()は起動時に1回だけ実行させるだけでOKです。あとは待機しています。
  • スプレッドシートが非公開の場合、APIが実行できなくなります。また、実行可能APIの実行可能権限が自分だけの場合、そのGAアカウントで認証実行しないとやはり、APIは実行できません。

関連リンク

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