Node.js
bluetooth
Scratch
Electron
microbit

micro:bit を Scratch 2 + Bluetooth で使う(ビルド編2:Electron + noble-uwp)

micro:bit を Scratch 2 + Bluetooth で使う(ビルド編2)

以下のような話題についてまとめます。

  1. ネイティブアドオンを使う Electron アプリケーションのビルドと配布可能なパッケージ化の方法
  2. Scratch2(オフライン版)から Bluetooth Low Energy 経由で BBC micro:bit を使うためのヘルパーアプリケーション作成方法

ビルド編1にて、ネイティブアドオンの node-gyp ビルドが絡んだ Node のアプリケーションについて説明しましたが、今回は後半の、Electron 用のビルドとそのパッケージ化の話です。UWP (Universal Windows Platform) 関係のビルドが入るため、通常の node-gyp の準備に加え、Windows SDK のインストールが必要になります。

electron-builder の使い方

electron-builder

Electron のパッケージ化には、electron-builder や electron-packager、electron-forge などいろいろとあるようです。いずれも設定次第なのかもしれませんが、ここではあまり深入りせず、ひとまずデフォルトのまま使ったときに比較的コンパクトな配布パッケージを生成した electron-builder を使ってみます。

インストーラの生成には、Windows では NSIS というツールが使用されます。初回にダウンロードされるため、別途インストールする必要はないようです。

なお、electron-builder では npm ではなくて yarn が強く推奨されているので、ここから先は yarn を使ってみます。(といいつつ、npm でもおそらくOKだと思います。)コマンドの説明はこちらにありますが、npm installyarn installnpm --saveyarn addnpm --save-devyarn add --dev となります。バージョンのロックには yarn.lock というファイルが生成されます。npm よりパッケージのインストールが早いらしいです。確かに早い気がします。

参考ページ

以下のページが参考になります。

フォルダの準備

以下のような階層にしておきます。electron-builder の version 8 以降は必ずしも二階層にしなくてよいようですが、整理のために、ここでは以前通りトップフォルダがビルド用、一つ下にアプリケーション用 app フォルダを用意し、それぞれに package.json を置きます。node_modules や dist は勝手に生成されるので作成不要です。build もなくて構いませんが、独自にアイコンを置く場合などは用意しておきます。以下では、このプロジェクト用のフォルダが project_root という名前だとします。

project_root
 │
 ├─ package.json (パッケージビルド用)
 │
 ├─ app
 │   ├─ package.json (アプリ用)
 │   ├─ main.js (メインコード)
 │   ├─ index.html (メインページ)
 │   └─ node_modules/  (yarn install で作成される)
 │
 ├─ build (なくてもよい)
 │   ├─ icon.ico  (Windows用)
 │   └─ icon.icns (Mac用)
 │
 ├─ node_modules/  (yarn install で作成される)
 │
 └─ dist/ (electron-builder で生成される)

アプリケーション用の package.json の準備

アプリケーション用の package.json を yarn init などで生成するか、適当に作成します。

app/package.json(アプリ用)
{
  "name": "mytest",
  "version": "1.0.0",
  "main": "main.js",
  "license": "MIT"
}

app フォルダに入って yarn add もしくは npm install --save します。

> cd app
> yarn add express

すると、node_modules へモジュールがインストールされ、dependencies のフィールドが追加されます。

アプリケーションサンプル

main.js および index.html は、たとえば electron hello world などで検索すれば様々なサンプルがウェブで見つかります。例として、以前の記事で解説した Node.js + 簡易Webサーバ (express) の Electron化のテストをこちら (Github) に置きます。

インストーラビルド用の package.json と electron-builder

インストーラビルド用の package.json を準備します。

package.json
{
  "build": {
    "appId": "com.electron.mytest"
  }
}

本来はこのページのようにいろいろと設定できますが、まずは最低限にしてみます。
appId はUUID代わりの適当な文字列で、この文字列が一致しているならば、二回目にインストールしたときに同じアプリケーションとして認識され、アップデートされます。別の文字列にすると別のアプリケーションとして認識され、別途インストールされます。

