Mac
MacAppStore
リリース
Electron
パッケージ化

Electron製アプリをMac App Storeでリリースするまでの手順

最近、ElectronでGateというMac用デスクトップアプリケーションを作って、Mac App Storeにリリースしました。Gateは、入力したパスのフォルダを、Finderで開くことができるアプリケーションです。Macのパスだけではなく、Windowsパスも開くことができるので、特にMacユーザとWindowsユーザがいるチームでフォルダパスを共有する際に役立つと思います。
Mac_App_Store.png

Mac App Storeにリリースするにあたり、具体的な手順がわからず苦労したので、今回はリリースまでの一連の流れをまとめてみようと思います。

前提事項

  • Mac用デスクトップアプリケーションの手順です。
  • アイコンや証明書等の事前準備については、既にわかりやすい記事がたくさんあるので詳細手順を省き、リンクを紹介させていただきます。(わかりやすい記事をありがとうございます)
  • 逆にリリース用インストーラパッケージの作成は、詳細な手順が見つからず苦労したので、詳細に記載していきます。
  • パッケージ化はリリースの度に発生する作業なので本来はスクリプト化すべきところですが、何をしているのか理解していただくために、手動での手順を記載します。
  • これらの手順はAppleによってアプリケーションが承認されることを保証するものではありませんので、ご注意下さい。
  • 本記事の情報は2018年10月時点のものですので、作業される際は各公式ページの最新情報も合わせてご参照下さい。

基本用語

まず初めに、本記事の中で出てくる用語を簡単にですが説明しておきます。一般的に使われるIT用語もありますが、ここではあくまで「Electron製アプリケーションをリリース用インストーラパッケージにする」文脈での意味を記載します。詳細を知りたい場合は、Apple Developerウェブサイトの用語解説をご参照ください。

  • Apple ID
    iTunes StoreやApp StoreなどのAppleサービスを利用するときに、ユーザを識別するためのIDのこと。
  • Apple Developer Program
    App StoreやMac App Storeでアプリケーションを配信したい開発者が登録する開発プログラムのこと。iOSやMacのアプリケーションを開発するためのツールを使用できたり、App StoreやMac App Storeでアプリを配布できたりするようになります。Apple Developer Programへの登録が完了すると、以下2つのサイトにサインインできるようになり、サービスを受けることができます。
    *年間99米ドルかかるので、ご注意下さい。(2018年10月時点)
  • 署名証明書
    Appleから発行してもらう証明書で、アプリケーションにコード署名(後述)するときに使用します。発行された証明書は、キーチェーンアクセスに登録しておく必要があります。
  • コード署名 署名証明書を使用してアプリケーションのコードに署名することです。署名することで、「アプリケーションの開発者をAppleが承認していること」、「アプリケーションが第三者に改竄されていないこと」が証明されます。Macには、Gatekeeperというセキュリティ機構があり、Appleが認証した開発者がコード署名したアプリケーション以外は、起動できないようになっています。(ユーザが自分の意志で署名のないアプリケーションを起動許可することもできますが、セキュリティ上オススメできません。)
  • Mac App IDs
    特定のチームが開発したアプリケーションを一意に識別するためのIDのことで、自分で決めることができます。「ドメインを逆に記述したもの(逆DNS形式の文字列)」+「アプリケーション名」がIDとなるので、事前にドメインの取得が必要となります。(例:com.hogedev.YourApp)
  • App Sandbox
    アプリケーションがアクセスできるディレクトリを制限するセキュリティ機構のこと。App Storeに登録する場合、必ず有効にする必要があります。有効にすることで、アプリケーションは必要最低限のディレクトリにしかアクセスできなくなりますが、エンタイトルメントファイル(後述)を設定することで、アクセス権限を追加することができます。
  • エンタイトルメントファイル
    エンタイトルメントファイルとは、アプリケーションに対して、通常は与えられていないディレクトリへのアクセス権限を付与するためのファイルです。例えば、通常はアクセスできない「Musicフォルダ」への読み取り/書き込み権限を、アプリに付与することができます。エンタイトルメントファイルは「.plist」という拡張子で作成します。
  • .plistファイル
    プロパティリストファイルのことで、バンドル(後述)情報を格納するために用いられます。
  • Info.plistファイル
    Info.plistファイルは、プロパティリストファイルの一つです。アプリケーションの設定に関する情報を記述したファイルで、必ず必要です。App StoreやMac OSのファイルを参照して、アプリケーションが必要とするハードウェア機能やリソースの場所を認識します。
  • バンドル
    関連のあるリソースを1つの場所に集めたディレクトリのことです。バンドルには、アプリケーションの実行可能ファイルと支援用リソースファイル(アイコン、画像ファイルなど)が含まれています。
  • バンドルID
    アプリケーションを識別するためのIDで、ドメインを逆に記述したもの(例:com.hogedev.YourApp)
  • パッケージ
    npmモジュール「electron-packager」を使用してアプリケーションを「.app」形式のファイルにひとまとめにしたもの。このパッケージファイルに対してコード署名を行い、リリース用インストーラパッケージを生成します。
  • リリース用インストーラパッケージ
    アプリケーションをインストールするために使用されるファイル形式のことで、拡張子は「.pkg」です。ダブルクリックするとインストーラが起動し、Macにアプリケーションをインストールできます。一つ以上のファイルをまとめたものであることからアーカイブとも呼ばれる。最終的に作ったアプリケーションはこのファイル形式へ変換し、App Store Connectへアップロードします。
  • ビルド
    App Store Connectにアップロードするファイルのこと。つまり、本記事では拡張子が「.pkg」のリリース用インストーラパッケージのこと。
  • プレバイナリビルド
    Electron公式ページでMac App Store登録用に予めパッケージ化して用意されている「.app」形式のファイルのこと。こちらのファイルへ自身のアプリケーションの実行ファイル部分を移行してリリース用インストーラパッケージを作ります。 なぜそのような手順を踏むかというと、App Sandboxの要件を満たすためです。作成したアプリケーションをMac App Storeに登録するには、App Sandboxの要件を満たす必要があります。しかしながら、Electronで作成したアプリには、「crashReporter」と「autoUpdater」というモジュールが標準搭載されており、これらが有効になっているとSandboxの要件を満たせず、審査を通過できません。そこで「crashReporter」と「autoUpdater」のモジュールを無効にして事前にパッケージ化したファイルが、プレバイナリビルドです。

