Skip to content

Empacotando uma ferramenta de desktop Python como MSIX para a Microsoft Store

2026-04-27

Tags: Tutorial · Python · Windows · MSIX · Empacotamento

Introdução

Em um artigo anterior, escrevi sobre a motivação e o processo de desenvolvimento do RDP Heartbeat. No final daquele artigo, mencionei:

Estou planejando escrever um artigo detalhando todo o processo de empacotamento do Python ao MSIX quando tiver tempo.

Aqui está.

Sinceramente, levar uma ferramenta de desktop escrita em Python para a Microsoft Store é muito mais trabalhoso do que usar C# / WinUI 3. Com estes últimos, o Visual Studio cuida de tudo com alguns cliques. Mas se você é como eu e usa Python, o caminho é este:

Código-fonte Python → PyInstaller → EXE → Inno Setup → Instalador → MSIX Packaging Tool → MSIX → Store

Cada etapa pode ter armadilhas, mas cada uma também tem soluções. Este artigo é o mapa e o guia.

Este artigo usa o projeto RDP Heartbeat como exemplo, mas os métodos e abordagens se aplicam a qualquer ferramenta Windows escrita em Python + Tkinter (ou PyQt, wxPython, etc.).

Uma observação: teoricamente, é possível converter diretamente um exe gerado pelo PyInstaller com o MSIX Packaging Tool, pulando o Inno Setup. Escolhemos passar primeiro pelo Inno Setup principalmente para facilitar a distribuição própria (por exemplo, colocar um Setup.exe no GitHub Releases para download). Pode não ser a solução teoricamente ideal, mas é a que realmente funcionou para nós.

Código-fonte de referência: O código completo do projeto pode ser consultado em [email protected], incluindo build_release.py, setup.iss e todas as configurações de empacotamento.

Visão geral: O pipeline de quatro etapas

Antes de começar, vamos ver toda a cadeia:

  • PyInstaller: .py.exe
  • Inno Setup: .exe → Instalador
  • MSIX Packaging Tool: Instalador → .msix
  • Microsoft Store: Publicação

Por que tão complicado? Porque a Microsoft Store precisa de um pacote no formato MSIX, e o MSIX Packaging Tool funciona «convertendo» um instalador tradicional que já instala e funciona corretamente — ele monitora o processo de instalação, captura todas as gravações de arquivos, alterações no registro e criação de atalhos, e depois gera automaticamente um MSIX. Por isso você precisa primeiro de um instalador tradicional limpo e completo.

Em outras palavras: PyInstaller cuida de «funcionar», Inno Setup cuida de «instalar», e o MSIX Packaging Tool cuida de «poder ser publicado na Store».

Vamos passo a passo.

Passo 1: PyInstaller — Transformar Python em EXE

1.1 Preparar seu projeto

Antes de começar, certifique-se de que seu projeto Python tem uma estrutura clara e um ponto de entrada bem definido. Usando o RDP Heartbeat como exemplo:

prune-rdp-heartbeat/
├── main.py              # Script de entrada
├── heartbeat_window.py  # Lógica da janela principal
├── win_utils.py         # Wrappers da API Win32
├── tray_icon.py         # Bandeja do sistema
├── settings_dialog.py   # Painel de configurações
├── about_dialog.py      # Diálogo Sobre
├── config_manager.py    # Gerenciamento de configuração
├── i18n.py              # Internacionalização
├── startup.py           # Inicialização automática
├── logger.py            # Registro de logs
├── version.py           # Número da versão
├── icon.ico             # Ícone do aplicativo
├── icon.png             # Ícone fonte (para gerar recursos MSIX)
├── requirements.txt     # Dependências
└── packaging/           # Recursos MSIX (usados posteriormente)

Dependências em requirements.txt:

pystray
Pillow
pywin32
customtkinter
packaging

1.2 Lidar com as «dependências ocultas» do PyInstaller

O PyInstaller detecta dependências por análise estática, mas algumas bibliotecas (especialmente pystray, PIL) não são detectadas e precisam ser declaradas manualmente:

python
# Configuração principal no build_release.py
cmd = [
    sys.executable, "-m", "PyInstaller",
    "--noconsole",           # Sem janela de console
    "--onefile",             # Empacotar em um único exe
    "--name=RDPHeartbeat",
    "--clean",
    "--icon=icon.ico",
    "--add-data=icon.ico;.", # Windows usa ponto e vírgula, Linux/macOS usa dois pontos
    "--hidden-import=PIL._tkinter_finder",
    "--hidden-import=pystray",
    "main.py"
]