続けてこの package.json があるフォルダ (project_root) で electron および electron-builder をインストールします。(npm であれば --save-dev ですがここでは yarn を使います。)

> cd ..
> yarn add --dev electron
> yarn add --dev electron-builder

これで node_modules にモジュールが追加されるとともに、package.json に devDependencies が追加されます。

package.json
{
  "build": {
    "appId": "mytest"
  },
  "devDependencies": {
    "electron": "^1.8.4",
    "electron-builder": "^20.8.1"
  }
}

Electron の実行テスト

一度 electron を実行してみます。project_root にいる場合は

> .\node_modules\.bin\electron app

一つ下の app フォルダにいるときは

> ..\node_modules\.bin\electron .

で確認できます。

electron-builder の実行

> .\node_modules\.bin\build

を実行すると

  • electron-builder version=20.8.1
  • loaded configuration file=package.json ("build" field)
  • writing effective config file=dist\electron-builder-effective-config.yaml
  • no native production dependencies
  • packaging       platform=win32 arch=x64 electron=1.8.4 appOutDir=dist\win-unpacked
  • default Electron icon is used reason=application icon is not set
  • building        target=nsis file=dist\<nameフィールド> Setup <versionフィールド>.exe archs=x64 oneClick=true
  • building block map blockMapFile=dist\<nameフィールド> Setup <versionフィールド>.exe.blockmap

のように表示され、dist フォルダ内にインストーラができます。初回はビルドの際にNSISなどのダウンロードが伴うため、二回目以降に比べて結構時間がかかります。

  • no native production dependencies は、このパッケージではネイティブアドオンが絡まないことを意味しています。
  • <nameフィールド><versionフィールド> はパッケージビルド用の package.json で設定した文字列(nameについては少し修正(サニタイズ)されたもの)が入ります。

インストーラの実行テストとNSISの設定

インストーラを実行すると、以下のユーザ領域にインストールされ、いきなり実行されます。

C:\Users\<ユーザ名>\AppData\Local\Programs\<nameフィールド>

インストール先などもう少し選びたいところです。パッケージビルド用の package.json を編集します。

