Packager un outil desktop Python en MSIX pour le Microsoft Store
2026-04-27
Tags: Tutoriel · Python · Windows · MSIX · Empaquetage
Introduction
Dans un article précédent, j'ai décrit la motivation et le processus de développement de RDP Heartbeat. À la fin de cet article, j'ai mentionné :
Je prévois d'écrire un article détaillant l'ensemble du processus d'empaquetage de Python vers MSIX lorsque j'aurai le temps.
Le voici.
Honnêtement, publier un outil desktop écrit en Python sur le Microsoft Store est beaucoup plus complexe qu'avec C# / WinUI 3. Avec ces derniers, Visual Studio gère presque tout en quelques clics. Mais si vous êtes comme moi et utilisez Python, le chemin ressemble à ça :
Source Python → PyInstaller → EXE → Inno Setup → Installateur → MSIX Packaging Tool → MSIX → StoreChaque étape peut comporter des pièges, mais chacune a aussi ses solutions. Cet article est la carte et le guide.
Cet article utilise le projet RDP Heartbeat comme exemple, mais les méthodes et approches s'appliquent à tout outil Windows écrit en Python + Tkinter (ou PyQt, wxPython, etc.).
Une remarque : en théorie, il est possible de convertir directement un exe généré par PyInstaller avec le MSIX Packaging Tool, en sautant Inno Setup. Nous avons choisi de passer d'abord par Inno Setup principalement pour faciliter la distribution autonome (par exemple, mettre un Setup.exe sur GitHub Releases). Ce n'est pas forcément la solution optimale en théorie, mais c'est celle que nous avons validée en pratique.
Code source de référence : Le code complet du projet abordé dans cet article est disponible sur [email protected], incluant
build_release.py,setup.isset toutes les configurations d'empaquetage.
Vue d'ensemble : Le pipeline en quatre étapes
Avant de commencer, déroulons l'ensemble de la chaîne :
- PyInstaller :
.py→.exe - Inno Setup :
.exe→ Installateur - MSIX Packaging Tool : Installateur →
.msix - Microsoft Store : Soumission
Pourquoi un tel détour ? Parce que le Microsoft Store nécessite finalement un paquet au format MSIX, et le MSIX Packaging Tool fonctionne en « convertissant » un installateur traditionnel déjà fonctionnel — il surveille le processus d'installation, capture toutes les écritures de fichiers, les modifications du registre et les créations de raccourcis, puis génère automatiquement un MSIX. Il vous faut donc d'abord un installateur traditionnel propre et complet.
En d'autres termes : PyInstaller s'occupe de « ça fonctionne », Inno Setup de « ça s'installe », et le MSIX Packaging Tool de « ça peut être publié sur le Store ».
Procédons étape par étape.
Étape 1 : PyInstaller — Transformer Python en EXE
1.1 Préparer votre projet
Avant de commencer, assurez-vous que la structure de votre projet Python est claire et que le point d'entrée est bien défini. Prenons RDP Heartbeat comme exemple :
prune-rdp-heartbeat/
├── main.py # Script d'entrée
├── heartbeat_window.py # Logique de la fenêtre principale
├── win_utils.py # Wrappers API Win32
├── tray_icon.py # Barre d'état système
├── settings_dialog.py # Panneau de paramètres
├── about_dialog.py # Boîte de dialogue À propos
├── config_manager.py # Gestion de la configuration
├── i18n.py # Internationalisation
├── startup.py # Démarrage automatique
├── logger.py # Journalisation
├── version.py # Numéro de version
├── icon.ico # Icône de l'application
├── icon.png # Icône source (pour générer les ressources MSIX)
├── requirements.txt # Dépendances
└── packaging/ # Ressources MSIX (utilisées plus tard)Dépendances dans requirements.txt :
pystray
Pillow
pywin32
customtkinter
packaging1.2 Gérer les « dépendances cachées » de PyInstaller
PyInstaller détecte les dépendances par analyse statique, mais certaines bibliothèques (notamment pystray, PIL) ne sont pas détectées et doivent être déclarées manuellement :
# Configuration clé dans build_release.py
cmd = [
sys.executable, "-m", "PyInstaller",
"--noconsole", # Pas de fenêtre de console
"--onefile", # Empaqueter en un seul exe
"--name=RDPHeartbeat",
"--clean",
"--icon=icon.ico",
"--add-data=icon.ico;.", # Windows utilise le point-virgule, Linux/macOS les deux-points
"--hidden-import=PIL._tkinter_finder",
"--hidden-import=pystray",
"main.py"
]De plus, les fichiers de ressources (comme les icônes) sont extraits dans un répertoire temporaire après l'empaquetage, il faut donc resource_path() pour la compatibilité :
# Approche dans tray_icon.py
def resource_path(relative_path):
try:
base_path = sys._MEIPASS # Répertoire temporaire de PyInstaller
except Exception:
base_path = os.path.abspath(".") # Mode développement : répertoire courant
return os.path.join(base_path, relative_path)Toute ressource nécessitant une lecture depuis le système de fichiers (icônes, polices, modèles de configuration, etc.) doit passer par cette fonction.
1.3 Script de build en un clic
Encapsulez la commande PyInstaller dans build_release.py :
# D'abord lire version.py pour obtenir le numéro de version
from version import APP_VERSION
def run_build():
# 0. Nettoyer les artefacts du build précédent
if os.path.exists("build"): shutil.rmtree("build")
if os.path.exists("dist"): shutil.rmtree("dist")
# 1. Exécuter PyInstaller
subprocess.check_call([...])
# 2. Vérifier le résultat
exe_path = os.path.join("dist", "RDPHeartbeat.exe")
assert os.path.exists(exe_path), "Build failed!"Exécutez python build_release.py. Si tout se passe bien, vous obtiendrez RDPHeartbeat.exe dans dist/.
Vous pouvez double-cliquer pour vérifier que tout fonctionne correctement.
Étape 2 : Inno Setup — Transformer l'EXE en véritable installateur
Le MSIX Packaging Tool a besoin d'un installateur comme source de conversion. Dans l'écosystème Windows, Inno Setup est un outil gratuit, mature et scriptable de création d'installateurs.
2.1 Installer Inno Setup
Téléchargez et installez depuis jrsoftware.org. Il est recommandé d'installer également Inno Script Studio (éditeur visuel).
2.2 Écrire le script d'installation
Le fichier principal 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 unique par application
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName} ; Par défaut dans Program Files
ArchitecturesAllowed=x64compatible ; Systèmes 64 bits
ArchitecturesInstallIn64BitMode=x64compatible
DisableProgramGroupPage=yes ; Ignorer la page « Sélectionner un groupe de programmes »
OutputBaseFilename=RDPHeartbeat_Setup ; Nom du fichier de sortie
SolidCompression=yes
WizardStyle=modern ; Style d'assistant moderne
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 skipifsilentQuelques points importants :
- AppId doit être unique : c'est ce qui permet à Windows d'identifier l'application. Évitez les conflits avec d'autres logiciels. L'IDE Inno Setup peut générer un GUID en un clic.
- Pas besoin d'écrire dans le registre : la conversion MSIX gère automatiquement les écritures dans le registre lors de l'installation, mais notre application n'en a de toute façon pas besoin.
2.3 Synchronisation automatique du numéro de version
Votre numéro de version peut être défini dans le code Python (version.py), et il y a aussi une copie dans setup.iss. La synchronisation manuelle finira par causer des erreurs. Ajoutez donc un patch automatique dans 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)Maintenant, quand vous exécutez python build_release.py, la dernière version est automatiquement écrite dans setup.iss, puis PyInstaller est lancé.
2.4 Compiler l'installateur
Ouvrez l'IDE Inno Setup, chargez setup.iss, et cliquez sur Compile. Le résultat est RDPHeartbeat_Setup.exe.
Vérification : Exécutez l'installateur sur une VM propre ou un autre ordinateur et confirmez :
- L'installation se déroule correctement
- Le programme se lance
- Aucun résidu après désinstallation (le désinstallateur d'Inno Setup se trouve dans
{app}\unins000.exe, MSIX l'inclura dans le paquet, pas de problème)
Étape 3 : MSIX Packaging Tool — De l'installateur au format Store
Si vous prévoyez de publier sur le Microsoft Store, il est recommandé de d'abord vous inscrire au Partner Center et réserver le nom de l'application (voir Étape 4), car le Package Name et le Publisher renseignés dans MPT doivent correspondre aux informations réservées sur le Store. Si vous faites seulement des tests, vous pouvez ignorer l'inscription et utiliser n'importe quel nom.
3.1 Préparer l'environnement
Vous aurez besoin de :
- MSIX Packaging Tool (Documentation officielle)
- Un environnement propre (machine virtuelle ou ordinateur séparé recommandé, car MPT surveille tout le processus d'installation — d'autres programmes sur votre système pourraient être capturés comme du bruit)
- Certificat de signature : pour les tests, vous pouvez utiliser un certificat auto-signé. Dans PowerShell (administrateur) :
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}")Exporter le certificat :
$password = ConvertTo-SecureString -String "YourPassword" -Force -AsPlainText
Export-PfxCertificate -Cert "Cert:\CurrentUser\My\<Thumbprint>" -FilePath "C:\cert.pfx" -Password $passwordLors de la publication officielle, le Microsoft Store re-signera avec son propre certificat, vous n'avez donc pas besoin d'acheter un certificat de signature de code. Mais si vous souhaitez distribuer en dehors du Store (par exemple, proposer un téléchargement MSIX sur votre propre site), vous devrez acheter un certificat de signature de code approprié.
3.2 Exécuter le MSIX Packaging Tool
- Ouvrez MPT, sélectionnez "Application package" → "Create a new package".
- À l'étape "Select environment", gardez les valeurs par défaut et cliquez sur Next.
- Étape clé : MPT vous demande de sélectionner le chemin de l'installateur. Choisissez le
RDPHeartbeat_Setup.exeque vous venez de générer. - MPT commence à surveiller le système et lance l'installateur. Terminez l'installation normalement — si l'installateur a coché "Launch RDP Heartbeat" à la fin, ce n'est pas un problème.
- Une fois l'installation terminée, cliquez sur "Next" — MPT arrête la surveillance.
- MPT affiche tous les processus détectés. Décochez ceux qui n'appartiennent pas à votre application (processus système, mises à jour antivirus, etc.). Ne conservez généralement que
RDPHeartbeat.exe,unins000.exe, etc. - Remplissez les informations de l'application :
- Package name : Pour le Store, utilisez le nom attribué lors de la réservation sur Partner Center (ex. :
PruneLab.RDPHeartbeat). Pour des tests locaux, vous pouvez utiliser n'importe quel nom — format recommandé :YourName.YourApp. - Package display name : Le nom d'affichage de l'application, ex. :
RDP Heartbeat. - Publisher display name : Nom de l'éditeur, ex. :
Prune Lab. - Publisher : Pour le Store, utilisez le sujet du certificat Publisher de votre compte Partner Center (ex. :
CN=21C32622-53AF-45A6-8AB1-B35BCD475CAD). Pour des tests locaux, utilisez le Subject de votre certificat auto-signé (ex. :CN=YourName). - Version : Extraite automatiquement de l'installateur.
- Package name : Pour le Store, utilisez le nom attribué lors de la réservation sur Partner Center (ex. :
- Spécifiez le répertoire de sortie et générez le paquet MSIX.
3.3 Tester le paquet MSIX
Après avoir généré le fichier .msix, ne modifiez pas encore le manifest. Double-cliquez pour l'installer et vérifiez qu'il fonctionne correctement. Si vous utilisez un certificat auto-signé, vous devez d'abord l'importer dans le magasin « Personnes de confiance » du système (voir la commande d'exportation dans la section précédente, utilisez Import-PfxCertificate).
Étape 4 : Soumettre au Microsoft Store
4.1 Inscription et réservation de nom
- Inscrivez-vous pour un compte développeur Microsoft Partner Center.
- Dans Partner Center, réservez le nom de l'application (Products → New Product → saisir le nom). Après la réservation, vous obtiendrez le Package Name et les informations Publisher, qui doivent correspondre à l'
AppxManifest.xmlde votre paquet MSIX.
4.2 Processus de soumission
- Accédez à votre application → Submissions → New submission.
- Remplissez les champs :
- Packages : Téléchargez le fichier
.msix - Description : Description de l'application (multilingue, au moins anglais et chinois recommandés)
- Screenshots : Au moins une capture d'écran 1366×768
- Store listing : Icônes, images promotionnelles, liste de fonctionnalités
- Packages : Téléchargez le fichier
- Soumettez pour examen. Le premier examen prend généralement 1 à 3 jours ouvrés.
Conclusion : Cela vaut-il le coup ?
Si vous comptez gagner beaucoup d'argent avec un outil Python, la réponse est « probablement pas ». Réécrire avec WinUI 3 / .NET offrirait une bien meilleure expérience d'empaquetage.
Mais si vous êtes comme moi — vous avez déjà un outil écrit en Python que vous utilisez régulièrement et souhaitez le partager avec d'autres — alors ce processus, bien que détourné, fonctionne au moins.
Rétrospective du pipeline :
| Étape | Outil | Résultat |
|---|---|---|
| .py → .exe | PyInstaller | Un seul exe |
| .exe → Installateur | Inno Setup | Setup.exe |
| Installateur → MSIX | MSIX Packaging Tool | .msix |
| Soumission | Partner Center | Publication sur le Store |
J'espère que cet article vous évitera quelques détours. Si vous avez également publié un outil Python sur le Store, n'hésitez pas à partager votre expérience sur le GitHub de RDP Heartbeat.