コンテンツにスキップ

Electron アプリを Microsoft Store に公開する方法:MSIX パッケージングからストア提出まで

ページを編集
HagiCode for Windows Microsoft Store artwork
HagiCode for Windows is now on Microsoft Store
HagiCode for Windows is officially live on Microsoft Store. Windows users can install it directly from the storefront and stay on the store-managed update path. Open the listing and take a look.
Open Microsoft Store

Electron アプリを Microsoft Store に公開する方法:MSIX パッケージングからストア提出まで

Electron は所詮、ただの一般的な Win32 デスクトップアプリに過ぎませんが、Microsoft Store は MSIX しか認めません。この記事では、私たちが HagiCode Desktop で実際に動かしたビルド設定を借りて、「開発者アカウント登録 → MSIX パッケージ作成 → ストア提出」というチェーンを最初から最後まで分解して紹介し、ついでに私たちが踏んだ落とし穴についてもお話しします。毕竟坑踩过了,也就成了故事。

背景

手元にこのような Electron アプリがあり、Windows 上でエンドユーザーに配布したいと考えています。これまでずっと使っていた NSIS インストーラー、ポータブル版に加えて、Microsoft Store に掲載されることも期待しています。理由は実に現実的です:

  1. 信頼できる配信チャネル:ストアのアプリは署名され、審査されているため、ユーザーがインストールする際に SmartScreen にブロックされることもなく、「未知の発行者」という冷たいメッセージに直面する必要もありません。
  2. 自動更新と商業化:更新はストアが代行してくれます。サブスクリプション、永久ライセンスも直接統合できます。
  3. Windows 10/11 組み込みのエントリポイントの網羅:winget、ストア検索、スタートメニューのおすすめ……これらのエントリポイントは、新規ユーザー獲得に実際に役立ちます。

ただ、Electron は結局 UWP ではありません。Microsoft Store に公開するには、実のところ核となるのは一つだけ——Electron の成果物を Microsoft Store が認識できる MSIX パッケージ に再パッケージングし、登録と提出の手続きをきちんと完了させることです。簡単に聞こえますが、実際に手をつけると、落とし穴は少なくありません。これらの落とし穴を埋めるために、私たちはチェーン全体を徹底的に把握するのに多くの時間を費やしました。以下では、各ステップを分解して詳しく説明します。

HagiCode について

この記事で紹介するソリューションは、私たちの HagiCode プロジェクトでの実践に基づいています。HagiCode Desktop は Electron ベースのデスクトップアプリで、公式サイト、GitHub Release、そして Microsoft Store という 3 つのチャネルを通じてユーザーに配布されます。ストアチャネルをどのように開通させたのか、これがこの記事で説明することです。記事の最後に HagiCode に関する詳細情報があります。興味があれば、最後までスクロールしてみてください。

分析:公開前に明確にする必要のある 4 つの質問

Microsoft Store に公開することについて、技術チェーンには 4 つの重要な判断があります。これらを明確にしておけば、後で何度もやり直す必要はありません——畢竟誰也不想返工呢。

1. Microsoft Store は MSIX / AppX のみを受け入れ、従来の NSIS/EXE は受け入れない

Microsoft Store のデスクトップアプリ(Desktop Bridge)サポートは、MSIX 形式に基づいています。従来の NSIS インストーラーは直接提出できず、まず MakeAppx を使って MSIX に再パッケージングする必要があります。幸いなことに、Electron Forge は @electron-forge/maker-msix maker を提供しており、パッケージング段階で直接 MSIX を生成できるため、インストール済みディレクトリからパッケージングを推測する手間が省けます。

私たちのプロジェクトにはこのような maker があります:

{
name: '@electron-forge/maker-msix',
platforms: ['win32'],
config: {
appManifest: msixManifestPath,
packageAssets: msixAssetsPath,
logLevel: 'warn',
...(windowsKitPath ? { windowsKitPath } : {}),
...(windowsKitVersion ? { windowsKitVersion } : {}),
...msixSigningConfig,
},
},

重要な入力は実に 2 つだけです:appManifest(つまり AppxManifest.xml、パッケージアイデンティティと機能を定義)と packageAssets(ストアアイコンアセット)。これらが間違っていると、後でどれだけ美しくしても無駄です。

2. パッケージアイデンティティは事前にパートナーセンターで予約する必要がある

MSIX パッケージ内の Identity フィールド(NamePublisher)は、適当に入力すればいいわけではありません。パートナーセンターで予約したアプリのアイデンティティと文字通り一致している必要があり、一文字でも違えば却下されます。私たちが予約したアイデンティティは、forge.store-config.json に記録されています:

{
"packageIdentity": {
"displayName": "Hagicode",
"publisherDisplayName": "newbe36524",
"publisher": "CN=8B6C8A94-AAE5-4C8B-9202-A29EA42B042F",
"identityName": "newbe36524.Hagicode",
"backgroundColor": "transparent",
"languages": ["en-US", "zh-CN", "zh-TW", "ja-JP", "ko-KR", "de-DE", "fr-FR", "es-ES", "pt-BR", "ru-RU"]
}
}

この中の publisher 文字列は、開発者アカウント登録後にマイクロソフトが発行した証明書のサブジェクトから来ており、文字単位で一致している必要があります。identityName は、あなたが予約したパッケージ名のプレフィックスです。この文字列は、パートナーセンターからそのままコピーしてください。絶対に手で入力しないでください——この件については、後の「よくある落とし穴」でまたお話しします。

3. デスクトップアプリは runFullTrust 機能を宣言する必要がある

Electron アプリは完全なファイルシステムアクセス、子プロセスの起動、Node ランタイムの実行が必要で、これらは「完全信頼」モードでのみ実現できます。したがって、MSIX マニフェストには、runFullTrust 機能を誠実に宣言する必要があります。さもないと、アプリを起動するとすぐにサンドボックスにブロックされ、謎のクラッシュとして表れます。私たちの設定はこのようになっています:

{
"msix": {
"minVersion": "10.0.17763.0",
"maxVersionTested": "10.0.19045.0",
"capabilities": [
"runFullTrust",
"internetClient",
"internetClientServer",
"privateNetworkClientsServer"
]
}
}

runFullTrust はデスクトップアプリ公開の標準です。minVersion を 17763(つまり Windows 10 1809)に設定しているのは、このバージョンから MSIX がデスクトップ Win32 アプリを安定してサポートするようになったためです。低く設定するとユーザーがインストールできず、高く設定すると古いマシンをカバーできません。

4. ストア提出には Windows 環境 + Microsoft Store CLI が必要

パッケージングはクロスプラットフォーム CI でできますが、ストア提出(msstore publish)はできません。Windows 環境で Microsoft Store CLI を実行し、Azure AD アプリの資格情報を設定する必要があります。これが、自動化パイプラインの publish_store ジョブが windows-latest runner で実行されなければならない理由です。これは回避できない厳しい制約であり、パッケージングのように Linux コンテナに押し込めることはできません。

解決:完全な公開の 8 ステッププロセス

上記の分析を繋げると、Electron アプリを Microsoft Store に公開する完全なステップはだいたい以下のようになります。

ステップ 1:開発者アカウントを登録する

まず Partner Center で開発者アカウント(個人または企業)を登録し、その一回限りの費用を支払います。アカウントが有効化されると、Publisher 証明書サブジェクト文字列が取得できます。これはだいたい次のように見えます:CN=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX。これが、後の publisher フィールドの唯一のソースです。

ステップ 2:ストアでアプリのアイデンティティを予約する

パートナーセンターで新しいアプリを作成し、予約したい名前を入力します。システムは identityName を割り当て、あなた自身の Publisher と組み合わせると、完全なパッケージアイデンティティが完成します。このアイデンティティをそのままローカル設定にコピーします:

forge.store-config.json
{
"packageIdentity": {
"displayName": "Hagicode",
"publisherDisplayName": "newbe36524",
"publisher": "CN=8B6C8A94-AAE5-4C8B-9202-A29EA42B042F",
"identityName": "newbe36524.Hagicode"
}
}

ステップ 3:ストアのアイコンアセットを準備する

Microsoft Store は一連の固定サイズの PNG を必要とします:StoreLogo.pngSquare44x44Logo.pngSquare150x150Logo.pngWide310x150Logo.png など。私たちの prepare-msix.js スクリプトは、パッケージング前にこれらのアセットがすべて揃っているかをチェックします:

// ストアに必要なアイコンアセットをチェック、一つでも欠けるとダメ
const requiredAssets = ['StoreLogo.png', 'Square44x44Logo.png', 'Square150x150Logo.png', 'Wide310x150Logo.png'];
for (const assetName of requiredAssets) {
const assetPath = path.join(paths.generatedAssetsPath, assetName);
if (!fs.existsSync(assetPath)) {
throw new Error(`Missing required MSIX asset after preparation: ${assetPath}`);
}
}

なぜこれをするのか? というのは、サイズが一つでも欠けていると、MakeAppx はパッケージング時に具体的なエラーを教えてくれず、ストアの審査時に却下されるからです——その時、あなたはもう数日待っています。事前にチェックすることは、非常に有効な防御策です。