それでは、ここからアプリケーションのリリースの準備に入っていきます。主な流れは下記の通りです。

1. App Sandboxとガイドラインの確認
2. アイコンの作成
3. アカウントの作成や証明書作成等の事前準備
**4. リリース用インストーラパッケージの作成

App Sandboxとガイドラインの確認

アプリケーションは基本自分が作りたいものを作ってOKです。ただし、「App Sandboxの要件」と「Appleのガイドライン」は必ず満たす必要があります。作ろうとしている 又は 既に作ったアプリケーションが、以下2点を満たしているか確認します。
既に作成していて、以下2点を満たしていない場合は、仕様変更をしてから以降の手順へ進んでください。

  • App Sandboxについて
    私はApp Sandboxを確認せずにアプリケーションを作ってしまったので、App Storeに公開するにあたり、仕様変更を余儀無くされました。何ができて、何ができないかを、できれば事前にAppleの公式ページで確認しておくのがオススメです。英語のページですが、Google翻訳でだいたいわかると思います。
  • アプリのレビューガイドラインについて
    どういった観点で審査されるかがわかります。でにればこちらも事前にざっと目を通しておくと良いと思います。

アイコンの作成

Mac App Storeにリリースするにはアプリケーションのアイコンが必須となります。まだ、作成していない方は作成しましょう。私のようにデザインの知識なくてもなんとかなります。
私はIllustratorなどのデザインツールを使えないので、Keynoteで作成しました。デザイナーでない方には、Keynoteがオススメです。
手順は以下を参考にしてください。

アカウントの作成や証明書作成等の事前準備

こちらは基本的に一度だけ行えば良いものなので、手間ですが頑張って進めていきましょう。

