
写在前面
本文记录了把 Tydora(一款基于 Tauri v2 的桌面 Markdown 编辑器)发布到微软商店(Microsoft Store)的完整过程,包含 MSIX 打包、Partner Center 配置、GitHub Actions 自动发布的全流程,以及途中踩过的所有坑。
背景:为什么是 MSIX
Tydora 的默认分发方式是 NSIS(.exe)+ MSI(.msi)+ macOS/Linux 包,通过 GitHub Releases 发布。但微软商店只接受 MSIX 格式,且 Tauri CLI 2.11.2 在 Windows 平台的 --bundles 不支持 msix 目标(只有 msi/nsis)。
所以我们的思路是:
1️⃣ 用 tauri build --no-bundle 产出原始 release exe(前端已内嵌到二进制)
2️⃣ 自己写一份 AppxManifest.xml
3️⃣ 用 Windows SDK 的 MakeAppx.exe 把 exe + 清单 + 图标打包成 .msix
4️⃣ 上传到 Partner Center,由微软统一签名后上架
整个过程不依赖 Tauri 的 MSIX bundler,可控且能精确对齐商店身份。
全流程概览
整个上架过程分为 6 个主要步骤,环环相扣:
Step 1 → 注册账号:在 Partner Center 注册开发者账号,保留产品名,获取商店身份信息
Step 2 → 配置环境:在 .env 中填入 MSSTORE_* 参数(Name / Publisher / DisplayName)
Step 3 → MSIX 打包:执行 npm run tauri build:msix,生成商店模式的未签名 MSIX 包
Step 4 → 手动上传:将 MSIX 上传至 Partner Center,填写隐私策略、支持信息、渠道等。首个版本必须手动上传
Step 5 → 等待审核:微软认证审核,周期通常 1-3 个工作日,审核通过即正式上架
Step 6 → 自动化发布:配置 GitHub Actions Secrets,后续版本通过 CI 自动发布
第 1 步:Partner Center 注册与保留产品名
1.1 注册开发者账号
打开 storedeveloper.microsoft.com 用微软账号登录,选「个人开发者」。
💡 小提示:个人号几分钟过审,免费;公司号需 DUNS 或营业执照,2-5 工作日。
1.2 新建产品并保留名称
进入 Partner Center → Apps and games → New product。
🚨 重点注意:产品类型必须选「MSIX 或 PWA 应用」(MSIX or PWA app)。如果选了「EXE 或 MSI app」,上传 MSIX 时会被直接拒绝,且产品类型创建后无法更改,只能删掉重建。
输入产品名「Tydora」并保留(名字保留后 3 个月内必须发布,否则失效)。
1.3 拿到商店身份
保留成功后进入应用页面 → 顶部 Product identity(产品标识)页,你会看到 4 个关键信息:
| 字段 | 示例值 | 用途 |
|---|---|---|
| Package/Identity/Name | <你的Name>(形如 1234567890.Tydora) | MSIX 清单的 Identity Name |
| Package/Identity/Publisher | <你的Publisher>(形如 CN=XXXX-XXXX-...) | MSIX 清单的 Identity Publisher |
| PublisherDisplayName | <你的发布者显示名> | MSIX 清单的 Properties/PublisherDisplayName |
| Store product ID | <你的ProductID>(形如 9WZDNCRFXXXX) | 后续 CI 自动发布用 |
🚨 划重点:这三个值(Name / Publisher / PublisherDisplayName)必须和你 MSIX 清单里的值一字不差,否则 Partner Center 校验会打回。下面会讲怎么把这三个值注入清单。
第 2 步:MSIX 清单与打包脚本
2.1 AppxManifest.xml 模板
Tauri 不生成 MSIX 清单,我们自己写一份,放在 src-tauri/msix/AppxManifest.xml。
关键点:
xml <IdentityName="{{PACKAGE_IDENTITY_NAME}}"Publisher="{{PUBLISHER}}"Version="{{VERSION}}"ProcessorArchitecture="x64" /><Properties><DisplayName>Tydora</DisplayName><PublisherDisplayName>{{PUBLISHER_DISPLAY_NAME}}</PublisherDisplayName><Logo>Assets\StoreLogo.png</Logo><Description>A modern Markdown editor built with Tauri</Description></Properties>
三个 {{...}} 占位符由打包脚本在运行时替换为实际值。
🚨 踩过的大坑:<Properties> 下子元素顺序有 XML Schema 严格约束——必须是DisplayName → PublisherDisplayName → Logo → Description。如果 Description 写在 Logo 前面,MakeAppx 会报 C00CEE3B(app manifest XML must be valid),但错误信息是乱码(???),很难定位。错误提示 Line 28, Column 15,但真正的问题在 line 25 的元素顺序!
2.2 文件关联(可选)
如果想让应用接管 .md 文件,在 <Applications> 节点加 <Extensions>:
xml <Extensions><uap:ExtensionCategory="windows.fileTypeAssociation"><uap:FileTypeAssociationName="markdown"><uap:SupportedFileTypes><uap:FileType>.md</uap:FileType><uap:FileType>.markdown</uap:FileType><uap:FileType>.mdx</uap:FileType></uap:SupportedFileTypes></uap:FileTypeAssociation></uap:Extension></Extensions>
2.3 能力声明(Capabilities)
xml <Capabilities><rescap:CapabilityName="runFullTrust" /><CapabilityName="internetClient" /></Capabilities>
runFullTrust 是受限能力,提交时 Partner Center 会强制要求你解释用途(见第 4.3 节)。
2.4 打包脚本 build-msix.ps1
核心流程:
1️⃣ 判定模式:检查 MSSTORE_PACKAGE_IDENTITY_NAME 和 MSSTORE_PUBLISHER 是否同时存在
- 都存在 → 商店模式(不签名,产物给 Partner Center)
- 任一缺失 → 本地测试模式(自签名,本地可安装)
2️⃣ 读取 release exe:src-tauri/target/release/tydora.exe
3️⃣ 暂存目录:src-tauri/target/msix-staging/,把 exe + 图标 + 生成的 manifest 放进去
4️⃣ MakeAppx pack:打包成 src-tauri/target/msix/Tydora_<version>_x64.msix
5️⃣ 签名(仅本地模式或显式 -Sign):用 Sign-AppxPackage 创建自签名证书并签名
📌 版本号来源:从 VERSION 文件读取,转换为四段式 0.1.4.0(MSIX 要求 Major.Minor.Build.Revision 四段,空位补 0)。
2.5 接入 npm 脚本
scripts/run-tauri.mjs 拦截 build:msix 子命令,转发给 PowerShell 脚本:
javascript if (subCommand === 'build:msix') {const args = process.argv.slice(3).join(' ');spawnSync('pwsh', ['-File', 'scripts/build-msix.ps1', ...args], { stdio: 'inherit' });}
在 package.json 里注册:
json "scripts":{"tauri":"node scripts/run-tauri.mjs"}
这样就能用 npm run tauri build:msix 打包了。
第 3 步:本地打包
3.1 配置 .env
在项目根目录的 .env 里填入商店身份:
dotenv # 已有的 Tauri 签名密钥(用于 NSIS/MSI 自动更新签名,不是 MSIX 签名)TAURI_SIGNING_PRIVATE_KEY=...TAURI_SIGNING_PRIVATE_KEY_PASSWORD=...# 微软商店身份(用于 MSIX 打包)MSSTORE_PACKAGE_IDENTITY_NAME=<你的Name>MSSTORE_PUBLISHER=<你的Publisher>MSSTORE_PUBLISHER_DISPLAY_NAME=<你的发布者显示名>
🚨 踩过的第二个坑:.env 里的值不要加引号。Tydora 的 loadEnv 解析器只按第一个 = 分割并 trim 两边,不会剥引号。如果写成 MSSTORE_PACKAGE_IDENTITY_NAME="你的Name",引号会被当作值的一部分传给 MakeAppx,导致 Partner Center 校验 Identity Name 时报错——「无效的软件包标识名称: Tydora (应为: 你的Name)」,实际上是因为之前 .env 里写成了 = " 你的Name"(带前导空格和引号)。
3.2 执行打包
powershell # 完整打包(含 Rust 编译,首次约 5-10 分钟)npm run tauri build:msix# 跳过编译,仅重新打包(已有 release exe 时,秒级)npm run tauri build:msix ---SkipBuild# 跳过签名(商店模式默认就是不签名,加这个只是不显示签名警告)npm run tauri build:msix ---SkipBuild-NoSign
3.3 验证产物
打包成功后,控制台会输出:
Identity Name: <你的Name>Publisher: <你的Publisher>PublisherDisplayName: <你的发布者显示名>Mode: Store (unsigned)Package creation succeeded.✓ MSIX 已生成: D:\code\Tydora\src-tauri\target\msix\Tydora_0.1.4.0_x64.msix 大小: 6.09 MB💡 重要说明:本地双击这个未签名 MSIX 会显示「发布者: 未知」并报错 0x800B010A(证书不受信任),这是正常的——商店模式的包本来就不该本地安装,它只应该上传到 Partner Center,由微软用自己的证书统一签名后分发给最终用户。
如果想本地测试安装效果,可以用本地模式(注释掉 .env 里的 MSSTORE_* 三行)打一个自签名的包,本地安装不会报错。
第 4 步:上传到 Partner Center
4.1 开始新提交
进入 Tydora 应用页面 → Start a submission(开始新提交)。需要填的几个块:
| 块 | 内容 |
|---|---|
| Packages | 上传 .msix 文件 |
| Pricing and availability | 免费 / 付费区域 |
| Properties | 应用分类、隐私策略 URL 等 |
| Age ratings | 年龄分级问卷 |
| Store listing | 商店页面文案、截图、图标 |
4.2 上传 Packages
在 Packages 块,把本地生成的 Tydora_0.1.4.0_x64.msix 拖进去。
上传完成后,Partner Center 会自动解析 Identity 信息并校验:
Package identifier: <你的Name>_0.1.4.0_x64__<PFN后缀>Version: 0.1.4.0Architecture: x64如果和你在 Partner Center 注册的 Name/Publisher 一致,就显示绿色 ✓;否则会报类似:
无效的软件包标识名称: Tydora (应为: <你的Name>)无效的软件包发布者名称: CN=Tydora (应为: <你的Publisher>)这时候你需要:
1️⃣ 检查 .env 里的 MSSTORE_PACKAGE_IDENTITY_NAME / MSSTORE_PUBLISHER 是否正确
2️⃣ 用 -SkipBuild 重新打包(秒级)
3️⃣ 在 Packages 页先删除旧包,再上传新包
4.3 填写受限功能说明(runFullTrust)
因为 MSIX 清单里声明了 rescap:Capability Name="runFullTrust",Partner Center 会要求你在「Properties」或「Notes for certification」里解释用途。
这是我填写的内容,供参考:
Tydora 是一款桌面 Markdown 编辑器,采用 Tauri v2 框架构建,核心工作模式为「本地优先」——所有笔记、文件、配置都保存在用户自己的设备上,不经过任何云端服务器。
runFullTrust 是 Tauri 桌面应用的标准要求,具体用于:
- 文件系统读写:用户通过「仓库」机制选择本地文件夹作为笔记存储位置,应用需要直接读取和写入该文件夹下的
.md文件、图片附件等。 - 文件系统监听:当用户使用其他编辑器同时编辑笔记时,应用需要监听本地文件变更(通过 Rust
notifycrate),以实时同步链接索引。 - 系统文件对话框:使用 Tauri
plugin-dialog提供原生打开/保存对话框。 - 调用外部程序:用系统默认应用打开文件、在文件管理器中定位文件等。
- 发布网站功能:调用本地 Node.js CLI 将 Markdown 构建为静态网站。
应用不收集任何用户个人数据,所有操作均在本地完成;不包含任何第三方分析 SDK 或广告 SDK。runFullTrust 仅用于上述桌面应用场景,不会绕过系统安全机制。
4.4 隐私策略 URL
微软商店强制要求所有应用提供隐私策略 URL。我在文档站专门加了一个页面:「隐私策略 · Tydora」。
隐私策略内容要点(按微软商店审查清单):
✅ 明确「不收集个人数据」的本地优先声明
✅ 哪些「仅本地」的非个人数据会写入 localStorage
✅ 自动更新机制说明(仅 HTTPS 版本检查,无用户数据)
✅ MSIX 微软商店版本的 Microsoft 端遥测说明
✅ 不使用第三方分析/广告 SDK
✅ 数据安全、保留与删除方式
✅ 儿童隐私、用户权利、策略更新
4.5 商店页面素材
Store listing 块需要准备:
- 至少 1 张截图(推荐 1920×1080,PNG)
- 应用图标(512×512)
- 简短描述(≤ 200 字符)
- 详细描述(≤ 10000 字符)
- 发行说明(可选)
4.6 提交审核
填完所有块后,点 Submit for certification。状态变化:
Pending → Pre-processing → Certification → Publishing → In the Store整个认证流程通常 1-3 个工作日。如果被拒,Partner Center 会告诉你具体原因(比如隐私策略 URL 不可访问、runFullTrust 说明不充分等),修改后重新提交即可。
第 5 步:首个版本过审后的 CI 自动发布
微软硬性规定:首个版本必须手动上传,之后版本才能通过 API 自动发布。
5.1 关联 Microsoft Entra ID
在 Partner Center:
1️⃣ 右上角齿轮 → Account settings → Organizations(或 Entra ID / Azure AD)
2️⃣ 关联你的 Microsoft Entra ID 租户(个人开发者可以用自己的微软账号对应的默认租户)
3️⃣ 在 Entra ID 里注册一个应用:Azure Portal → App registrations → New registration
4️⃣ 给这个应用赋予 Partner Center 的 Manager 角色
5.2 拿到 4 个 Secrets 值
| Secret Name | 在哪里拿 |
|---|---|
AZURE_AD_TENANT_ID | Entra ID → 应用注册 → 概览 → 目录(租户) ID |
AZURE_AD_APPLICATION_CLIENT_ID | 同上 → 应用程序(客户端) ID |
AZURE_AD_APPLICATION_SECRET | 同上 → 证书和密码 → 新建客户端密码 → 生成的值(仅显示一次!) |
SELLER_ID | Partner Center → 账户设置 → Legal Info → Seller ID |
5.3 配置 GitHub 仓库
进入仓库 Settings → Secrets and variables → Actions:
🔒 Secrets(敏感信息):
| Name | Value |
|---|---|
AZURE_AD_TENANT_ID | 上面的租户 ID |
AZURE_AD_APPLICATION_CLIENT_ID | 上面的客户端 ID |
AZURE_AD_APPLICATION_SECRET | 上面的客户端密码 |
SELLER_ID | 上面的 Seller ID |
📋 Variables(非敏感,控制开关):
| Name | Value |
|---|---|
MSSTORE_PACKAGE_IDENTITY_NAME | <你的Name>(如 1234567890.Tydora) |
MSSTORE_PUBLISHER | <你的Publisher>(如 CN=XXXX-XXXX-...) |
MSSTORE_PUBLISHER_DISPLAY_NAME | <你的发布者显示名> |
MSSTORE_PRODUCT_ID | Partner Center 概览页的 Store product ID(如 9WZDNCRFXXXX) |
💡 关键设计:在 .github/workflows/msstore.yml 的发布步骤用 if: vars.MSSTORE_PRODUCT_ID 门控。只要不配 MSSTORE_PRODUCT_ID 变量,工作流只会构建 MSIX 并附到 GitHub Release,不会尝试调用 msstore publish。这意味着你可以现在就推 tag 验证 MSIX 打包是否成功,等手动上架后再开启自动发布。
5.4 工作流文件
完整工作流 .github/workflows/msstore.yml,核心步骤:
yaml on:push:tags: ['v*']workflow_dispatch:jobs:msix:runs-on:windows-lateststeps:-uses:actions/checkout@v4-name:SetupNode.jsuses:actions/setup-node@v4-name:InstallRuststableuses:dtolnay/rust-toolchain@stable-name:Rustcacheuses:swatinem/rust-cache@v2-name:Installfrontenddependenciesrun:npmci-name:BuildMSIXshell:pwshenv:MSSTORE_PACKAGE_IDENTITY_NAME:${{vars.MSSTORE_PACKAGE_IDENTITY_NAME}}MSSTORE_PUBLISHER:${{vars.MSSTORE_PUBLISHER}}run:./scripts/build-msix.ps1-name:UploadMSIXartifactuses:actions/upload-artifact@v4with:name:tydora-msixpath:src-tauri/target/msix/*.msix-name:AttachMSIXtoGitHubReleaseif:startsWith(github.ref,'refs/tags/v')uses:softprops/action-gh-release@v2with:files:src-tauri/target/msix/*.msix# 以下步骤仅当配置了 MSSTORE_PRODUCT_ID 时执行-name:SetupMicrosoftStoreCLIif:vars.MSSTORE_PRODUCT_IDuses:microsoft/microsoft-store-apppublisher@v1.1-name:Reconfigurestorecredentialsif:vars.MSSTORE_PRODUCT_IDrun:| msstore reconfigure ` --tenantId ${{ secrets.AZURE_AD_TENANT_ID }} ` --sellerId ${{ secrets.SELLER_ID }} ` --clientId ${{ secrets.AZURE_AD_APPLICATION_CLIENT_ID }} ` --clientSecret ${{ secrets.AZURE_AD_APPLICATION_SECRET }}-name:PublishpackagetoStoreif:vars.MSSTORE_PRODUCT_IDrun:| $msix = Get-ChildItem src-tauri/target/msix/*.msix | Select-Object -First 1 msstore publish $msix.FullName -id ${{ vars.MSSTORE_PRODUCT_ID }}
5.5 触发发布
bash # 打 taggit tag v0.1.5git push origin v0.1.5
推送后 GitHub Actions 自动跑:构建 → 打包 → 上传 Release → (配了变量时)发布到商店。整个过程约 10-15 分钟。
踩过的坑汇总
坑 1:MakeAppx 报 C00CEE3B 且错误信息是乱码
现象:
MakeAppx : error: Error info: error C00CEE3B: App manifest validation error:The app manifest XML must be valid: Line 28, Column 15, Reason: ???????????????????????????根因:<Properties> 下子元素顺序不符合 XML Schema。正确顺序必须是 DisplayName → PublisherDisplayName → Logo → Description,我原来把 Description 写在 Logo 前面了。
修复:调整 AppxManifest.xml 的元素顺序。
坑 2:中文变乱码导致闭合标签被吃掉
现象:MakeAppx 仍然报 C00CEE3B,但这次是真正的 XML 解析错误。
根因:PowerShell 5.1 的 Get-Content -Raw 在文件无 BOM 时,会按系统默认编码(中文 Windows = GBK/936)解码 UTF-8 字节。具体破坏点:
- 「左瑞宁」的「宁」UTF-8 编码是
E5 AE 81 - 紧跟其后的
<是3C - GBK 把
81 3C当作一个合法双字节汉字 → 吃掉了< - 导致
</PublisherDisplayName>变成?/PublisherDisplayName>,XML 闭合标签失效
修复:在 build-msix.ps1 里把 Get-Content -Raw 改成 [System.IO.File]::ReadAllText(path, [System.Text.Encoding]::UTF8),并给 AppxManifest.xml 加 UTF-8 BOM。
坑 3:Identity Name 不匹配
现象:
无效的软件包标识名称: Tydora (应为: <你的Name>)无效的软件包发布者名称: CN=Tydora (应为: <你的Publisher>)根因:.env 里的值带了引号和前导空格:
dotenv MSSTORE_PACKAGE_IDENTITY_NAME = " <你的Name>"
Tydora 的 loadEnv 解析器不剥引号,导致实际传给 MakeAppx 的 Name 是带引号带空格的字符串,触发 Partner Center 校验失败。
修复:.env 里去掉引号和 = 两边的空格:
dotenv MSSTORE_PACKAGE_IDENTITY_NAME=<你的Name>
坑 4:PublisherDisplayName 不匹配
现象:
应用清单中的 PublisherDisplayName 元素是 Tydora,该值与发布者显示名称: <你的发布者显示名> 不匹配根因:Partner Center 注册时填的发布者显示名(个人账号默认用真实姓名),但 manifest 模板里硬编码了「Tydora」。
修复:把 PublisherDisplayName 改成占位符 {{PUBLISHER_DISPLAY_NAME}},由脚本从 .env 注入。
坑 5:本地双击未签名 MSIX 报 0x800B010A
现象:商店模式打的包,本地双击显示「发布者: 未知」,安装按钮灰色,报错 0x800B010A。
根因:不是坑,是预期行为。商店模式的包本来就不签名,只应该上传到 Partner Center,由微软统一签名后分发。
解决:如果只是想本地测试安装效果,用本地模式(注释掉 .env 里的 MSSTORE_* 三行)打一个自签名的包即可。
常用命令速查
powershell # 完整打包(含 Rust 编译)npm run tauri build:msix# 跳过编译,仅重新打包npm run tauri build:msix ---SkipBuild# 跳过签名npm run tauri build:msix ---SkipBuild-NoSign# 强制在商店模式下也签名(用于本地安装商店身份的包做视觉验证)npm run tauri build:msix ---SkipBuild-Sign# 本地测试模式(不配 MSSTORE_* 变量)Remove-Item Env:MSSTORE_PACKAGE_IDENTITY_NAME, Env:MSSTORE_PUBLISHER, Env:MSSTORE_PUBLISHER_DISPLAY_NAME -ErrorAction SilentlyContinuenpm run tauri build:msix ---SkipBuild
参考资料
Publishing app updates to Microsoft Store with GitHub Actions
https://learn.microsoft.com/en-us/windows/apps/publish/msstore-dev-cli/github-actions?tabs=msix
MakeAppx.exe 文档
https://learn.microsoft.com/zh-cn/windows/win32/appxpkg/make-appx-package--makeappx-exe-
App package manifest schema reference
https://learn.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/schema-root
Microsoft Store submission API
https://learn.microsoft.com/en-us/windows/uwp/monetize/create-and-manage-submissions
写在最后
把应用上架微软商店,整个流程走下来最大的感受是——坑都在细节里。XML 元素顺序错了不行,编码没搞对不行,.env 多了个引号也不行。但一旦首个版本上架成功,后续的 CI 自动化发布就非常顺滑了。
希望这篇文章能帮到同样想把 Tauri 应用上架微软商店的你。如果觉得有用,欢迎点赞收藏 👍
夜雨聆风