ステップ 4:AppxManifest.xml を生成する

マニフェストには、パッケージアイデンティティ、機能、ビジュアルアセット、エントリポイント実行ファイルを詰め込みます。私たちはオーバーライド設定(forge.store-config.json)を使って prepare-msix.js を駆動し、マニフェストを生成します。アイデンティティがストアと一致していることを確保します。マニフェストの重要な部分はだいたいこうなります:

<!-- パッケージアイデンティティ:パートナーセンターと一致している必要がある -->
<Identity Name="newbe36524.Hagicode"
Publisher="CN=8B6C8A94-AAE5-4C8B-9202-A29EA42B042F"
Version="1.2.3.0" />
<Applications>
<Application Id="Hagicode" Executable="Hagicode.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements ... />
</Application>
</Applications>
<!-- 機能宣言:runFullTrust はデスクトップアプリの重要なポイント -->
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<Capability Name="internetClientServer" />
</Capabilities>

EntryPoint="Windows.FullTrustApplication" の行に注意してください。これはデスクトップアプリの重要なマークであり、runFullTrust 機能と組み合わせることで、完全な権限で実行できます。これがないと、アプリはサンドボックスの中で大人しくしていることしかできません。

ステップ 5:maker-msix でパッケージングする

ビルドコマンドは package.json に書かれています:

{
"scripts": {
"build:win:store": "npm run generate:store-bindings && node scripts/build-store-package.js"
}
}

これが最終的に Electron Forge を起動し、forge.store-config.json をオーバーライド設定として渡します。maker-msix は Windows SDK の MakeAppx を呼び出し、.msix ファイルを吐き出します。ここには厳しい制約があります:パッケージングは必ず Windows 上で行う必要がある(または Windows SDK 入りのコンテナ内)。結局 MakeAppx に依存しており、これは回避できません。

ステップ 6:署名(ストア提出時は署名不要)

このステップは、実は簡単に見逃されます——ストアに提出するパッケージは、マイクロソフトが自分の証明書で再署名するため、「正式な提出」以外の開発自己テスト段階では、署名しなくても構いません。ただ、ローカルでテストインストールしたい場合は、信頼された証明書で署名する必要があります。さもないと、Windows はインストールを拒否します。私たちの resolveMsixSigningConfig は、署名材料が設定されていない場合、空のオブジェクトを返して、プロセスを続けさせます:

// 署名材料が設定されていない場合は署名しない、ストアで一括再署名させる
function resolveMsixSigningConfig() {
if (!process.env.MSIX_CERT_FILE) return {};
return {
signMethod: 'signtool',
certFilePath: process.env.MSIX_CERT_FILE,
certPassword: process.env.MSIX_CERT_PASSWORD,
};
}

「自己テスト署名」と「提出時の空署名」という 2 つのパスを分けることは、非常に重要な実践です。

ステップ 7:Microsoft Store CLI 資格情報を設定する

Azure ポータルで Azure AD アプリを作成し、Partner Center へのアクセス権限を付与し、次の資格情報を取得します:

  • AZURE_AD_APPLICATION_CLIENT_ID
  • AZURE_AD_APPLICATION_SECRET
  • AZURE_AD_TENANT_ID
  • SELLER_ID(パートナーセンターの販売者 ID)
  • MICROSOFT_STORE_PRODUCT_ID(予約したアプリの製品 ID)

このステップは少し複雑ですが、Azure ポータルと Partner Center のドキュメントには詳しく書かれているので、従ってください。

ステップ 8:ストアに提出する

Windows 環境で、Microsoft Store CLI を使って提出します:

