すでにWeb版が存在してるけどショボいのでネイティブアプリでいい感じにしたいときがあったりすることもあります。
これを、Electronで作ったネイティブアプリの画面上に見えないwebviewを置くことで実現します。
方法
見えないwebviewの埋め込み
Electronアプリにwebviewを埋め込むことは簡単でただ
次にこれを非表示にします。 非表示というと普通はdispaly: noneを使いますが、display: noneでは残念ながらwebviewの中身が実行されません。 そこでwidthとheightを0にしてやることで非表示にします。
webviewの通信
webviewはrendererプロセスとは別プロセスになるのでwebview内のjsとrendererプロセスのjsでやり取りするにはプロセス間通信をする必要があります。
rendererプロセス→webview
webviewエレメントのsendというメソッドがあるのでこれを叩くことで、webview側にイベントを送ることができます。
webview側でこのイベントを受け取るには、受け取る用のjsファイルを用意してpreloadを使って読み込ませます。 そしてその受け取る用のjsファイルの中でipcRenderer.onを使ってrendererプロセスからのイベントを受け取ります。
webview->rendererプロセス
webviewからrendererプロセスへのイベントの送信はipcRenderer.sendToHostを使います。
rendererプロセス側でこのイベントを受け取るにはipc-messageをaddEventListererで登録すればよいです。
具体例
electron-vueでやる場合の例です。
<template> <div> <webview id="webview" v-bind:preload="preloadJS()" src="https://facebook.com" style="width:0;height:0;" > </webview> </div> </template>
<script> import path from 'path'; import { remote } from 'electron'; let webview = null; export default { data: function() { return { userId: '', password: '', } } mounted: function() { // webviewからのイベントの受信 webview = document.getElementById('webview'); webview.addEventListener('ipc-message', event => { if (event.channel === 'login') { switch (event.args[0]) { case "loading": break; case "loaded": break; case "success": console.log('ログイン成功'); break; case "failure": console.log('ログイン失敗'); break; } } }); }, methods: { preloadJS() { return `file:${path.join(__static, 'fb.js')}`; }, login() { // webviewへのイベントの送信 webview.send('login', this.userId, this.password); } },
// fb.js const { ipcRenderer } = require('electron'); document.addEventListener('DOMContentLoaded', event => { // rendererプロセスからのイベントの受信 ipcRenderer.on('login', (event, userId, password) => { // DOMをゴニョゴニョしてログインする }); }); document.addEventListener('readystatechange', event => { if ( window.location.href === 'https://facebook.com/sign' ) { // rendererプロセスへのイベントの送信 ipcRenderer.sendToHost('login', 'loaded'); } });