リリース用インストーラパッケージの作成

ここから本記事のメインである、リリース用インストーラパッケージの作成を行っていきます
。主な流れは下記の通りです。

1. エンタイトルメントファイルの作成
2. アプリ署名シェルスクリプトの作成
3. プレバイナリビルドの編集
4. コード署名

なお、パッケージ作業は下記フォルダ構成で行なっていきますので、自身の環境に合わせて読み替えて下さい。
また、作成したアイコンファイルもプロジェクトフォルダに含めておいて下さい。

  • アプリのプロジェクトディレクトリ:/Users/foo/YourApp
  • 作業用ディレクトリ:/Users/foo/releases
ディレクトリ構造
/Users
  └── foo
       ├── releases                          # 作業用ディレクトリ
       └── YourApp                           # 作成したアプリのプロジェクトフォルダ
            ├── resources                    # アプリのリソースを格納するフォルダ
            │      └── icon
            │            └── YourApp.icns    # アプリアイコン
            │
            └── src                          # パッケージ対象のソース

1. エンタイトルメントファイルの作成

まずは、アプリケーションのディレクトリアクセス権限をコントロールするエンタイトルメントファイルを作成します。作成すると言っても、フォーマットは、Electronの「Mac App Storeへの公開ガイド」に用意されているので、こちらからコピーして作業用ディレクトリに作成すればOKです。
それでは、以下3つのエンタイトルメントファイルを用意していきます。

  • parent.plistの作成
    親プロセスの権限を管理するためのファイルです。作業用ディレクトリ(/Users/foo/releases直下)に作成します。
    権限の追加が必要な場合は、App Sandboxの有効化から必要なエンタイトルメントキーを確認し、追加して下さい。
アプリケーションにMusicフォルダへの読み取り/書き込みアクセス権を付与したい場合の例:
# 以下2行をparent.plistに追記
<key>com.apple.security.network.client</key>
<true/>
  • child.plistの作成
    親プロセスから作られた子プロセスの権限を管理するためのファイルです。parent.plistと同様に作業用ディレクトリ(/Users/foo/releases直下)に作成します。
    親プロセスの権限を継承するので、基本的に編集は必要ありませんが、子プロセスに限定したい権限があれば、こちらのファイルにエンタイトルメントキーを追加して下さい。
  • loginhelper.plistの作成 
    アプリケーションをログイン項目に登録した時に、MacOSログイン時に登録したアプリケーションを起動するヘルパーの権限を管理するためのファイルです。parent.plistと同様に作業用ディレクトリ(/Users/foo/releases直下)に作成します。
    アプリケーションを起動する役割だけなので、基本的には編集は必要ありません。

2. コード署名シェルスクリプトの作成

作成したアプリケーションにコード署名を行うためのスクリプトです。こちらのスクリプトもElectronの公式ページに用意されているので、エンタイトルメントファイルと同様にMac App Storeへの公開ガイドからコピーして作成すればOKです。エンタイトルメントファイルと同様に作業用ディレクトリ(/Users/foo/releases直下)に、任意のファイル名(ここではCodeSign.sh)で作成します。
内容をコピーしてきたら、自身の環境に合わせて、下記変数の値を変更していきます。
*Team NameとTeam IDはApple Developerウェブサイトにサインインし、Membershipページで確認できます。

#作成したアプリ名
APP="YourApp"
#本記事では、/Users/foo/releases/package/とします
APP_PATH="/path/to/YourApp.app"
#本記事では、/Users/foo/releases/package/$YourApp.pkgとします
RESULT_PATH="~/Desktop/$APP.pkg"
#Company NameにはTeam Name、APPIDENTITYにはTeam IDを記入
APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)"
INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)"
#本記事では、/Users/foo/releases/child.plist/とします
CHILD_PLIST="/path/to/child.plist"
#本記事では、/Users/foo/releases/parent.plist/とします
PARENT_PLIST="/path/to/parent.plist"
#本記事では、/Users/foo/releases/loginhelper.plist/とします
LOGINHELPER_PLIST="/path/to/loginhelper.plist"

3. プレバイナリビルドの編集