Terminal window
# 資格情報を設定
msstore reconfigure --tenantId $env:AZURE_AD_TENANT_ID `
--clientId $env:AZURE_AD_APPLICATION_CLIENT_ID `
--clientSecret $env:AZURE_AD_APPLICATION_SECRET `
--sellerId $env:SELLER_ID
# MSIX パッケージを予約した製品に提出
msstore publish "$packagePath" -id $env:MICROSOFT_STORE_PRODUCT_ID

提出した後、Partner Center に戻ってストアの詳細(説明、スクリーンショット、価格、レーティング)をすべて埋め、最後に審査提出をクリックします。審査には通常 1–3 営業日かかります。初回の審査なので、少し時間がかかります。

実践:設定と落とし穴の経験を蓄積する

一度プロセスを完了した後、以下の実践で、いくつかの遠回りを避けることができます——毕竟弯路走多了,也就不觉得弯了,只是有些事能省则省。

設定ファイルは分けて保存する

「一般ビルド設定」と「ストア専用設定」を分けて保存することが重要です。私たちのやり方は:forge.config.js は日常ビルド(NSIS、portable、macOS dmg)を実行し、forge.store-config.json はストアビルド時にのみ extends を通じて継承しオーバーライドします:

{
"extends": "forge.config.js",
"buildVersion": "0.1.0.0",
"packageIdentity": { /* ストアで予約したアイデンティティ */ },
"msix": {
"minVersion": "10.0.17763.0",
"maxVersionTested": "10.0.19045.0",
"capabilities": ["runFullTrust", "internetClient", "internetClientServer", "privateNetworkClientsServer"]
}
}

これにより、ストア版とリリース版が互いに汚染されません。HagiCode Desktop は 3 つの配信チャネルを同時に維持していますが、設定を分けることで、安定して反復し続けることができます。

バージョン番号は 4 セグメントでなければならない

MSIX のバージョン番号は Major.Minor.Build.Revision の 4 セグメント(例:1.2.3.0)でなければなりませんが、Electron の package.json は通常 3 セグメントしか書きません。buildVersion フィールドは、最後のセグメントを補うために使われます——ストア提出時、バージョン番号は増分する必要があり、第 4 セグメントは同じセマンティックバージョンでの複数回の提出を区別するのに非常に便利です。この点、踏んだ人はわかります。踏んでいない人は、いずれ踏みます。

多言語宣言

ストアは複数言語のリスティングをサポートしており、マニフェストでは <Resource Language="..." /> の各エントリに対応します。私たちは 10 言語を宣言しており、ストアは各言語に説明を入れることを要求します(まず機械翻訳で審査を通し、後でゆっくりローカライズできます)。prepare-msix.js の対応するレンダリングロジックはこうなっています:

// 言語リストを MSIX マニフェストの Resource タグにレンダリングする
function renderResourceTags(languages) {
return languages
.map((language) => ` <Resource Language="${escapeXml(language)}" />`)
.join('\n');
}

よくある落とし穴(重点)

以下の落とし穴は、HagiCode Desktop がほぼすべて踏んだものです:

  1. Publisher が一致しない:Partner Center から publisher 文字列をコピーする際、うっかりスペースを落としたり大文字小文字を間違えたりすると、提出が直ちに拒否されます。設定ファイルに直接書くことをお勧めします。手で入力しないでください。
  2. runFullTrust が欠けている:アプリ起動後、ファイルシステムにアクセスできず、子プロセスも起動できず、謎のクラッシュとして表れます。原因究明には大変苦労します。
  3. アイコンサイズが不完全:MakeAppx はチェックしませんが、ストア審査は却下します。prepare-msix.js で事前にチェックすることは、有効な防御策です。
  4. バージョン番号が増分しない:ストアは同じまたは低いバージョン番号の受信を拒否します。CI パイプラインは各ビルドごとに増分することを保証する必要があります。
  5. Windows 以外の環境で maker-msix を実行するMakeAppx が見つかりません。windows-latest runner を使用する必要があります。
  6. 署名が混乱している:自己テストは自己署名証明書、ストア提出は空署名でマイクロソフトに再署名させます。この 2 つのパスを分けて、自己署名証明書を提出パッケージに入れないでください。

自動化の提案

最初は手動で全プロセスを完了させ、各ステップを把握した後、強く GitHub Actions で自動化することをお勧めします。私たちは最終的に、バージョン解析、MSIX ビルド、GitHub Release 公開、ストア公開を一条のパイプラインに繋ぎ、4 時間ごとに新バージョンをチェックしています。この部分の詳細は、私たちの別の記事《Windows アプリを Microsoft Store に自動公開する自動化実践》で完全に分解されています。

まずアプリをストアに掲載し、商業化(サブスクリプション / 永久ライセンス)を統合してから自動化を始めたい場合は、私たちの《Electron デスクトップアプリで Microsoft Store のサブスクリプションと永久ライセンスを統合する方法》も見てください。そちらは、ストア公開後の商業化機能の統合について説明しています。

参考資料

まとめ

「Electron アプリを Microsoft Store に公開する方法:MSIX パッケージングからストア提出まで」について、より堅実な推進方法は、まず重要な設定、依存境界、実装パスを徐々に動かし、その後最適化の詳細を補うことです。

目標、ステップ、検収ポイントが明確になると、この種のソリューションは通常、よりスムーズに実際のデリバリーに入ることができます。

开始使用 HagiCode

一次安装,几分钟上手

HagiCode for Windows 在 Microsoft Store 免费提供。打开商店即可安装并保持更新;也可以先对比各版本与定价,再决定从哪个渠道开始。