Além disso, os arquivos de recursos (como ícones) são extraídos para um diretório temporário após o empacotamento, então você precisa de resource_path() para compatibilidade:

python
# Abordagem no tray_icon.py
def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS   # Diretório temporário do PyInstaller
    except Exception:
        base_path = os.path.abspath(".")  # Modo de desenvolvimento: diretório atual
    return os.path.join(base_path, relative_path)

Qualquer recurso que precise ser lido do sistema de arquivos (ícones, fontes, modelos de configuração, etc.) deve passar por esta função.

1.3 Script de build com um clique

Encapsule o comando PyInstaller em build_release.py:

python
# Primeiro ler version.py para obter o número da versão
from version import APP_VERSION

def run_build():
    # 0. Limpar artefatos do build anterior
    if os.path.exists("build"): shutil.rmtree("build")
    if os.path.exists("dist"):  shutil.rmtree("dist")

    # 1. Executar PyInstaller
    subprocess.check_call([...])

    # 2. Verificar o resultado
    exe_path = os.path.join("dist", "RDPHeartbeat.exe")
    assert os.path.exists(exe_path), "Build failed!"

Execute python build_release.py. Se tudo correr bem, você obterá RDPHeartbeat.exe em dist/.

Você pode clicar duas vezes para verificar se funciona corretamente.

Passo 2: Inno Setup — Transformar o EXE em um instalador adequado

O MSIX Packaging Tool precisa de um instalador como fonte de conversão. No ecossistema Windows, o Inno Setup é uma ferramenta gratuita, madura e baseada em scripts para criação de instaladores.

2.1 Instalar o Inno Setup

Baixe e instale em jrsoftware.org. Recomenda-se instalar também o Inno Script Studio (editor visual).

2.2 Escrever o script de instalação

O arquivo principal setup.iss:

ini
#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 único por aplicativo
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName}             ; Padrão para Program Files
ArchitecturesAllowed=x64compatible                ; Sistemas de 64 bits
ArchitecturesInstallIn64BitMode=x64compatible
DisableProgramGroupPage=yes                       ; Pular página «Selecionar grupo de programas»
OutputBaseFilename=RDPHeartbeat_Setup             ; Nome do arquivo de saída
SolidCompression=yes
WizardStyle=modern                                ; Estilo de assistente moderno
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

Alguns pontos importantes:

  • AppId deve ser único: é a base para o Windows identificar o aplicativo. Evite conflitos com outros softwares. O IDE do Inno Setup pode gerar um GUID com um clique.
  • Não precisa escrever no registro: a conversão MSIX cuida automaticamente das gravações no registro durante a instalação, mas este aplicativo não precisa delas de qualquer forma.

2.3 Sincronização automática do número da versão

Seu número de versão pode estar definido no código Python (version.py), e há também uma cópia no setup.iss. A sincronização manual sooner or later causará erros. Adicione um patch automático no build_release.py:

python
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)

Agora, ao executar python build_release.py, a versão mais recente será escrita automaticamente no setup.iss e depois o PyInstaller será executado.

2.4 Compilar o instalador

Abra o IDE do Inno Setup, carregue setup.iss e clique em Compile. O resultado é RDPHeartbeat_Setup.exe.

Verificação: Execute o instalador em uma VM limpa ou outro computador e confirme:

  • Instala corretamente
  • O programa inicia
  • Não há resíduos após a desinstalação (o desinstalador do Inno Setup está em {app}\unins000.exe, o MSIX o incluirá no pacote, sem problemas)

Passo 3: MSIX Packaging Tool — Do instalador ao formato Store

Se você planeja publicar na Microsoft Store, é recomendável registrar-se primeiro no Partner Center e reservar o nome do aplicativo (veja Passo 4), pois o Package Name e o Publisher preenchidos no MPT precisam corresponder às informações reservadas na Store. Se você está apenas testando, pode pular o registro e usar qualquer nome.

3.1 Preparar o ambiente

Você precisará de:

  • MSIX Packaging Tool (Documentação oficial)
  • Um ambiente limpo (recomenda-se usar uma VM ou um computador separado, pois o MPT monitora todo o processo de instalação — outros programas no seu sistema podem ser capturados como ruído)
  • Certificado de assinatura: para testes, você pode usar um certificado autoassinado. Execute no PowerShell (administrador):
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}")

