Cómo publicar aplicaciones de Electron en Microsoft Store: desde el empaquetado MSIX hasta el envío a la tienda
Cómo publicar aplicaciones de Electron en Microsoft Store: desde el empaquetado MSIX hasta el envío a la tienda
Al final del día, Electron no es más que una aplicación de escritorio Win32 ordinaria, pero Microsoft Store solo acepta MSIX. Este artículo, basado en la configuración de compilación que hemos implementado con éxito en HagiCode Desktop, te muestra paso a paso el proceso completo de “registrar cuenta de desarrollador → crear paquete MSIX → enviar a la tienda”, y también compartimos los problemas que encontramos en el camino — después de todo, los problemas que hemos superado se convierten en historias.
Antecedentes
Tenemos una aplicación de Electron que queremos distribuir a usuarios finales en Windows. Además de los instaladores NSIS y las versiones portátiles que siempre hemos utilizado, también esperamos que aparezca en Microsoft Store. Las razones son bastante prácticas:
- Canal de distribución confiable: Las aplicaciones de la tienda están firmadas y verificadas, por lo que los usuarios no serán bloqueados por SmartScreen durante la instalación y no tendrán que enfrentarse a ese frío mensaje de “editor desconocido”.
- Actualizaciones automáticas y monetización: La tienda se encarga de las actualizaciones; las suscripciones y licencias permanentes también se pueden integrar directamente.
- Cobertura de los puntos de entrada integrados de Windows 10/11: winget, búsqueda en la tienda, recomendaciones del menú de inicio… estos puntos de entrada son realmente útiles para atraer nuevos usuarios.
Sin embargo, Electron no es UWP. Para publicar en Microsoft Store, lo esencial es reempaquetar el resultado de Electron en un paquete MSIX que Microsoft Store reconozca, y luego completar los procesos de registro y envío. Suena fácil, pero cuando te pones a hacerlo, hay muchos obstáculos. Para superar estos obstáculos, dedicamos mucho tiempo a entender todo el proceso, así que vamos a desglosar cada paso a continuación.
Sobre HagiCode
La solución descrita en este artículo proviene de nuestra práctica en el proyecto HagiCode. HagiCode Desktop es una aplicación de escritorio basada en Electron que se distribuye a los usuarios a través de tres canales: el sitio web oficial, GitHub Release y Microsoft Store. Cómo conectamos el canal de la tienda es exactamente lo que explica este artículo. Al final hay más información sobre HagiCode; si te interesa, puedes ir al final para verla.
Análisis: cuatro preguntas que debes considerar antes de publicar
Para publicar en Microsoft Store, hay cuatro decisiones clave en la cadena técnica. Si las aclaras desde el principio, no tendrás que repetir el trabajo — después de todo, nadie quiere repetir el trabajo.
1. Microsoft Store solo acepta MSIX / AppX, no NSIS/EXE tradicionales
El soporte de Microsoft Store para aplicaciones de escritorio (Desktop Bridge) se basa en el formato MSIX. Los instaladores NSIS tradicionales no se pueden enviar directamente; primero deben reempaquetarse en MSIX con MakeAppx. Afortunadamente, Electron Forge proporciona un maker @electron-forge/maker-msix que puede generar MSIX directamente durante la fase de empaquetado, evitando todo el trabajo de tener que inferir el empaquetado desde el directorio de instalación.
En nuestro proyecto tenemos este maker:
{ name: '@electron-forge/maker-msix', platforms: ['win32'], config: { appManifest: msixManifestPath, packageAssets: msixAssetsPath, logLevel: 'warn', ...(windowsKitPath ? { windowsKitPath } : {}), ...(windowsKitVersion ? { windowsKitVersion } : {}), ...msixSigningConfig, },},Las entradas clave son solo dos: appManifest (es decir, AppxManifest.xml, que define la identidad del paquete y las capacidades) y packageAssets (activos de iconos de la tienda). Si estos dos están incorrectos, todo lo demás que hagas será en vano.
2. La identidad del paquete debe reservarse en el Centro de socios con antelación
El campo Identity del paquete MSIX (Name, Publisher) no se puede llenar arbitrariamente; debe coincidir exactamente con la identidad de la aplicación reservada en el Centro de socios. Incluso un carácter diferente hará que sea rechazado. La identidad que reservamos está registrada en 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"] }}La cadena publisher proviene del tema del certificado emitido por Microsoft después de registrar la cuenta de desarrollador y debe coincidir carácter por carácter. identityName es el prefijo del nombre del paquete que reservaste. Esta cadena debe copiarse tal cual desde el Centro de socios, nunca la escribas manualmente — volveremos a hablar de esto en “problemas comunes” más adelante.
3. Las aplicaciones de escritorio deben declarar la capacidad runFullTrust
Las aplicaciones de Electron necesitan acceso completo al sistema de archivos, iniciar procesos secundarios y ejecutar el runtime de Node; todo esto solo se puede lograr en el modo de “confianza completa”. Por lo tanto, en el manifiesto MSIX, debes declarar honestamente la capacidad runFullTrust, de lo contrario, la aplicación será bloqueada por el sandbox al iniciar, lo que se manifestará como varios bloqueos inexplicables. Nuestra configuración se ve así:
{ "msix": { "minVersion": "10.0.17763.0", "maxVersionTested": "10.0.19045.0", "capabilities": [ "runFullTrust", "internetClient", "internetClientServer", "privateNetworkClientsServer" ] }}runFullTrust es el estándar para la publicación de aplicaciones de escritorio. minVersion está configurado en 17763 (es decir, Windows 10 1809), porque a partir de esta versión, MSIX admite de manera estable las aplicaciones Win32 de escritorio; si se configura más bajo, los usuarios no podrán instalar; si se configura más alto, no cubrirá esas máquinas más antiguas.
4. El envío a la tienda requiere entorno de Windows + Microsoft Store CLI
El empaquetado se puede hacer en CI multiplataforma, pero el envío a la tienda (msstore publish) no; debe ejecutarse en un entorno de Windows con Microsoft Store CLI, y también configurar las credenciales de la aplicación Azure AD. Es por eso que el trabajo publish_store en la canalización automatizada debe ejecutarse en un runner windows-latest. Esta es una restricción dura que no se puede evitar, a diferencia del empaquetado que se puede poner en un contenedor de Linux.
Solución: proceso de ocho pasos para la publicación completa
Conectando el análisis anterior, para publicar una aplicación de Electron en Microsoft Store, los pasos completos son aproximadamente estos.
Paso 1: registrar cuenta de desarrollador
Primero ve a Partner Center para registrar una cuenta de desarrollador (individual o corporativa), y paga esa tarifa única. Después de activar la cuenta, obtendrás una cadena de tema de certificado de publicador, que se ve así: CN=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Esta es la única fuente del campo publisher más adelante.
Paso 2: reservar identidad de la aplicación en la tienda
Crea una nueva aplicación en el Centro de socios, llena el nombre que deseas conservar. El sistema te asignará identityName, y al combinarlo con tu propio Publisher, se forma la identidad completa del paquete. Copia esta identidad tal cual a tu configuración local:
{ "packageIdentity": { "displayName": "Hagicode", "publisherDisplayName": "newbe36524", "publisher": "CN=8B6C8A94-AAE5-4C8B-9202-A29EA42B042F", "identityName": "newbe36524.Hagicode" }}Paso 3: preparar activos de iconos de la tienda
Microsoft Store requiere un conjunto de PNG de tamaños fijos: StoreLogo.png, Square44x44Logo.png, Square150x150Logo.png, Wide310x150Logo.png, etc. Nuestro script prepare-msix.js, antes del empaquetado, verifica si todos estos activos están presentes:
// Verificar los activos de iconos requeridos por la tienda, falta uno y no funcionaconst 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}`); }}¿Por qué hacemos esto? Porque si falta un tamaño, MakeAppx no te dirá exactamente qué está mal durante el empaquetado, y solo será rechazado durante la revisión de la tienda — en ese momento, ya habrás esperado varios días. Verificar con anticipación es una defensa muy efectiva.
Paso 4: generar AppxManifest.xml
El manifiesto debe contener identidad del paquete, capacidades, activos visibles y ejecutable de entrada. Usamos una configuración de sobrescritura (forge.store-config.json) para impulsar prepare-msix.js a generar el manifiesto, asegurando que la identidad coincida con la tienda. Las secciones clave del manifiesto son aproximadamente así:
<!-- Identidad del paquete: debe coincidir con el Centro de socios --><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>
<!-- Declaración de capacidades: runFullTrust es clave para aplicaciones de escritorio --><Capabilities> <rescap:Capability Name="runFullTrust" /> <Capability Name="internetClientServer" /></Capabilities>Observa esa línea EntryPoint="Windows.FullTrustApplication", esta es la marca clave para aplicaciones de escritorio; combinada con la capacidad runFullTrust, puede ejecutarse con permisos completos. Sin ella, la aplicación solo puede quedarse obedientemente en el sandbox, muy restringida.
Paso 5: empaquetar con maker-msix
El comando de compilación está escrito en package.json:
{ "scripts": { "build:win:store": "npm run generate:store-bindings && node scripts/build-store-package.js" }}Al final invoca Electron Forge, pasando forge.store-config.json como configuración de sobrescritura, maker-msix llamará a MakeAppx del Windows SDK y generará el archivo .msix. Aquí hay una restricción dura: el empaquetado debe hacerse en Windows (o en un contenedor con Windows SDK), ya que depende de MakeAppx, esto no se puede evitar.
Paso 6: firmar (no es necesario para el envío a la tienda)
Este paso se pasa por alto fácilmente — el paquete enviado a la tienda será firmado nuevamente por Microsoft con su propio certificado, por lo que en la etapa de desarrollo y autoprueba, se puede omitir la firma. Solo si quieres instalarlo localmente para probar, debes firmarlo con un certificado de confianza, de lo contrario Windows rechazará la instalación. Nuestro resolveMsixSigningConfig devuelve un objeto vacío cuando no hay materiales de firma configurados, permitiendo que el proceso continúe:
// Sin materiales de firma no firmar, dejar que la tienda firme uniformementefunction resolveMsixSigningConfig() { if (!process.env.MSIX_CERT_FILE) return {}; return { signMethod: 'signtool', certFilePath: process.env.MSIX_CERT_FILE, certPassword: process.env.MSIX_CERT_PASSWORD, };}Separar las rutas de “firma para autoprueba” y “envío sin firma” es una práctica muy clave.
Paso 7: configurar credenciales de Microsoft Store CLI
Ve al portal de Azure para crear una aplicación Azure AD, otorgarle permisos para acceder al Centro de socios, y luego obtener este conjunto de credenciales:
AZURE_AD_APPLICATION_CLIENT_IDAZURE_AD_APPLICATION_SECRETAZURE_AD_TENANT_IDSELLER_ID(ID del vendedor del Centro de socios)MICROSOFT_STORE_PRODUCT_ID(ID del producto de la aplicación reservada)
Este paso es un poco complicado, pero la documentación del portal de Azure y el Centro de socios lo explica muy detalladamente, solo sigue las instrucciones.
Paso 8: enviar a la tienda
En un entorno de Windows, envía con Microsoft Store CLI:
# Configurar credencialesmsstore reconfigure --tenantId $env:AZURE_AD_TENANT_ID ` --clientId $env:AZURE_AD_APPLICATION_CLIENT_ID ` --clientSecret $env:AZURE_AD_APPLICATION_SECRET ` --sellerId $env:SELLER_ID
# Enviar paquete MSIX al producto reservadomsstore publish "$packagePath" -id $env:MICROSOFT_STORE_PRODUCT_IDDespués de enviar, debes regresar al Centro de socios para completar los detalles de la tienda (descripción, capturas de pantalla, precio, clasificación), y finalmente hacer clic en enviar para revisión. La revisión generalmente toma 1-3 días laborales, la primera vez siempre es un poco más larga.
Práctica: consolidar la configuración y la experiencia de superar problemas
Después de completar todo el proceso, estas prácticas pueden ayudarte a evitar desvíos — después de todo, después de muchos desvíos, ya no parecen desvíos, simplemente algunas cosas se pueden ahorrar.
Guardar archivos de configuración por separado
Separar la “configuración de compilación general” y la “configuración específica de la tienda” es clave. Nuestro enfoque es: forge.config.js ejecuta compilaciones diarias (NSIS, portable, macOS dmg), forge.store-config.json solo se usa durante compilaciones de tienda, heredando y sobrescribiendo a través de extends:
{ "extends": "forge.config.js", "buildVersion": "0.1.0.0", "packageIdentity": { /* identidad reservada por la tienda */ }, "msix": { "minVersion": "10.0.17763.0", "maxVersionTested": "10.0.19045.0", "capabilities": ["runFullTrust", "internetClient", "internetClientServer", "privateNetworkClientsServer"] }}De esta manera, la versión de la tienda y la versión de distribución no se contaminan entre sí. HagiCode Desktop mantiene simultáneamente tres canales de distribución, la separación de configuraciones es el requisito previo para que podamos iterar de manera estable.
El número de versión debe ser de cuatro partes
El número de versión de MSIX debe ser de cuatro partes Major.Minor.Build.Revision (por ejemplo, 1.2.3.0), pero package.json de Electron generalmente solo escribe tres partes. El campo buildVersion se usa para completar la última parte — durante el envío a la tienda, el número de versión debe incrementarse, la cuarta parte es muy conveniente para distinguir múltiples envíos bajo la misma versión semántica. Quienes han tenido este problema lo entienden; quienes no lo han tenido, tarde o temprano lo tendrán.
Declaración de múltiples idiomas
La tienda admite listings en varios idiomas, que corresponden a las etiquetas <Resource Language="..." /> en el manifiesto. Declaramos diez idiomas, y la tienda requerirá que cada idioma tenga una descripción (se puede usar traducción automática para aprobar, luego localizar gradualmente). La lógica de renderizado correspondiente en prepare-msix.js es así:
// Renderizar la lista de idiomas como etiquetas Resource en el manifiesto MSIXfunction renderResourceTags(languages) { return languages .map((language) => ` <Resource Language="${escapeXml(language)}" />`) .join('\n');}Problemas comunes (prestar especial atención)
HagiCode Desktop casi ha pasado por todos estos problemas:
- Publisher no coincide: Al copiar la cadena publisher del Centro de socios, accidentalmente se pierde un espacio o se escribe mal mayúscula/minúscula, el envío es rechazado directamente. Se recomienda escribirlo directamente en el archivo de configuración, no escribirlo manualmente.
- Falta
runFullTrust: Después de iniciar la aplicación, no se puede acceder al sistema de archivos ni iniciar procesos secundarios, se manifiesta como varios bloqueos extraños, la investigación es muy difícil. - Tamaños de iconos incompletos: MakeAppx no verifica, pero la revisión de la tienda lo rechazará. La verificación anticipada en
prepare-msix.jses una defensa efectiva. - Número de versión no incrementado: La tienda rechaza recibir el mismo número de versión o uno inferior, la canalización CI debe garantizar bump en cada compilación.
- Ejecutar maker-msix en un entorno no Windows: No se encontrará
MakeAppx, debe usar el runnerwindows-latest. - Firma confusa: Para autoprueba usa certificado autofirmado, para envío a la tienda usa firma vacía para que Microsoft firme, estas dos rutas deben estar separadas, no metas el certificado autofirmado en el paquete de envío.
Sugerencias de automatización
Después de completar manualmente todo el proceso la primera vez y aclarar cada paso, se recomienda encarecidamente conectar con GitHub Actions para automatización. Al final conectamos el análisis de versión, construcción MSIX, publicación de GitHub Release y publicación de tienda en una canalización, verificando nuevas versiones cada 4 horas. Estos detalles se explican completamente en otro artículo “Práctica de automatización para la publicación automática de aplicaciones de Windows en Microsoft Store”.
Si solo quieres poner la aplicación en la tienda primero y luego conectar la monetización (suscripción / licencia permanente), también puedes ver nuestro artículo “Cómo integrar suscripciones y licencias permanentes de Microsoft Store en aplicaciones de escritorio de Electron”, ese artículo trata sobre la integración de capacidades de monetización después de la publicación en la tienda.
Referencias
- Documentación de Microsoft Store CLI
- electron-forge maker-msix
- Documentación de MSIX
- Sitio web oficial de HagiCode
- Repositorio GitHub HagiCode-org/site
Resumen
En torno a “Cómo publicar aplicaciones de Electron en Microsoft Store: desde el empaquetado MSIX hasta el envío a la tienda”, una forma más sólida de avanzar es primero ejecutar gradualmente las configuraciones clave, los límites de dependencia y la ruta de implementación, y luego completar los detalles de optimización.
Cuando los objetivos, pasos y puntos de verificación están claros, este tipo de solución generalmente puede entrar en la entrega real de manera más fluida.
开始使用 HagiCode
一次安装,几分钟上手
HagiCode for Windows 在 Microsoft Store 免费提供。打开商店即可安装并保持更新;也可以先对比各版本与定价,再决定从哪个渠道开始。