しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Electron で Surface Pro X にネイティブ対応したアプリを作る

Surface Pro X というか ARM64 にネイティブ対応したアプリケーションが中々増えないですが、.NET Framework / .NET Core 以外ならいい感じに ARM64 対応が進んでいます。

特に Electron 7 から ARM64 対応したのは結構インパクトが大きいと思っています。

Electron の公式ドキュメントに Windows on ARM 向けのチュートリアルが用意されていますが、微妙に古い情報だったので最新の Electron 8 と Visual Studio 2019 で試してみました。

と言っても自分は Win32 とか Windows on ARM に関する知識はあっても Electron 周りの知識はほぼないので、サンプルプロジェクトを全編通して利用しています。

ARM64 ネイティブで動くと、常駐するタイプのメッセージングアプリで有利になってくるはずなので、是非とも Slack や Teams には対応してほしいところです。てか Teams は出すべき。

とりあえず Electron サンプルを動かす

前述したように Electron の経験がゼロなので、まずは普通の Windows 10 上で Electron のサンプルをビルドして動かしてみました。今回は公式の Quick Start を利用しました。

Node.js がインストールされていれば、以下のコマンドを叩くだけでアプリケーションが起動します。

git clone https://github.com/electron/electron-quick-start
cd electron-quick-start
npm install
npm start

実際に起動した例は以下になります。見慣れたインターフェースを持つアプリケーションが起動しました。

f:id:shiba-yan:20200416015437p:plain

Node.js の Web アプリケーションを動かすのとほとんど変わらない手順で Electron のアプリケーションが起動できました。このアプリケーションを Surface Pro X 上でネイティブ動作するように持っていきます。

実行可能ファイルとしてビルド

Electron を使ったアプリケーションを実行可能ファイルにするには electron-packager というツールが公式に提供されているようですが、最低限の機能しか持っていないようなので、インストーラ付きでビルドできる electron-builder を使った方が便利なようです。

使い方も簡単で、公式ドキュメントの通りに npm を使って electron-builder をインストールします。

npm install -D electron-builder

インストール後に packages.jsonscripts にコマンドを追加しつつ、同時に build セクションを追加しておきます。スクリプトベースでも定義できるようですが、簡単な方を選びました。

{
  "name": "electron-quick-start",
  "version": "1.0.0",
  "description": "A minimal Electron application",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "pack": "electron-builder --dir",
    "dist": "electron-builder"
  },
  "build": {
    "appId": "SampleApp"
  },
  "author": "GitHub",
  "license": "CC0-1.0",
  "devDependencies": {
    "electron": "^8.2.4",
    "electron-builder": "^22.6.0"
  }
}

appId は無くてもビルドは通りますが、ドキュメントには明示的に指定するように強く書かれていたので設定しています。本来ならユニークな値を設定する必要があります。

設定完了後に npm run dist を実行すると実行ファイルが生成されます。

f:id:shiba-yan:20200429193134p:plain

アイコンなどのリソースは決められたパスにファイルを置いておけば自動的に使われます。指定しない場合は Electron のデフォルトアイコンのままになるので、実際のアプリ開発時には用意しておきましょう。

複数アーキテクチャ対応のインストーラーを作成

デフォルトの設定のままでは x64 向けの実行可能ファイルが生成されましたが、アプリケーションの配布時には複数アーキテクチャに対応したインストーラーが必要になってきます。

Electron では Windows 環境において ia32 (x86) / x64 / arm64 がサポートされています。

electron-builder を使って複数アーキテクチャに対応させるには win セクションを追加して、その中でビルドするアーキテクチャを指定します。

以下のように書くと Windows で利用可能な全てのアーキテクチャ向けにビルドします。

{
  "name": "electron-quick-start",
  "version": "1.0.0",
  "description": "A minimal Electron application",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "pack": "electron-builder --dir",
    "dist": "electron-builder"
  },
  "build": {
    "appId": "SampleApp",
    "win": {
      "target": {
      	"target": "nsis",
      	"arch": ["ia32", "x64", "arm64"]
      }
    }
  },
  "author": "GitHub",
  "license": "CC0-1.0",
  "devDependencies": {
    "electron": "^8.2.4",
    "electron-builder": "^22.6.0"
  }
}

x86 ではなく ia32、amd64 ではなく x64 と書く必要があるのが少し罠っぽいです。若干統一感に欠ける印象がありますが、間違った場合にはビルドエラーになるのですぐに気が付くはずです。

これも先ほどと同様に npm run dist を実行するとインストーラー付きで作成されます。

f:id:shiba-yan:20200429204541p:plain

このインストーラーを Surface Pro X にコピーして実行してみると、問題なく arm64 版がインストールされてアプリケーションが動作していることが確認できます。

Surface Pro X 上では 64bit プロセスは ARM64 で動作している場合だけなので、タスクマネージャーから簡単に確認することが出来ます。

