Python デスクトップツールをMSIXにパッケージングしてMicrosoft Storeに公開する方法
2026-04-27
Tags: チュートリアル · Python · Windows · MSIX · パッケージング
はじめに
前回の記事で、RDP Heartbeat の開発の動機と過程について書きました。その記事の最後で、次のように述べました:
時間ができたら、PythonからMSIXまでのパッケージングの全工程について詳しく書くつもりです。
その記事が完成しました。
正直なところ、Pythonで書いたデスクトップツールをMicrosoft Storeに載せるのは、C# / WinUI 3を使う場合よりずっと面倒です。後者ならVisual Studioでほぼワンクリックですが、私と同じくPythonを使っているなら、次のような道のりになります:
Python ソース → PyInstaller → EXE → Inno Setup → インストーラ → MSIX Packaging Tool → MSIX → Storeそれぞれのステップで落とし穴がありますが、すべて解決策もあります。この記事はその地図と攻略法です。
この記事ではRDP Heartbeatプロジェクトを例にしていますが、方法とアプローチはPython + Tkinter(またはPyQt、wxPythonなど)で書かれたWindowsツール全般に適用できます。
補足:理論上はPyInstallerで生成したexeを直接MSIX Packaging Toolで変換し、Inno Setupをスキップできるかもしれません。Inno Setupを挟む主な理由は、自分で配布しやすくするためです(GitHub ReleaseにSetup.exeを置いてダウンロードできるようにするなど)。理論上の最適解ではないかもしれませんが、この方法で確実に動作したので共有します。
参考ソースコード:この記事で扱う完全なプロジェクトコードは [email protected] で確認できます。
build_release.py、setup.iss、およびすべてのパッケージング設定が含まれています。
全体図:4つのステップ
始める前に、全体の流れを整理しましょう:
- PyInstaller:
.py→.exe - Inno Setup:
.exe→ インストーラ - MSIX Packaging Tool:インストーラ →
.msix - Microsoft Store:公開
なぜこんなに回り道をするのか?Microsoft Storeが最終的に必要とするのは MSIX形式のパッケージ だからです。MSIX Packaging Toolの仕組みは、正常にインストール・実行できる従来のインストーラを「変換」することです。インストール過程を監視し、ファイルの書き込み、レジストリの変更、ショートカットの作成をすべてキャプチャし、自動的にMSIXを生成します。そのため、まずクリーンで完全な従来のインストーラが必要です。
言い換えると:PyInstallerが「動くこと」を担当し、Inno Setupが「インストールできること」を担当し、MSIX Packaging Toolが「Storeに載せられること」を担当します。
では、一歩ずつ見ていきましょう。
ステップ1:PyInstaller —— PythonをEXEにする
1.1 プロジェクトの準備
始める前に、Pythonプロジェクトの構造が明確で、エントリポイントがはっきりしていることを確認しましょう。RDP Heartbeatを例にします:
prune-rdp-heartbeat/
├── main.py # エントリスクリプト
├── heartbeat_window.py # コアウィンドウロジック
├── win_utils.py # Win32 API ラッパー
├── tray_icon.py # システムトレイ
├── settings_dialog.py # 設定パネル
├── about_dialog.py # バージョン情報ダイアログ
├── config_manager.py # 設定管理
├── i18n.py # 国際化
├── startup.py # 自動起動
├── logger.py # ログ
├── version.py # バージョン番号
├── icon.ico # アプリケーションアイコン
├── icon.png # ソースアイコン(MSIXリソースの生成用)
├── requirements.txt # 依存関係
└── packaging/ # MSIX関連リソース(後で使用)依存関係 requirements.txt:
pystray
Pillow
pywin32
customtkinter
packaging1.2 PyInstallerの「暗黙の依存関係」の処理
PyInstallerは静的解析で依存関係を検出しますが、一部のライブラリ(特に pystray、PIL)は検出できず、手動で宣言する必要があります:
# build_release.py の主要設定
cmd = [
sys.executable, "-m", "PyInstaller",
"--noconsole", # コンソールウィンドウを表示しない
"--onefile", # 単一exeにまとめる
"--name=RDPHeartbeat",
"--clean",
"--icon=icon.ico",
"--add-data=icon.ico;.", # Windowsはセミコロン、Linux/macOSはコロン
"--hidden-import=PIL._tkinter_finder",
"--hidden-import=pystray",
"main.py"
]また、リソースファイル(アイコンなど)はパッケージング後に一時ディレクトリに展開されるため、resource_path() で対応する必要があります:
# tray_icon.py のアプローチ
def resource_path(relative_path):
try:
base_path = sys._MEIPASS # PyInstallerが展開する一時ディレクトリ
except Exception:
base_path = os.path.abspath(".") # 開発モード:カレントディレクトリ
return os.path.join(base_path, relative_path)ファイルシステムから読み取る必要があるリソース(アイコン、フォント、設定ファイルテンプレートなど)はすべて、この関数を通す必要があります。
1.3 ワンクリックビルドスクリプト
PyInstallerコマンドを build_release.py にまとめます:
# まずversion.pyからバージョン番号を取得
from version import APP_VERSION
def run_build():
# 0. 前回のビルド成果物をクリーンアップ
if os.path.exists("build"): shutil.rmtree("build")
if os.path.exists("dist"): shutil.rmtree("dist")
# 1. PyInstallerを実行
subprocess.check_call([...])
# 2. 成果物を確認
exe_path = os.path.join("dist", "RDPHeartbeat.exe")
assert os.path.exists(exe_path), "Build failed!"python build_release.py を実行し、すべてうまくいけば dist/ に RDPHeartbeat.exe が生成されます。
ダブルクリックして正しく動作することを確認しましょう。
ステップ2:Inno Setup —— EXEを正規のインストーラにする
MSIX Packaging Toolには変換元としてインストーラが必要です。Windowsエコシステムでは、Inno Setupは無料で成熟したスクリプトベースのインストーラ作成ツールです。
2.1 Inno Setupのインストール
jrsoftware.org からダウンロードしてインストールします。Inno Script Studio(ビジュアルエディター)も一緒にインストールすることをお勧めします。
2.2 インストールスクリプトの作成
コアファイル setup.iss:
#define MyAppName "RDP Heartbeat"
#define MyAppVersion "1.1.3.0"
#define MyAppPublisher "Prune Lab"
#define MyAppExeName "RDPHeartbeat.exe"
[Setup]
AppId={{DDEC247A-5DC0-4393-BB13-466CCAD7F90B} ; アプリケーションごとに固有のGUID
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName} ; デフォルトはProgram Files
ArchitecturesAllowed=x64compatible ; 64ビットシステム
ArchitecturesInstallIn64BitMode=x64compatible
DisableProgramGroupPage=yes ; 「プログラムグループの選択」ページをスキップ
OutputBaseFilename=RDPHeartbeat_Setup ; 出力ファイル名
SolidCompression=yes
WizardStyle=modern ; モダンなインストールウィザードスタイル
SetupIconFile=icon.ico
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: "dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; Flags: unchecked
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,...}"; Flags: nowait postinstall skipifsilent注意すべき点:
- AppIdは一意である必要があります:これはWindowsがアプリケーションを識別するためのものです。他のソフトウェアと競合しないようにしてください。Inno Setup IDEでGUIDをワンクリックで生成できます。
- レジストリの書き込みは不要:MSIX変換時にインストール過程のレジストリ書き込みが自動的に処理されますが、このアプリ自体は不要なので、書かない方がクリーンです。
2.3 バージョン番号の自動同期
バージョン番号がPythonコード(version.py)で定義されていて、setup.iss にもある場合、手動同期は迟早ミスが生じます。そこで build_release.py に自動パッチを追加します:
def patch_setup_iss():
with open("setup.iss", 'r', encoding='utf-8') as f:
content = f.read()
content = re.sub(
r'#define MyAppVersion ".*?"',
f'#define MyAppVersion "{APP_VERSION}"',
content
)
with open("setup.iss", 'w', encoding='utf-8') as f:
f.write(content)これで python build_release.py を実行すると、最新のバージョン番号が自動的に setup.iss に書き込まれ、その後PyInstallerが実行されます。
2.4 インストーラのコンパイル
Inno Setup IDEを開き、setup.iss を読み込み、Compileをクリックします。出力は RDPHeartbeat_Setup.exe です。
確認:クリーンな仮想マシンまたは別のコンピューターでインストーラを実行し、次の点を確認してください:
- 正常にインストールできる
- プログラムが起動する
- アンインストール後に残存物がない(Inno Setupのアンインストーラは
{app}\unins000.exeにあり、MSIXにまとめてパッケージされますが、問題ありません)
ステップ3:MSIX Packaging Tool —— インストーラからStore形式へ
Microsoft Storeへの公開を予定している場合は、先にPartner Centerに登録してアプリ名を予約することをお勧めします(ステップ4を参照)。MPTで入力するPackage NameとPublisherは、Storeで予約した情報と一致する必要があるためです。自分でテストするだけの場合は、登録をスキップして任意の名前を使用できます。
3.1 環境の準備
必要なもの:
- MSIX Packaging Tool(公式ドキュメント)
- クリーンな環境(仮想マシンまたは別のコンピューターの使用を推奨。MPTはインストール過程全体を監視するため、システム上の他のプログラムがノイズとしてキャプチャされる可能性があります)
- 署名証明書:テスト段階では自己署名証明書を使用できます。PowerShell(管理者)で実行:
New-SelfSignedCertificate -Type Custom -Subject "CN=YourName" -KeyUsage DigitalSignature -FriendlyName "Your Cert" -CertStoreLocation "Cert:\CurrentUser\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}")証明書をエクスポートして保存:
$password = ConvertTo-SecureString -String "YourPassword" -Force -AsPlainText
Export-PfxCertificate -Cert "Cert:\CurrentUser\My\<Thumbprint>" -FilePath "C:\cert.pfx" -Password $password正式に公開する際、Microsoft Storeは独自の証明書で再署名するため、コード署名証明書を購入する必要はありません。ただし、Store以外の場所で配布する場合(自分のWebサイトでMSIXのダウンロードを提供するなど)は、正式なコード署名証明書を購入する必要があります。
3.2 MSIX Packaging Toolの実行
- MPTを開き、"Application package" → "Create a new package" を選択します。
- "Select environment" のステップでは、デフォルトのまま Next をクリックします。
- 重要なステップ:MPTがインストーラのパスを選択するように求められます。先ほど生成した
RDPHeartbeat_Setup.exeを選択します。 - MPTがシステムの監視を開始し、インストーラが起動します。インストールを最後まで完了してください。インストーラの最後に "Launch RDP Heartbeat" がチェックされていても、そのまま起動して構いません。
- インストールが完了したら、"Next" をクリックして監視を停止します。
- MPTが検出したすべてのプロセスが表示されます。アプリに属さないもの(システムプロセス、ウイルス対策ソフトの更新プロセスなど)のチェックを外します。通常は
RDPHeartbeat.exe、unins000.exeなどだけを残します。 - アプリケーション情報を入力します:
- Package name:Storeに公開する場合は、Partner Centerでアプリを予約した際に割り当てられた名前(例:
PruneLab.RDPHeartbeat)を入力します。自分でテストするだけの場合は任意の名前を使用でき、推奨形式はYourName.YourAppです。 - Package display name:アプリの表示名。例:
RDP Heartbeat。 - Publisher display name:パブリッシャー名。例:
Prune Lab。 - Publisher:Storeに公開する場合は、Partner Centerアカウントに対応するPublisher証明書のサブジェクト(例:
CN=21C32622-53AF-45A6-8AB1-B35BCD475CAD)を入力します。自分でテストする場合は、自己署名証明書のSubject(例:CN=YourName)を入力します。 - Version:インストーラから自動的に取得されます。
- Package name:Storeに公開する場合は、Partner Centerでアプリを予約した際に割り当てられた名前(例:
- 出力ディレクトリを指定し、MSIXパッケージを生成します。
3.3 MSIXパッケージのテスト
.msix ファイルが生成されたら、すぐにmanifestを編集せず、まずダブルクリックしてインストールし、正常に動作するか確認してください。自己署名証明書を使用している場合は、インストール前に証明書をシステムの「信頼されたユーザー」ストアにインポートする必要があります(前のセクションの証明書エクスポートコマンドを参照し、Import-PfxCertificate を使用してください)。
ステップ4:Microsoft Storeに提出する
4.1 登録とアプリ名の予約
- Microsoft Partner Center に開発者アカウントを登録します。
- Partner Centerでアプリ名を予約します(Products → New Product → 名前を入力)。予約すると、Package NameとPublisherの情報が得られます。これらはMSIXパッケージの
AppxManifest.xmlと一致させる必要があります。
4.2 提出プロセス
- アプリ → Submissions → New submission に進みます。
- 各フィールドを入力します:
- Packages:
.msixファイルをアップロード - Description:アプリの説明(複数言語に対応、少なくとも英語と中国語を推奨)
- Screenshots:1366×768以上のアプリのスクリーンショット
- Store listing:アイコン、プロモーション画像、機能一覧
- Packages:
- 審査に提出します。初回の審査は通常1〜3営業日かかります。
まとめ:この方法は価値があるか?
Pythonツールで大金を稼ごうとしているなら、答えは「おそらくNo」です。WinUI 3 / .NET で書き直した方が、パッケージングの体験はずっと良いでしょう。
しかし、私と同じように——すでにPythonで書いていて、普段から使っているツールがあり、それをより多くの人に共有したいと思っているなら——この方法は回り道ですが、少なくとも機能します。
パイプラインを振り返ってみましょう:
| ステップ | ツール | 出力 |
|---|---|---|
| .py → .exe | PyInstaller | 単一exe |
| .exe → インストーラ | Inno Setup | Setup.exe |
| インストーラ → MSIX | MSIX Packaging Tool | .msix |
| 提出 | Partner Center | Store公開 |
この記事が、少しでも遠回りを減らすのに役立てば幸いです。PythonツールをStoreに載せた方がいれば、RDP HeartbeatのGitHub でぜひ交流してください。