Cordovaで作成したアプリをElectronを用いてWindowsアプリ化してみる（手順と移植の問題点）

# はじめに

Javascript/CSS/HTMLでアプリを作成できるツールがいくつか存在します。Android用としては[Cordova](https://cordova.apache.org/)などが有名だと思います。そのCordovaで作成したソースを少ない変更で[Electron](https://electron.atom.io/)を使ってWindowsアプリ化できないかと思い取り組んでみました。

ついでにもとになったアプリ（？）は、後述にある理由でリリースしていないため、その証明にはなりませんが。機会があればCordova化の記事も書きたいと思っております。

Javascript/CSS/HTMLでElectronでアプリ化できますが実際に作ってみないと勉強にならないと思い作成してみました。

ただし、作成元にしたアプリ（ソース）はCordovaのAPIをできるだけ使用しないように作成したため、移植が容易だった背景があります。


# 環境

Windows 10で作成しています。他のOSは手元に常時動いていないのでとりあえずはWindowsアプリしか作成しておりません。

# 下準備

## node.jsの準備

Electronでアプリを作成するにはnode.jsが必要です。

私は以下の本を購入して参考にしました。

[Electronではじめるアプリ開発](http://gihyo.jp/book/2017/978-4-7741-8819-5)

ただ、node.jsのバージョンはv7.3.0をすでにインストールしていたので、そのまま使用しました。

node.jsは以下から持ってきてインストールしてください。

[https://nodejs.org/ja/](https://nodejs.org/ja/)

## gitの準備

ソースがgithubにアップロードしているため、gitコマンドのインストールも必要です。

以下からダウンロードしてください。

[https://git-for-windows.github.io/](https://git-for-windows.github.io/)


[Github Desktop](https://desktop.github.com/)もいいかもしれません。この辺りはお好みのものをご使用ください。私は自分のソース管理はGithub Desktopを使っています。




# ソース取得

作成元のgithubにアップされているアプリ([GaiHex](https://github.com/rakichiki/gaihex))をcloneします。
以下ではWindows PowerShellを使った手順です。

Windows PowerShellを開き以下を実行します。（ディレクトリの作成場所は任意で）

```
> mkdir electron_apl
> git clone https://github.com/rakichiki/gaihex
Cloning into 'gaihex'...
remote: Counting objects: 672, done.
remote: Compressing objects: 100% (562/562), done.
remote: Total 672 (delta 109), reused 669 (delta 109), pack-reused 0
Receiving objects: 100% (672/672), 36.22 MiB | 5.77 MiB/s, done.
Resolving deltas: 100% (109/109), done.
```

```
> ls

    ディレクトリ: C:\***\***\make_apl


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2017/04/22     13:32                gaihex
```

gaihexのディレクトリができていればOKです。次の作業を行うためにcdしておきましょう。

```
> cd gaihex
```

# 動かしてみよう

オリジナルのpackage.jsonをmvしておきます。

```
> mv .\package.json .\package.json.org
```

次に

```
> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (gaihex)   <=リターン
version: (1.0.0)   <=リターン
description: gaihex   <=リターン
entry point: (main.js)   <=リターン
test command:   <=リターン
git repository: (https://github.com/rakichiki/gaihex)   <=リターン
keywords:   <=リターン
author:   <=リターン
license: (ISC)   <=リターン
About to write to C:\***\***\make_apl\gaihex\package.json:

{
  "name": "gaihex",
  "version": "1.0.0",
  "description": "gaihex",
  "main": "main.js",
  "directories": {
    "man": "man"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/rakichiki/gaihex.git"
  },
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/rakichiki/gaihex/issues"
  },
  "homepage": "https://github.com/rakichiki/gaihex#readme"
}
```

たくさん聞いてきますがリターン押しましょう。

```
> mv .\package.json .\package.json_old
> cp .\package.json.org .\package.json
```

Electronのマニュアルでは、ここでmain.jsを作成することになるので、すでにcommitしているので不要です。

次にElectronを入れます。

```
> npm install electron@1.6.1 --save-dev


electron@1.6.1 postinstall C:\****\****\make_apl\gaihex\node_modules\electron
node install.js

gaihex@1.0.0 C:\****\****s\make_apl\gaihex
`-- electron@1.6.1
  +-- electron-download@3.3.0
～
省略
～

    | | +-- process-nextick-args@1.0.7
    | | +-- string_decoder@0.10.31
    | | `-- util-deprecate@1.0.2
    | `-- typedarray@0.0.6
    +-- debug@0.7.4
    +-- mkdirp@0.5.0
    | `-- minimist@0.0.8
    `-- yauzl@2.4.1
      `-- fd-slicer@1.0.1
        `-- pend@1.2.0

npm WARN gaihex@1.0.0 No repository field.
```

インストールできました。

ここで動かしてみましょう。

```
> ./node_modules/.bin/electron .
```


そうすると以下のように起動画面が出てくればOKです（起動時に登場するユニットはランダムなので同じ画面でない可能性はあります）。

![start.png](https://qiita-image-store.s3.amazonaws.com/0/176294/0507461d-b091-7fc8-a3bd-2579d803ccfd.png)

メニューなどを選択するとゲームができます。（以下がゲーム動作イメージ）

![game1.png](https://qiita-image-store.s3.amazonaws.com/0/176294/64d02839-c966-4d2b-55b8-011d02e4fe92.png)

以下が動作イメージ動画。

[![GaiHexの動作イメージ動画](http://img.youtube.com/vi/QGKKco4qf-Q/0.jpg)](https://youtu.be/QGKKco4qf-Q)


注意としてCordovaで作成したAndroidアプリはスマフォ・タブレットで縦持ち用~~盾持ち用~~として作成した関係上非常に縦長です。もとは複数解像度に対応して作成したのですが、Electron用にするにあたり変更しておりません。

手元の開発マシン(ThinkPad X260のFHD)で動かすことしか対応していないため、FHD未満の場合は画面が切れてしまうかもしれません。

マルチ解像度対応は要望があれば行うかもしれません（元がマルチ解像度のAndroid用なので対応する解像度を決めれば少ない稼働で対応できそうな気がしております）。

あまり関係ないですが、参考になるかどうかわからないマニュアルが一応あります。トップページから歯車アイコン→ブックアイコンをクリックするとてきとうに書いたマニュアルが見れます。

# パッケージ化

これで一応は遊べますが、いちいちWindows PowerShellを起動してコマンドを打つのはおっくうです。そこでバイナリ化してみましょう。


```
> npm i electron-packager -g
C:\U***\***\AppData\Roaming\npm\electron-packager -> C:\***\***\AppData\Roaming\npm\node_modules\electron-package
r\cli.js
C:\***\***\AppData\Roaming\npm
`-- electron-packager@8.6.0
  +-- asar@0.13.0
  | `-- mksnapshot@0.3.1
  |   `-- request@2.81.0
  |     `-- har-validator@4.2.1
  |       `-- ajv@4.11.7
  +-- debug@2.6.4
  | `-- ms@0.7.3
  +-- get-package-info@1.0.0
  | `-- read-pkg-up@2.0.0
  |   `-- read-pkg@2.0.0
  |     `-- normalize-package-data@2.3.8
  `-- resolve@1.3.3


> electron-packager ./ gaihex --platform=win32 --arch=x64 --icon=./img/icon/icon.ico --overwrite

```

このようにすると同じディレクトリの下にディレクトリが作成されます。

```
gaihex-win32-x64
```

その中に青い六角形の中に剣のアイコンであるバイナリファイル(gaihex.exe)が存在します。


![ディレクトリ.png](https://qiita-image-store.s3.amazonaws.com/0/176294/a3bf36d0-bb17-73a4-05c9-c15f819c5ec7.png)


アイコンは専用のものを使用していますが、なぜかファイルを一覧するとElectronのデフォルトのアイコンが表示されます。改善方法はわかりません。

これを起動するとゲームが始まります。

ついでにアイコンは96x96から256x256に大きくしたので、最大サイズだと粗が目立ちますがご容赦ください。


# Cordova→Electron化にあたりソースの修正箇所

Cordovaアプリを少し修正してElectron化に対応しました。修正箇所は３か所です。

1.Android用にマルチ解像度対応箇所を１解像度に修正
2.Cordovaのライブラリを読み込まない
3.広告を停止させた

実際は１だけ対応した程度です。この程度で済んだ理由は、もとからWindowsのChromeで動作検証して作成したアプリのためごく一部しかCordovaのAPIを使用しなかったためでしょう。

そのおかげでElectron化への移植コストは非常に少なく済みました。

Electronでアプリをリリースする予定で作成していたのでこのようにしたわけではありませんが、思わない効果を発揮したと言えます。

# 失敗したところ

Electronで作成してみいくつか失敗しところが見えております。

1.メニューでページ別を採用したら、ページ遷移のたびに白化した
2.シングルウインド形式
3.縦長サイズ
4.フリック防止
5.キーボードが使えない

メニューの箇所をすべて別ページにしました（特に意識してそうしたのではない）。Cordovaではページ遷移しても白化しないのですが、なぜかElectronではページ遷移のたびに白化します。

理由はわかりませんが、最近はやりのシングルページ化すればこのような問題が起きなかったのではないかと思い反省しています。Cordovaでは問題なかったのに...

また、Androidアプリのためマルチウインドやメニューを表示させる気がなかっため、Electron化で同様にメニューが作りませんでした。このため、メニューがないのですがマニュアルとかは別ウインドで表示させることができてもよかったかなと思ったりしています。この辺りはElectron/Cordovaの両対応を考慮に入れて作成しないとできないところでしょうか。

Androidでゲームでは横置きのほうが画面作りはやりやすいような気がしていますが、それでもスマフォでゲームする場合は縦持ちのほうがいいのではと思いアプリを縦長にしました。（電車の中でゲームしてほしいため）

ですが、PCの画面は基本横長です。このため、PCでゲームを起動するとすごく中途半端です。Androidのソマフォとタブレット用として、マルチ解像度まで想定して画面を作りましたが、画面の縦・横両方に対応は最初から想定して作らないとだめかもしれません。

Androidアプリにしてはフリックできないようにしています。理由は、ベースがブラウザのためフリックすると画面全体が動いてしまうためです（ページを進められるようになってしまう）。このせいで操作感がいまいちイケていない気がしないでもないですが、私には解決策が思い浮かびませんでした。

Android向けアプリだったので、当然ですがキーボードを想定したUIは用意されていません。PC向けアプリではゲームでもキーボード対応があってもいいのかもしれません。キャンセルなどのボタンをマウス操作以外で操作するのも盛り込んでもいいかもしれません。この辺りのOSの違いをどこまで対応するかはコスト次第でしょうか。

# あまり関係ないけどゲームのライセンスに関して

Android用に作成しましたがリリースはしておりません。理由は３つあります。

1.非常に低い頻度でしか発生しないが、ゲームが止まってしまう致命的なバグがどうしても直せない
2.ゲーム内容に少し問題があり、直すには相当時間がかかりそうで、ほかのことがしたいので、ほっておいてしまった
3.もう少し絵を立体的にすべきだったと反省しているけどもう直すのに時間がかかる

このためリリースをしていなかったのですが、それではここまで作成したのでgithubとElectron対応化の話（と移植の感想）を込みで公開してみました。

私が作成したソース部分はapacheライセンスですが、画像の著作権はK.Haruma氏が保持しております。このため、本アプリを個人利用は問題ありませんが、これを使ったフリー・商用リリースはご容赦ください。

また、ゲームルール分はApacheライセンスに採用したいと思っておりますが、ゲームルールにApacheライセンスが適応できるのか私はわかっておりません。

# 最後に

Javascrit/CSS/HTMLでアクションは少なめのゲームは作れます。やりようによっては、１つのソースで、ブラウザでも、Electronを用いたWindows/Mac/Linuxのアプリにも、Cordovaを使ってAndroid/iPhoneのアプリにもできます。

Javascrit/CSS/HTMLは、"Write once, run anywhere"を実現できるプラットフォームだと私は思っています。ただ、画面サイズの対応はそこそこ大変なきがしないでもありませんが。


# 一応いらない補足

別にけ〇のフレンズのアニメに触発されてこのようなユニットにしたわけではありません。鳥系とか出てきませんし。ゲーム作っているときはけも〇フレンズはサービス展開中ではありましたが、広告は見たことはあってもやったことは残念ながらありませんでした。サーバルちゃんに似ている（？）のがいるかもしれませんが、サーバルキャットではないです。

# ついでにリンク

2017/5/1追加
同じソースでJavascriptベンチを作ってみたものです。Canvasベンチを作成する上での失敗例でもあります。
[Javascriptベンチを作ってみた(Canvasもの)](http://qiita.com/rakichiki/items/b8e85ac7af746539e9fe)