基本用語でも少し説明しましたが、パッケージ化では二段階の手順を踏みます。
①自身で作成したアプリケーションをパッケージ化し、YourApp.appを生成する。
②YourApp.appの中から、処理の中身にあたる「app.asar」とアイコンファイルの「YourApp.icon」を抜き出し、その抜き出した2つのファイルをプレビルドバイナリへコピーする。
copy-image.png
この2つを意識してないと、途中で何をしてるかわからなくなるので、このことはしっかり頭に入れておいてください。

  • プレバイナリビルドの取得
    まずは、下記からプレバイナリビルドをダウンロードし、「/Users/foo/releases/」に保存します。バージョンはご自身が作成したアプリのElectronバージョンと合わせればいいと思います。本記事では、「electron-v2.0.8-mas-x64.zip」を使用します。
  • 作業用フォルダの作成
    続いて、「/Users/foo/releases/」にパッケージ作業用の「package」フォルダを作成します。
$ mkdir /Users/foo/releases/package
  • フォルダ構成の確認
    ここまでで作成したフォルダ/ファイルと、アプリのプロジェクトフォルダ構成を示します。フォルダ構成は自由なので、適宜ご自身の環境に合うようにコマンドのパスを差し替えてください。
/Users
  └── foo
       ├── releases
       │    ├── CodeSign.sh                   # コード署名用スクリプト
       │    ├── child.plist                  # エンタイトルメントファイル
       │    ├── electron-v2.0.8-mas-x64.zip  # ダウンロードしたプレバイナリビルド
       │    ├── loginhelper.plist            # エンタイトルメントファイル
       │    ├── package                      # パッケージ作業用フォルダ
       │    └── parent.plist                 # エンタイトルメントファイル
       └── YourApp                           # 作成したアプリのプロジェクトフォルダ
            ├── resources                    # アプリのリソースを格納するフォルダ
            │      └── icon
            │            └── YourApp.icns    # アプリアイコン
            │
            └── src                          # パッケージ対象のソース
  • 自身のアプリのパッケージ化
    それでは、いよいよパッケージ作業を行なっていきます。コマンドは絶対パス指定しているので、どのディレクトリで実行してもOKです。electron-packagerを使って、実行形式のファイル(YourApp.app)を作成します。 コマンド実行後に、/Users/foo/releases/package/YourApp-darwin-x64/YourApp.appが作成されたことを確認してください。
$ npx electron-packager /Users/foo/YourApp/src YourApp --platform=darwin --arch=x64 --overwrite --icon=/Users/foo/YourApp/resources/icon/YourApp.icns --out=/Users/foo/releases/package --prune=true --asar
  • プレバイナリビルドの準備
    次にプレビルドバイナリを解凍します。
$ unzip -d /Users/foo/releases/package/ /Users/foo/releases/electron-v2.0.8-mas-x64.zip

コマンド実行後、/Users/foo/releases/Electron.appが作成されたことを確認します。Electron.appを自身のアプリケーション名に変更します。
・Electron.app → YourApp.app

  • プレバイナリビルドの不要ファイル削除
    次に/Users/foo/releases/package/YourApp.app/Contents/Resources内にある不要なフォルダとファイルを削除します。
    【削除対象】
    ・default_app.asar
    ・electron.icns
    ・◯◯.lproj
    補足ですが、「◯◯.lproj」は、Mac App Storeの表示をローカライズするためのディレクトリですので、対応していない言語の「◯◯.lproj」フォルダは削除します。例えば、en.lprojとja.lprojを残した場合、Mac App Storeの言語表記には「日本語」と「英語」が下記のように表示されます。
    App-Store-image.png
  • 自身のパッケージしたファイルをプレバイナリビルドへコピー
    自身のアプリのapp.asarとアイコンをコピーしていきます。
    【コピー対象ファイル】
     ・app.asar
     ・electron.icns
    【コピー元】/Users/foo/releases/package/YourApp-darwin-x64/YourApp.app/Contents/Resources
      ↓
    【コピー先】/Users/foo/releases/package/YourApp.app/Contents/Resources
    コピー後にelectron.icnsを自身のアプリケーション名に変更します。
    ・electron.icns → YourApp.icns
  • Info.plistの編集と実行ファイル名の変更
    ここまできたら、あと少しです。次はInfo.plistの中身の修正と、実行ファイルの名称変更を行なっていきます。
    /Users/foo/releases/package/YourApp.app/Contents/Info.plistを開いて、下記箇所を修正します。 ElectronTeamIDの2行は自分で追記してください。