f:id:shiba-yan:20200429203052p:plain

Quick Start は特にプラットフォームに大きく依存するものを使っておらず、外部のライブラリも参照していないので簡単に ARM64 向けビルドが行えました。

しかし普通は何かしらライブラリを使うはずなのでその辺りも検証していきます。

Native Module をビルドして利用

Node.js のモジュールにはネイティブコードを使うものがあり、通常なら node-gyp でいい感じにビルドするか、node-pre-gyp でビルド済みバイナリをダウンロードするのであまり気にする必要がないです。

現状 Windows 10 の ARM64 向けバイナリはほぼ提供されていないので、自前でビルドする必要があります。Electron 向けにビルドするのはドキュメントがありますが割とめんどくさい感じです。

しかし electron-builder は自動的に上のドキュメントにある処理を行ってくれるので、何も考えなくてもコマンドを叩くだけで ARM64 向けビルドが行えます。

実際にビルドが必要になるライブラリで試してみます。今回は bcrypt を使ってみました。

npm install bcrypt

ARM64 向けのビルドを行うためにはコンパイラーやライブラリをインストールする必要があるので、予め Visual Studio Installer からインストールしておきます。

f:id:shiba-yan:20200430165434p:plain

これまでのように npm run dist を実行するだけで、bcrypt のビルドが実行されていることがログから確認できます。ARM64 の場合は node-gyp によってビルドが行われています。

f:id:shiba-yan:20200430163456p:plain

Native Module を使っていても、electron-builder を使っていれば自動でビルドが走るので便利です。ただしビルド対象のライブラリが ARM64 向けにコンパイルできないコードの場合はエラーになります。

アプリケーションを AppX としてビルド

インストーラーとしてこれまでビルドしてきましたが、Windows Store での配布を行う場合には AppX や MSIX としてビルドする必要があります。electron-builder は AppX としてのビルドに対応しているので、多少の設定変更でビルド出来ます。

設定は以下のように変更しています。変更点としては targetappx に変更し、appx セクションを追加しているぐらいです。AppX の場合は identityName の設定は必須のようです。

{
  "name": "electron-quick-start",
  "version": "1.0.0",
  "description": "A minimal Electron application",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "pack": "electron-builder --dir",
    "dist": "electron-builder"
  },
  "build": {
    "appId": "SampleApp",
    "win": {
      "target": {
        "target": "appx",
        "arch": ["ia32", "x64", "arm64"]
      }
    },
    "appx": {
      "identityName": "ElectronQuickStart"
    }
  },
  "author": "GitHub",
  "license": "CC0-1.0",
  "devDependencies": {
    "electron": "^8.2.4",
    "electron-builder": "^22.6.0"
  },
  "dependencies": {
    "bcrypt": "^4.0.1"
  }
}

electron-builder のバージョンは 22.6.0 以上を使わないと、ARM64 向けビルドの時にエラーになります。

これまでのようにビルドを行うと、各アーキテクチャ向けに AppX が生成されます。

f:id:shiba-yan:20200430170351p:plain

appxbundle は生成されないですが、Windows Store へのアップロード時には appx で問題ないです。

appx を開いてみるとインストーラーが立ち上がります。署名がないので今はインストールエラーになりますが、Windows Store へのアップロード目的の場合は署名無しで問題ありません。

f:id:shiba-yan:20200430225908p:plain

サイドローディングの場合は署名を行う必要がありますが、これもまた electron-builder が対応しています。

アプリケーションに署名を行う

electron-builder を使うと PFX とパスワードだけ用意しておけば簡単に署名が行えます。証明書はとりあえず自己署名証明書を作成して試すので、PowerShell を使って適当に PFX を作成しておきました。

署名の設定は環境変数を使って行うので、CI でも簡単に実行可能でしょう。以下のような環境変数を設定しておけば、自動的に署名が実行されます。

set CSC_LINK=certificate.pfx
set CSC_KEY_PASSWORD=P@ssw0rd

ビルド後に署名されているか確認するには、AppX のファイルプロパティを開くだけです。

f:id:shiba-yan:20200430231237p:plain

Windows Store 以外からインストールするためには信頼済みの署名が必要なので、認証局から発行されたコードサイニング証明書を使うか、自己署名証明書を「信頼されたルート証明機関」に入れる必要があります。

証明書をインストールすれば、appx を開いたときに警告が表示されなくなります。

f:id:shiba-yan:20200430232435p:plain:w550

これでインストールが完了したので、後はスタートメニューからアプリケーションを選べば起動出来ます。

f:id:shiba-yan:20200430232445p:plain

思ったより Electron のビルド周りのインフラが洗練されているという印象を持ちました。

外部のライブラリ次第ではありますが ARM64 への対応も比較的簡単になっているので、対応アプリが増えていくことを期待しています。まずは Teams は何とかしてほしい。