package.json
{
  "build": {
    "appId": "mytest",
    "artifactName": "${productName}_installer_${version}.${ext}",
    "win": {
      "target": "nsis"
    },
    "nsis": {
      "oneClick": false,
      "perMachine": false,
      "allowElevation": true,
      "allowToChangeInstallationDirectory": true
    }
  },
  "devDependencies": {
    "electron": "^1.8.4",
    "electron-builder": "^20.8.1"
  }
}
  • artifactname では生成されるインストーラの名前を指定できます。詳しくはこちらを確認してください。
  • nsis でインストーラ生成ツールNSIS の各種設定ができます。詳しくはこちらを確認してください。
    • oneClick : インストールから実行まで一気に行います。(デフォルトは true
    • perMachine : oneClicktrue のときに、ユーザ領域へのインストールするには false、全ユーザ用にインストールするには true(デフォルトは false
    • allowElevation : 管理者権限でのインストールに移行するためのダイアログを開きます。(デフォルトは true
    • allowToChangeInstallationDirectory : インストール先の変更を許します。(デフォルトは false

以上が electron-builder の基本的な使い方でした。次はネイティブアドオンのビルドが絡む場合です。

Electron用のネイティブアドオンをビルド

UWP が絡まないネイティブアドオンのビルド

Node用のネイティブアドオンは、yarn install (npm install) すればリモートでダウンロードされることも多いですが、Electron用には別途ビルドが必要になります。

方法1: 手動で npm rebuild する場合

app フォルダで以下のコマンドを実行します。

> npm rebuild --runtime=electron --target=1.8.4 --arch=x64 --rebuild --disturl=https://atom.io/download/electron --build_from_source=true

これにより node-pre-gyp や node-gyp が走ります。--target には .\node_modules\.bin\electron -v で表示される Electron のバージョンを入れます。

ネイティブアドオンのビルドが終われば、UWP無しの場合と同様に、project_root のフォルダにある package.json のbuild に、"npmRebuild": false を加えておきます。(記載がなければデフォルトは true になります。)その後、.\node_modules\.bin\build すればインストーラが生成されます。

方法2: electron-builder に任せる場合

electron-builder のデフォルトの設定では内部で、自動的にこの rebuild を行います。しかし、場合によっては明示的に方法1が必要な場合もあるようです。方法2でエラーが起きる場合は方法1を試してみるのもよいかもしれません。

二回目以降のインストーラ生成時など、再度ネイティブアドオンをビルドする必要がなければ package.json の npmBuildfalse にしておきます。

補足(yarn + node-pre-gyp まわりのエラー)

以下の問題は、以前は起きなかったので一時的な現象かもしれませんが、はまったのでメモしておきます。

自分の環境 (node v8.10.0, npm v5.6.0, yarn v1.5.1) では、なぜか yarn install noble-uwp では Node用ビルド済みバインディング (noble-uwp) がリモートからはダウンロードできず、ローカルでビルドされるようになりました。(npm install noble-uwp ではリモートからダウンロードされます。)さらに、node-pre-gyp まわりの設定がおかしくなっているのか、node-pre-gyp 0.9.0 に依存するようにインストールされてしまい、したがって、インストーラでインストールすると、node-pre-gyp がないという実行時エラーまで出てしまいます。

いずれも、app/package.jsondependencies"node-pre-gyp": "0.6.39" を加えると解決されました。(なお、npm install を使う場合は dependencies への追加は不要でした。)

UWP が絡むネイティブアドオンのビルドは Windows SDK が必要

UWPなどが絡む一部のネイティブアドオンでは、ビルド編1で説明した node-gyp の準備(Python 2.7 と Visual C++ Build Tools 2015)だけでは不足で、fatal error C1107: could not find assembly 'Windows.winmd' などが出てしまいます。

ビルドするネイティブアドオンの設定に合ったバージョンの Windows 10 SDK が必要になります。必要なバージョンは、モジュールの説明ページの README(たとえば Requirements)などに書かれていたりします。
noble-uwp は Windows 10 の Creators Update に依存するため、必要な バージョンは Windows 10 SDK build 10.0.15063 です。

これは Electron 用ビルドに限りません。ビルド編1 の noble-uwp では、ビルド済みバインディングをリモートからダウンロードしたため SDKが不要でしたが、ローカルでビルドしようとすると同様に SDK をインストールしておく必要があります。

  1. Visual Studio 2017 がインストール済みの場合、Visual Studio Installer を実行して「変更」ボタンを押し、右側の「概要」>「C++によるデスクトップ開発」で必要なバージョンにチェックを入れます。今回は「デスクトップ C++用 Windows 10 SDK (10.0.15063.0) [x86 および x64]」をインストールします。
  2. Visual Studio 2017 が未インストールの場合、試していませんがおそらく Windows SDK のアーカイブからダウンロードすればよさそうです。

これで UWP が絡む場合のビルドもエラーが出なくなります。

usbモジュールでのエラーの対処

Nodeアプリケーション用の場合はリモートからダウンロードされていた usb モジュールですが、ビルド時にロシア語周りで以下のエラーが出ます。

..\libusb\libusb\strerror.c : warning C4819: The file contains a character that cannot be represented in the current co
de page (932). Save the file in Unicode format to prevent data loss [c:\hiroaki\coder\ScratchMicrobit\s2microbit-ble\ap
p\node_modules\usb\build\libusb.vcxproj]
  threads_windows.c
..\libusb\libusb\strerror.c(108): error C2001: newline in constant [c:\hiroaki\coder\ScratchMicrobit\s2microbit-ble\app
\node_modules\usb\build\libusb.vcxproj]
..\libusb\libusb\strerror.c(114): error C2001: newline in constant [c:\hiroaki\coder\ScratchMicrobit\s2microbit-ble\app

このlibusbのissuesにあるように、簡易的な対処としてはロシア語の該当文字列の後ろに半角スペースを入れるようです。簡単なパッチを用意しておきます。

実行時にモジュール依存関係のエラーが起きた時のヒント

Electron のアプリケーションが依存するスクリプトやモジュールは dist\win-unpacked\resources\app.asar にたばねられています。asar コマンドで展開できます。最後の app は展開先のフォルダ名です。

> npm install -g asar
> cd dist\win-unpacked\resources
> asar extract app.asar app

インストール後にも展開することができます。ユーザ領域に入れた場合は c:\Users\<ユーザ名>\AppData\Local\Programs\<nameフィールド>\resources にあります。

もし直接変更を加えた後に再度たばねるなら以下のコマンドです。

> asar pack app app.asar

appフォルダの外のファイルをインストーラへ追加したいとき

ネイティブアドオンの文脈から外れますが、app.asar と関連して、electron-builder でインストーラにファイルを追加する方法をまとめておきます。

electron-builder はデフォルトだと project_root/app フォルダを app.asar としてたばねますが、project_root/build にあるアイコンをアプリ内や index.html でも使いたいなど、project_root 直下のフォルダ(appにはないフォルダ)をインストーラに加えたい場合があります。このときの package.json の記述は electron-builder のマニュアルに詳しく書かれていますが、コピー先をどこにしたいのかで、filesextraResourcesextraFiles を使い分けます。インストーラの app フォルダの中に加えるのであれば files を使います。

project_root/00microbit フォルダとその中にある .hex 拡張子のついたファイルをインストーラの app/00microbit へコピーしてみます。マニュアルによれば、デフォルトの指定は **/* で、これも加えておく必要があるとのことで、package.json に加える記述は以下のようになります。

package.json
    "files": [
      "**/*",
      {
        "from": "../00microbit",
        "to": "00microbit",
        "filter": ["*.hex"]
      }
    ],

これで build コマンドを実行すれば、インストーラ生成時に、インストーラの app の中に 00microbit フォルダが、さらにその中に .hex ファイルがコピーされます。

  • files では fromto は app フォルダが起点になります。
  • OS非依存なら package.json の "build" 以下に加えます。OS依存の場合は "win""mac" などの下に書いても良いそうです。extraResourcesextraFilesなどでは特に必要になるかもしれません。
  • インストーラ生成時にコピーされるだけで、本来の project_root/app は影響を受けません。

asar extract コマンドを使って展開すると、実際に app/00microbit があるのが分かります。

まとめ: s2microbit-ble のインストーラの作成方法

前回のビルド編1 で紹介した s2microbit-ble-console を使うには Node, Python, VC++ のビルド環境が必要でした。さすがにこれだけの環境を子供のPCにそれぞれインストールするのは大変です。

そこで、いずれの環境もインストールせずに済むように、s2microbit-ble-console を Electron アプリケーション化し、インストーラとともに s2microbit-ble で公開することにします。

以下ではこのインストーラの生成方法をまとめます。

要件

インストーラの生成手順

以下の手順でインストーラを作ることができます。 npm rebuildtarget は Electronのバージョンに合わせます。

> git clone https://github.com/memakura/s2microbit-ble.git
> cd s2microbit-ble\app
> yarn install (もしくは npm install)
> npm rebuild --runtime=electron --target=1.8.4 --arch=x64 --rebuild --disturl=https://atom.io/download/electron --build_from_source=true
> (Python 2.7 の環境にしておく。npm config で python にパスが通っていれば設定は不要)
> cd ..
> yarn install (もしくは npm install)
> .\node_modules\.bin\electron app (テストが必要な場合)
> .\node_modules\.bin\build

これで dist 以下にインストーラが生成されます。

インストール方法とアプリケーションの使用方法は s2microbit-ble (Github) で確認できます。

次回は、s2microbit-ble で何ができるか、および bbc-microbit の API を一部説明します。

つづく:まとめ編