Exportar o certificado:

powershell
$password = ConvertTo-SecureString -String "YourPassword" -Force -AsPlainText
Export-PfxCertificate -Cert "Cert:\CurrentUser\My\<Thumbprint>" -FilePath "C:\cert.pfx" -Password $password

Ao publicar oficialmente, a Microsoft Store reassinará com seu próprio certificado, então você não precisa comprar um certificado de assinatura de código. Mas se quiser distribuir fora da Store (por exemplo, oferecer download de MSIX no seu próprio site), precisará comprar um certificado de assinatura de código adequado.

3.2 Executar o MSIX Packaging Tool

  1. Abra o MPT, selecione "Application package""Create a new package".
  2. No passo "Select environment", mantenha os padrões e clique em Next.
  3. Passo chave: O MPT pedirá para selecionar o caminho do instalador. Escolha o RDPHeartbeat_Setup.exe que você acabou de gerar.
  4. O MPT começa a monitorar o sistema e inicia o instalador. Complete a instalação normalmente — se o instalador marcou "Launch RDP Heartbeat" no final, não tem problema.
  5. Após a conclusão da instalação, clique em "Next" — o MPT para de monitorar.
  6. O MPT listará todos os processos detectados. Desmarque os que não pertencem ao seu aplicativo (processos do sistema, atualizações do antivírus, etc.). Normalmente, mantenha apenas RDPHeartbeat.exe, unins000.exe, etc.
  7. Preencha as informações do aplicativo:
    • Package name: Para a Store, use o nome atribuído ao reservar o aplicativo no Partner Center (ex.: PruneLab.RDPHeartbeat). Para testes locais, você pode usar qualquer nome — formato recomendado: YourName.YourApp.
    • Package display name: O nome de exibição do aplicativo, ex.: RDP Heartbeat.
    • Publisher display name: Nome do editor, ex.: Prune Lab.
    • Publisher: Para a Store, use o Subject do certificado Publisher da sua conta Partner Center (ex.: CN=21C32622-53AF-45A6-8AB1-B35BCD475CAD). Para testes locais, use o Subject do seu certificado autoassinado (ex.: CN=YourName).
    • Version: Extraído automaticamente do instalador.
  8. Especifique o diretório de saída e gere o pacote MSIX.

3.3 Testar o pacote MSIX

Após gerar o arquivo .msix, não edite o manifest ainda. Clique duas vezes para instalar e verifique se funciona corretamente. Se estiver usando um certificado autoassinado, você precisa importá-lo primeiro para o repositório «Pessoas Confiáveis» do sistema (veja o comando de exportação na seção anterior, use Import-PfxCertificate).

Passo 4: Enviar para a Microsoft Store

4.1 Registro e reserva de nome

  1. Registre-se para uma conta de desenvolvedor no Microsoft Partner Center.
  2. No Partner Center, reserve o nome do aplicativo (Products → New Product → insira o nome). Após a reserva, você obterá o Package Name e as informações de Publisher, que devem corresponder ao AppxManifest.xml do seu pacote MSIX.

4.2 Processo de envio

  1. Vá para seu aplicativo → SubmissionsNew submission.
  2. Preencha os campos:
    • Packages: Carregue o arquivo .msix
    • Description: Descrição do aplicativo (suporta vários idiomas, recomenda-se pelo menos inglês e chinês)
    • Screenshots: Pelo menos uma captura de tela 1366×768
    • Store listing: Ícones, imagens promocionais, lista de funcionalidades
  3. Envie para revisão. A primeira revisão geralmente leva de 1 a 3 dias úteis.

Conclusão: Vale a pena?

Se você espera ganhar muito dinheiro com uma ferramenta Python, a resposta é «provavelmente não». Reescrever com WinUI 3 / .NET daria uma experiência de empacotamento muito melhor.

Mas se você é como eu — já tem uma ferramenta escrita em Python que usa regularmente e quer compartilhá-la com mais pessoas — então este processo, embora trabalhoso, pelo menos funciona.

Retrospectiva do pipeline:

EtapaFerramentaResultado
.py → .exePyInstallerUm único exe
.exe → InstaladorInno SetupSetup.exe
Instalador → MSIXMSIX Packaging Tool.msix
EnvioPartner CenterPublicação na Store

Espero que este artigo ajude a evitar alguns desvios. Se você também levou uma ferramenta Python para a Store, sinta-se à vontade para compartilhar sua experiência no GitHub do RDP Heartbeat.