<key>CFBundleDisplayName</key>
<string>Electron</string>                <!-- Electronを自身のアプリ名に置換 -->
<key>CFBundleExecutable</key>
<string>Electron</string>                <!-- Electronを自身のアプリ名に置換 -->
<key>CFBundleIconFile</key>
<string>electron.icns</string>           <!-- electronを自身のアプリアイコン名に置換 -->
<key>CFBundleIdentifier</key>
<string>com.github.electron</string>     <!-- 自身のMac App IDsに置換 -->
<key>CFBundleName</key>
<string>Electron</string>                <!-- 自身のアプリ名に置換 -->
<key>CFBundleShortVersionString</key>
<string>2.0.8</string>                   <!-- 好きなアプリバージョン番号に置換 -->
<key>CFBundleVersion</key>
<string>2.0.8</string>                   <!-- 好きなアプリバージョン番号に置換 -->
<key>ElectronTeamID</key>
<string>TEAM_ID</string>                 <!-- 自身のTEAM_IDに置換 -->

*アプリバージョンのルールはご自身で決定して大丈夫です。
*Team IDはApple Developer Centerにサインインし、Membershipで確認できます。

/Users/foo/releases/package/YourApp.app/Contents/MacOSの下記ファイル名を自身のアプリケーション名に変更します。
・Electron → YourApp

/Users/foo/releases/package/YourApp.app/Contents/Library/LoginItemsの下記ファイル名を自身のアプリケーション名に変更します。
・Electron Login Helper.app → YourApp Login Helper.app

/Users/foo/releases/package/YourApp.app/Contents/Library/LoginItems/YourApp Login Helper.app/Contents/Info.plistを書き換えます。

<key>CFBundleExecutable</key>
<string>Electron Login Helper</string>            <!-- Electronを自身のアプリ名に置換 -->
<key>CFBundleIdentifier</key>
<string>com.github.electron.loginhelper</string>  <!-- com.github.electronの部分をご自身のMac App IDsに置換 -->
<key>CFBundleName</key>
<string>Electron Login Helper</string>            <!-- Electronを自身のアプリ名に置換 -->

/Users/foo/releases/package/YourApp.app/Contents/Library/LoginItems/YourApp Login Helper.app/Contents/MacOSの下記ファイル名を自身のアプリ名に変更します。
・Electron Login Helper → YourApp Login Helper

/Users/foo/releases/package/YourApp.app/Contents/Frameworks
・Electron Helper EH.app → YourApp Helper EH.app
・Electron Helper NP.app → YourApp Helper NP.app
・Electron Helper.app → YourApp Helper.app

/Users/foo/releases/package/YourApp.app/Contents/Frameworks/YourApp Helper EH.app/Contents/Info.plistを書き換えます。

<key>CFBundleDisplayName</key>
<string>Electron Helper EH</string>             <!-- Electronを自身のアプリ名に置換 -->
<key>CFBundleExecutable</key>
<string>Electron Helper EH</string>             <!-- Electronを自身のアプリ名に置換 -->
<key>CFBundleIdentifier</key>
<string>com.github.electron.helper.EH</string>  <!-- com.github.electronの部分をご自身のMac App IDsに置換 -->
<key>CFBundleName</key>
<string>Electron Helper EH</string>             <!-- Electronを自身のアプリ名に置換 -->

/Users/foo/releases/package/YourApp.app/Contents/Frameworks/YourApp Helper EH.app/Contents/MacOSの下記ファイル名を自身のアプリ名に変更します。
・Electron Helper EH → YourApp Helper EH

