Electronをブラウザとして使う場合の証明書エラーとBasic認証の処理
ElectronアプリのUIは基本的にローカルのHTMLファイルを利用して作るので、パスさえ間違えなければ間違いなくHTMLをロードして表示できます。
しかし場合によっては<webview>
を使って簡易ブラウザ/アプリ内ブラウザのようなものを実装することもあるかと思います。
このときに少しハマったところがあったのでメモとして残しておきます。
SSL/TLS証明書エラー
httpsを使う時にSSL/TLS証明書の検証でエラーがある場合*1、Electronは何もせず通信失敗となります。
この時app
モジュールのcertificate-error
イベントが発生するので、event.preventDefault()
で元の動作を止め、callback(true)
を呼び出すことでエラーを無視して通信を続行することができます。
問答無用でエラーを無視してもいいですが、ユーザーに確認させたいのであれば以下のようにcallback
を非同期で呼び出すことができます。
app.on('certificate-error', function(event, webContents, url, error, certificate, callback) { event.preventDefault(); electron.dialog.showMessageBox(mainWindow, { title: 'Certificate error', message: `Do you trust certificate from "${certificate.issuerName}"?`, detail: `URL: ${url}\nError: ${error}`, type: 'warning', buttons: [ 'Yes', 'No' ], cancelId: 1 }, function(response) { if (response === 0) { callback(true); } else { callback(false); } }); });
Basic認証
こちらもやはり、そのままではElectronは何もしてくれません。
login
イベントが発火するので、これを使います。
// Quoted from electron.atom.io app.on('login', function(event, webContents, request, authInfo, callback) { event.preventDefault(); callback('username', 'secret'); });
こちらはかなり厄介です。
証明書エラーの時のようにユーザー名とパスワードの入力を促すダイアログを出したいところですが、Electronはテキスト入力をGUIで受け付けるためのAPIを持っていないからです。
ブラウザ側で動作するRendererプロセスであってもwindow.prompt
さえサポートされていません。*2
つまり、ユーザー名・パスワードの入力ダイアログはなんとかして自力で用意しなければなりません。 自分の場合はRenderer側でBootstrapを使っているので、そのダイアログを利用しようかと思っています。 あるいは入力ダイアログ専用のBrowserWindowを作成してしまうのも手かもしれません。
*1:通常のブラウザであれば警告表示になる場面、例えば自己署名証明書
*2:スレッドをブロックするからなんだとか。必要ならHTMLで入力場所作れるから十分でしょ?みたいな雰囲気を感じる https://github.com/atom/electron/issues/472
ブログを移行しました
https://airwalker00.wordpress.com/ から移行してきました。
wordpress.comが良くなかったというわけではないんですが、自分みたいな記事だけ書く人間にはwordpressを使えることのメリットがあまりなかったように思います。 確かにwordpressが使えるけどそれ以上でもそれ以下でもなく。 CMSとして使っていたわけではないですし、プラグインがほぼ使用できないので実はwordpressである意味がほぼないという...
ブログタイトルはふっと浮かんだものなので特に意味とか無いです。〜's Blogとかよりはいくらかマシかと。
何はともあれよろしくお願いします。
Electronのデフォルトフォントを変更する
前記事でElectronのフォントを変更する方法を書いていたのですが、0.36になってからは内部のChromeのバージョンが上がり、この方法が使用できなくなっていました。しかし最近公開になった0.36.5で、ついにデフォルトフォント関連のパラメータを指定する機能が追加されました。(と言っても、自分にとって重要なwebview
への対応はまだなのですが...)
この機能の使い方自体は難しくなく、BrowserWindow
でウィンドウを作成する際、オプションのwebPreferences
に使用したいフォントを指定してあげるだけです。ざっと確認した限り、すべてのパラメータを指定する必要はないようです。
// main.js var mainWindow = new BrowserWindow({ webPreferences: { defaultFontFamily: { standard: 'Meiryo UI', serif: 'MS PMincho', sansSerif: 'Meiryo UI', monospace: 'MS Gothic' } // 他、以下のパラメータが設定可能 // defaultFontSize // defaultMonospaceFontSize // minimumFontSize // defaultEncoding } });
フォントの選択機能を付けるのであれば、以下のページが参考になるかと思います。
Electronの中華フォントを克服したかった
Electronでは楽にアプリを作れるのは良いのですが、日本語についてはいわゆる中華フォントが表示されてしまうという問題がありました。
これを解決する方法を見つけた、という記事を元々書こうとしていたんですが、つい最近リリースされたv0.36.0で内部のChromeのバージョンが47に上がったせいか、きちんと日本語フォントで表示されるようになっていました。(たぶんChrome 47と同じくMS P ゴシック)
とはいえ、webViewの中身のフォントを外部から変えるといった用途には使えるので一応書き残しておきます。
※2016/01/19 追記 この方法はElectron 0.36 (自分が確認した限りでは0.36.3)では使えなくなっています。Chrome 45から47になる際にフォント関連の動作が変わっているようです。日本語フォントになっただけでも0.35よりは大きく改善されているとはいえ、デフォルトフォントを変えるAPIが無いのはつらいですね...
※2016/01/30 追記 Electron 0.36.5からはデフォルトフォントを変更にできるようになりました。適切に活用していきましょう。->Electronのデフォルトフォントを変更する
ローカルのHTMLファイルをロードするようなElectronアプリの場合、通常通りCSSでfont-familyを指定してやればもちろんフォントを変更できます。
一方、webViewタグを使って外部ページをロードする場合、当然ながら元のサイト側でフォントが指定されることになります。
このとき、sans-serif
やmonospace
が適用されるとElectronでは中華フォントが使用されてしまっていました。
webContentsやwebViewタグではinsertCSS()を使ってCSSを後から適用できますが、当然ながら全要素のfont-familyを変更するわけにはいきませんので、うまくこの問題を解決できませんでした。
結局のところ今回は、実行環境が日本語Windowsだった場合、font-faceを使ってMeiryo UIとMSゴシックをそれぞれsans-serif
とmonospace
として設定する、という方法をとりました。
(Mattermostでは基本的にfont-family: 'Open Sans', sans-serif;
でフォント指定されているため)
まずWindowsのロケールを判定するためにos-localeをインストールしておきます。
$ npm install os-locale
あとはfont-faceを設定するためにCSSを準備しておき、webViewのDOMの準備ができたタイミングでinsertCSS()でCSSを適用します。
/* jp_fonts.css */ @font-face { font-family: sans-serif; src: local("Meiryo UI"); } @font-face { font-family: monospace; src: local("MS Gothic"); }
/* index.js */ const osLocale = require('os-locale'); webView.addEventListener("dom-ready", function() { if (process.platform === 'win32') { var applyCssFile = function(cssFile) { fs.readFile(cssFile, 'utf8', function(err, data) { if (err) { console.log(err); return; } webView.insertCSS(data); }); }; osLocale(function(err, locale) { if (err) { console.log(err); return; } if (locale === 'ja_JP') { applyCssFile(__dirname + '/css/jp_fonts.css'); } }); } });
前の記事のデスクトップ通知もそうですが、こんな強引に見える方法が動いてしまうHTML関係っていかがなもんなのかとは感じます。
Electronのデスクトップ通知の動作を変更する
ElectronではNotificationを使ってWebアプリケーションと同様にデスクトップ通知をすることができます。 しかし、electron-mattermostのようにBrowserWindowやWebViewに外部HTMLを読み込んで表示するだけのアプリケーションでは、通知の動作が外部HTMLによって操作されるので、元のElectronのままでは以下のような動作を実現することができませんでした。
- 通知をクリックしたときに、隠した/最小化したBrowserWindowにフォーカスを移し、かつ元々のNotification.onclickを実行する
- 通知方法を変更し、Windows 7ではトーストの代わりにバルーンを表示する
そこでNotificationを直接上書きしてみたところ、デスクトップ通知の動作を変更できました。
var NativeNotification = Notification; Notification = function(title, options) { this.notification = new NativeNotification(title, options); }; Notification.requestPermission = function(callback) { callback('granted'); }; Notification.prototype.close = function() { this.notification.close(); }; Notification.prototype.__defineSetter__('onclick', function(callback) { this.notification.onclick = function() { electron.remote.getCurrentWindow().show(); callback(); }; });
通知を表示する部分に関してはElectronに頼りたいので、NativeNotificationに元々のNotificationを保持させておきます。その後、Notificationのコンストラクタやメンバを再設定することで通知動作を変更する、というコードになっています。
このコードでは受け取った通知関連のパラメータをそのままthis.notificationに渡してやることで元の通知動作を維持しつつ、通知元のBrowserWindowを表示します。Electronの通知でなく他の方法で通知を表示したければ、コンストラクタの中身を書き換えることになります。後はHTML側で通常通りnew Notification()
が呼び出されたときに、変更された動作を使って通知を発生させられます。