Electron 앱을 Microsoft Store에 출시하는 방법: MSIX 패키징부터 스토어 제출까지
Electron 앱을 Microsoft Store에 출시하는 방법: MSIX 패키징부터 스토어 제출까지
사실 Electron은 그저 평범한 Win32 데스크톱 앱일 뿐입니다. 하지만 Microsoft Store는 MSIX만 인식합니다. 이 글에서는 HagiCode Desktop에서 실제로 사용했던 빌드 설정을 통해 “개발자 계정 등록 → MSIX 패키징 → 스토어 제출”까지의 전체 과정을 상세하게 설명하고, 우리가 겪었던 문제들도 함께 공유해 드릴게요 —毕竟坑踩过了,也就成了故事。
배경
Electron 앱을 Windows 사용자에게 배포해야 합니다. 기존에 사용하던 NSIS 설치 패키지, 포터블 버전 외에도 Microsoft Store에 앱을 게시하기를 원합니다. 현실적인 이유는 다음과 같습니다:
- 신뢰할 수 있는 배포 채널: 스토어의 앱은 서명되고 검증된 앱이므로, 사용자가 설치할 때 SmartScreen에 차단되지 않고 “알 수 없는 발행자”라는 차가운 메시지를 마주하지 않아도 됩니다.
- 자동 업데이트 및 상업화: 업데이트는 스토어가 대신 관리하고, 구독 및 영구 라이선스도 직접 연동할 수 있습니다.
- Windows 10/11 내장 진입점 커버: winget, 스토어 검색, 시작 메뉴 추천 등 — 이러한 진입점들은 신규 사용자 확보에 실질적으로 유용합니다.
하지만 Electron은 결국 UWP가 아닙니다. Microsoft Store에 출시하려면 핵심은 한 가지 — Electron 산출물을 Microsoft Store가 인식하는 MSIX 패키지로 다시 패키징하고, 등록 및 제출 절차를 차근차근 진행해야 합니다. 말은 쉽지만 실제로 해보면 문제가 꽤 많습니다. 이러한 문제들을 해결하기 위해 우리는 전체 과정을 꼼꼼하게 파악하는 데 시간을 들였고, 아래에서 각 단계를 자세하게 설명해 드리겠습니다.
HagiCode 소개
이 글에서 설명하는 방법은 HagiCode 프로젝트의 실무 경험에서 비롯되었습니다. HagiCode Desktop은 Electron 기반 데스크톱 애플리케이션으로, 공식 웹사이트, GitHub Release, Microsoft Store 세 가지 채널을 통해 사용자에게 배포됩니다. 스토어 채널을 어떻게 구축했는지가 바로 이 글의 주제입니다. HagiCode에 대한 더 많은 정보는 글 마지막에 있으니, 관심이 있다면 아래로 스크롤해서 확인해 보세요.
분석: 출시 전에 명확히 해야 할 네 가지 질문
Microsoft Store에 출시하는 것은 기술적으로 네 가지 핵심 판단이 필요합니다. 명확히 해두면 나중에 반복해서 수정할 필요가 없습니다 —毕竟谁也不想返工呢。
1. Microsoft Store는 MSIX/AppX만 수용하고, 기존 NSIS/EXE는 수용하지 않습니다
Microsoft Store의 데스크톱 앱 지원은 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, },},핵심 입력은 사실 두 가지입니다: appManifest(즉 AppxManifest.xml, 패키지 ID 및 기능 정의)과 packageAssets(스토어 아이콘 자산). 이 두 가지가 틀리면 아무리 잘 만들어도 소용이 없습니다.
2. 패키지 ID는 반드시 파트너 센터에서 미리 예약해야 합니다
MSIX 패키지의 Identity 필드(Name, Publisher)는 아무렇게나 채울 수 있는 것이 아니라, 파트너 센터에서 예약한 앱 ID와 정확히 일치해야 합니다. 한 문자라도 다르면 거절됩니다. 우리가 예약한 ID는 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 문자열은 개발자 계정 등록 후 Microsoft가 발급한 인증서 주제에서 오는 것으로, 문자 단위로 일치해야 합니다. 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: 스토어에서 앱 ID 예약
파트너 센터에서 새 앱을 만들고, 보유하고자 하는 이름을 입력하세요. 시스템이 identityName을 할당하고, 이를 자신의 Publisher와 결합하면 완전한 패키지 ID가 생성됩니다. 이 ID를 그대로 로컬 설정에 복사하세요:
{ "packageIdentity": { "displayName": "Hagicode", "publisherDisplayName": "newbe36524", "publisher": "CN=8B6C8A94-AAE5-4C8B-9202-A29EA42B042F", "identityName": "newbe36524.Hagicode" }}단계 3: 스토어 아이콘 자산 준비
Microsoft Store는 고정 크기의 PNG 세트를 요구합니다: StoreLogo.png, Square44x44Logo.png, Square150x150Logo.png, Wide310x150Logo.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 생성
매니페스트에는 패키지 ID, 기능, 비주얼 자산, 진입점 실행 파일을 포함해야 합니다. 우리는 오버라이드 설정(forge.store-config.json)을 사용하여 prepare-msix.js가 매니페스트를 생성하도록 하고, ID가 스토어와 일치하는지 확인합니다. 매니페스트의 핵심 부분은 대략 다음과 같습니다:
<!-- 패키지 ID: 파트너 센터와 일치해야 함 --><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: 서명(스토어 제출 시에는 서명하지 않아도 됨)
이 단계는 쉽게 간과될 수 있습니다 — 스토어에 제출하는 패키지는 Microsoft가 자체 인증서로 다시 서명하므로, “정식 제출” 외의 개발 자체 테스트 단계에서는 서명하지 않아도 됩니다. 다만 로컬에 설치하여 테스트하려면 신뢰된 인증서로 서명해야 하며, 그렇지 않으면 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, };}“자체 테스트 서명”과 “서명 없이 제출” 두 경로를 분리하는 것은 매우 중요한 실무 경험입니다.
단계 7: Microsoft Store CLI 자격 증명 구성
Azure 포털에서 Azure AD 애플리케이션을 만들고, Partner Center에 액세스할 수 있는 권한을 부여한 다음, 다음 자격 증명을 얻습니다:
AZURE_AD_APPLICATION_CLIENT_IDAZURE_AD_APPLICATION_SECRETAZURE_AD_TENANT_IDSELLER_ID(파트너 센터의 판매자 ID)MICROSOFT_STORE_PRODUCT_ID(예약된 앱의 제품 ID)
이 단계는 약간 복잡하지만, Azure 포털과 Partner Center 문서에 자세히 설명되어 있으니 그대로 따르면 됩니다.
단계 8: 스토어에 제출
Windows 환경에서 Microsoft Store CLI를 사용하여 제출:
# 자격 증명 구성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": { /* 스토어 예약 ID */ }, "msix": { "minVersion": "10.0.17763.0", "maxVersionTested": "10.0.19045.0", "capabilities": ["runFullTrust", "internetClient", "internetClientServer", "privateNetworkClientsServer"] }}이렇게 하면 스토어 버전과 일반 배포 버전이 서로 오염되지 않습니다. HagiCode Desktop은 세 가지 배포 채널을 동시에 유지하며, 설정 분리는 안정적인 반복을 위한 전제 조건입니다.
버전 번호는 네 단계여야 합니다
MSIX의 버전 번호는 Major.Minor.Build.Revision 네 단계(예: 1.2.3.0)여야 합니다. 하지만 Electron의 package.json은 보통 세 단계만 작성합니다. buildVersion 필드는 마지막 단계를 보완하는 데 사용됩니다 — 스토어 제출 시 버전 번호는 증가해야 하며, 네 번째 단계는 동일한 시멘틱 버전에서의 여러 제출을 구분하는 데 매우 편리합니다. 이 부분은 겪어본 사람만 이해합니다. 겪지 않은 사람은迟早也会踩。
다국어 선언
스토어는 다국어 목록을 지원하며, 매니페스트에서는 <Resource Language="..." /> 라인으로 대응됩니다. 우리는 열 가지 언어를 선언했으며, 스토어는 각 언어마다 설명을 작성하도록 요구합니다(먼저 기계 번역으로 심사를 통과하고, 점진적으로 현지화할 수 있습니다). prepare-msix.js에서의 해당 렌더링 로직은 다음과 같습니다:
// 언어 목록을 MSIX 매니페스트의 Resource 태그로 렌더링function renderResourceTags(languages) { return languages .map((language) => ` <Resource Language="${escapeXml(language)}" />`) .join('\n');}일반적인 문제(중요)
다음 문제들은 HagiCode Desktop에서 거의 모든 것을 겪었습니다:
- Publisher 불일치: Partner Center에서 publisher 문자열을 복사할 때 실수로 공백을 잃거나 대소문자를 틀리면 제출이 즉시 거절됩니다. 구성 파일에 직접 작성하고 직접 입력하지 마세요.
runFullTrust누락: 앱 시작 후 파일 시스템에 접근할 수 없고 하위 프로세스를 실행할 수 없으며, 다양한 이상한 크래시로 나타나며, 조사하기가 매우 번거롭습니다.- 아이콘 크기 불완전: MakeAppx는 검증하지 않지만 스토어 심사는 거절합니다.
prepare-msix.js미리 확인은 효과적인 방어입니다. - 버전 번호가 증가하지 않음: 스토어는 동일하거나 낮은 버전 번호를 거부하므로 CI 파이프라인은 매번 빌드할 때마다 증가시켜야 합니다.
- 비 Windows 환경에서 maker-msix 실행:
MakeAppx를 찾을 수 없으므로 반드시windows-latestrunner를 사용해야 합니다. - 서명 혼란: 자체 테스트는 자체 서명 인증서를 사용하고, 스토어 제출은 서명 없이 Microsoft 재서명을 사용하며, 이 두 경로를 분리하고 제출 패키지에 자체 서명 인증서를 포함하지 마세요.
자동화 제안
처음에는 전체 프로세스를 수동으로 완료하고 각 단계를 명확히 파악한 후에는 GitHub Actions를 통한 자동화를 강력히 권장합니다. 우리는 마지막에 버전 파싱, MSIX 빌드, GitHub Release 배포, 스토어 배포를 하나의 파이프라인으로 연결하고, 4시간마다 새 버전을 확인합니다. 이 부분의 세부 사항은 우리의 다른 글《Windows 앱 자동 Microsoft Store 출시 자동화 실무》에서 완전히 분석합니다.
단지 앱을 스토어에 먼저 올리고, 상업화(구독 / 영구 라이선스) 후에 연결하려면, 우리의《Electron 데스크톱 앱 Microsoft Store 구독 및 영구 라이선스 통합》 글을 참고할 수도 있습니다. 그 글은 스토어 출시 후 상업화 기능 통합에 대해 설명합니다.
참고 자료
- Microsoft Store CLI 문서
- electron-forge maker-msix
- MSIX 문서
- HagiCode 공식 웹사이트
- HagiCode-org/site GitHub 저장소
요약
“Electron 앱을 Microsoft Store에 출시하는 방법: MSIX 패키징부터 스토어 제출까지”를 중심으로, 더 안정적인 추진 방법은 핵심 설정, 의존 경계 및 구현 경로를 먼저 점진적으로 실행한 다음, 최적화 세부 사항을 보완하는 것입니다.
목표, 단계 및 검수점이 명확해지면, 이러한 방안은 일반적으로 더 원활하게 실제 배포 단계로 들어갈 수 있습니다.
开始使用 HagiCode
一次安装,几分钟上手
HagiCode for Windows 在 Microsoft Store 免费提供。打开商店即可安装并保持更新;也可以先对比各版本与定价,再决定从哪个渠道开始。