/Users/foo/releases/package/YourApp.app/Contents/Frameworks/YourApp Helper NP.app/Contents/Info.plistを書き換える。

<key>CFBundleDisplayName</key>
<string>Electron Helper NP</string>             <!-- Electronを自身のアプリ名に置換 -->
<key>CFBundleExecutable</key>
<string>Electron Helper NP</string>             <!-- Electronを自身のアプリ名に置換 -->
<key>CFBundleIdentifier</key>
<string>com.github.electron.helper.NP</string>  <!-- com.github.electronの部分をご自身のMac App IDsに置換 -->
<key>CFBundleName</key>
<string>Electron Helper NP</string>             <!-- Electronを自身のアプリ名に置換 -->

/Users/foo/releases/package/YourApp.app/Contents/Frameworks/YourApp Helper NP.app/Contents/MacOSの下記ファイル名を自身のアプリ名に変更します。
・Electron Helper NP → YourApp Helper NP

/Users/foo/releases/package/YourApp.app/Contents/Frameworks/YourApp Helper.app/Contents/Info.plistを書き換えます。

<key>CFBundleIdentifier</key>
<string>com.github.electron.helper</string>    <!-- com.github.electronの部分をご自身のMac App IDsに置換 -->
<key>CFBundleName</key>
<string>Electron Helper</string>               <!-- Electronを自身のアプリ名に置換 -->

/Users/foo/releases/package/YourApp.app/Contents/Frameworks/YourApp Helper.app/Contents/MacOSの下記ファイル名を自身のアプリ名に変更します。
・Electron Helper → YourApp Helper

4. コード署名

コード署名用のシェルスクリプトを実行し、アプリケーションに署名を行います。エラーが出ていないければ、/Users/foo/releases/package/YourApp.pkgが作成されているはずです。
YourApp.pkgが作成されていたら、/Users/foo/releases/package/YourApp.appを削除し、YourApp.pkgを自身のPCにインストールしてみます。自身のPCで問題なく動けば、パッケージ化作業は終了です。
起動しなかったり、仕様通り動かったりする場合は、Sandboxの権限設定か、パッケージ化作業に不備がある可能性が高いと思われます。
*YourApp.appを削除しないと、YourApp.pkgをインストールできないのでご注意ください。
*挙動に問題なくとも、Developerモードでconsoleログでエラーが出ていないかも確認しておきましょう。

$ /bin/bash /Users/foo/releases/CodeSign.sh
/Users/foo/releases/package/YourApp.app/Contents/Frameworks/Electron Framework.framework: replacing existing signature
/Users/foo/releases/package/YourApp.app/Contents/Frameworks/YourApp Helper.app/: replacing existing signature
productbuild: Adding component at /Users/foo/releases/package/YourApp.app
productbuild: Signing product with identity "3rd Party Mac Developer Installer: Team Name (Team ID)" from keychain /Users/foo/Library/Keychains/login.keychain-db
productbuild: Adding certificate "Apple Worldwide Developer Relations Certification Authority"
productbuild: Adding certificate "Apple Root CA"
productbuild: Wrote product to /Users/foo/releases/package/YourApp.pkg
productbuild: Supported OS versions: [10.9.0, )

ビルドのアップロード

ここまでの手順で、リリース用インストーラパッケージは完成しました。最後に、インストーラパッケージを審査に出します。App Store ConnectにApplication Loaderでビルドをアップロードする必要があります。Application Loaderを使用するには、Xcodeが必要になりますので、まずはXcodeをインストールしましょう。

  • Xcodeのインストール
    https://itunes.apple.com/jp/app/xcode/id497799835?mt=12
  • Application Loaderでアップロード
    Xcodeをインストールしたら、Xcodeを起動します。
    起動したらメニューから[Xcode] > [Open Developer Tool] > [Application Loader]をクリックし、Application Loaderを起動します。
    Application Loaderでビルド(/Users/foo/releases/package/YourApp.pkg)を選択し、アップロードをすれば完了です。

最後に

ここまで長かったですが、お疲れ様でした。あとは、App Store Connectでアプリケーションの紹介文や画面キャプチャを登録して審査に出せば終わりです。