用 PackageUploader 自动化上传 MSStore
用 PackageUploader 自动化上传 MSStore
手动上传是浏览器登 Partner Center 手点;自动化是让微软官方的 PackageUploader 工具用 Azure AD App 的 ClientSecret 程序化登录、上传、删包、发布,不用每次开浏览器。
- 文档:https://learn.microsoft.com/zh-cn/gaming/gdk/docs/features/common/packaging/package-uploader
- 项目:https://github.com/microsoft/PackageUploader
- 工具下载:https://github.com/microsoft/PackageUploader/releases
先拿 bigId
每个游戏在 Partner Center 有个 bigId(9 开头的 12 位字符串):
- 登 https://partner.microsoft.com
- 进 Xbox & PC game publishing → 点游戏
- 看地址栏
https://partner.microsoft.com/dashboard/products/9XXXXXXXX/...,9XXXXXXXX就是 bigId
准备 Azure AD App(证书认证的前提)
证书认证(-a AppSecret)需要三个值,都从 Azure Entra ID 拿:
| 值 | 在哪找 |
|---|---|
tenantId | Azure Portal → Entra ID → 概述 |
clientId | Azure Portal → Entra ID → 应用注册 → 你的 App → 概述 |
clientSecret | Azure Portal → Entra ID → 应用注册 → 你的 App → 证书和密码 |
创建步骤:Azure Portal → 应用注册 → 新注册,名字随便填,账户类型选"仅此组织目录中的账户",重定向 URI 留空 → 注册。记下应用(客户端)ID 和 目录(租户)ID。再到 证书和密码 → 新建客户端密码,有效期 12-24 个月,立刻复制密码的"值"(离开页面就再也看不到)。这个 App 还要在 Partner Center 的 Account settings → User management → Azure AD applications 里加进去并赋开发者角色。
注册和配置证书都需要 Azure 租户管理员权限。如果你的账号只是外部协作者(manager/developer 角色),没有租户应用注册权限,这一步得让客户方 IT 或管理员协助。
验证权限:GetProduct
上传前先用 GetProduct 验证账号有 API 访问权,顺便确认 flightName 的准确大小写(上传时必须完全一致):
{"operationName": "GetProduct", "bigId": "<BIG_ID>"}
PackageUploader.exe GetProduct -c GetProduct.json -a Browser
多租户账号 not found 的坑
如果你的账号挂在两个 Azure 目录下,-a Browser 模式会默认登进其中一个,导致 bigId not found。试过在 json 里指定客户的 Tenant ID 无效——-a Browser 的逻辑是先用浏览器 session,成功了就完全忽略配置里的 Tenant ID。
绕法是在弹出浏览器登录时手动切目录(以下五步要在 100s 内完成,否则超时):
- 登录界面不要直接点账号,选 "Use another account"
- 在该界面点最下方 "Sign-in options"
- 选 "Sign in to an organization"
- 输入客户的域名
- 再选账号登录
全自动流程
证书认证拿到 tenantId/clientId/clientSecret 后,四个操作各有一个 json + 一条命令。命令统一是 -a AppSecret -s "<ClientSecret>" -t "<TenantId>" --Verbose。
上传
{
"operationName": "UploadXvcPackage",
"bigId": "{BIG_ID}",
"branchFriendlyName": "{BRANCH_NAME}",
"marketGroupName": "{MARKET_GROUP}",
"deltaUpload": true,
"packageFilePath": "{PKG_PATH}",
"gameAssets": {
"ekbFilePath": "{EKB_PATH}",
"subValFilePath": "{SUBVAL_PATH}",
"symbolsFilePath": "{SYMBOL_PATH}",
"discLayoutFilePath": "{LAYOUT_PATH}"
},
"minutesToWaitForProcessing": 60,
"availabilityDate": { "isEnabled": false, "effectiveDate": "" },
"uploadConfig": {
"httpTimeoutMs": 5000,
"httpUploadTimeoutMs": 300000,
"maxParallelism": 24,
"defaultConnectionLimit": -1,
"expect100Continue": false,
"useNagleAlgorithm": false
}
}
PackageUploader.exe UploadXvcPackage -c upload_config.json -a AppSecret -s "<ClientSecret>" -t "<TenantId>" --Verbose
deltaUpload 增量上传:XVC 和 MSIXVC 支持,UWP 不支持。minutesToWaitForProcessing 是上传完轮询包处理状态的等待时间。
获取包列表(删包前置)
删包不能按文件名,必须用 GUID,先 GetPackages 拿当前分支所有包的 packageId:
{
"operationName": "GetPackages",
"bigId": "{BIG_ID}",
"branchFriendlyName": "{BRANCH_NAME}",
"marketGroupName": "{MARKET_GROUP}"
}
PackageUploader.exe GetPackages -c get_packages.json -a AppSecret -s "<ClientSecret>" -t "<TenantId>" --Verbose
删包
Partner Center 限制同一市场组下只能有一个可发布状态的包,发新包前必须删旧包。删除不可逆,且只能用 GUID:
{
"operationName": "RemovePackages",
"bigId": "{BIG_ID}",
"branchFriendlyName": "{BRANCH_NAME}",
"packageIdsToRemove": [ "{OLD_PACKAGE_ID_1}", "{OLD_PACKAGE_ID_2}" ]
}
PackageUploader.exe RemovePackages -c remove_config.json -a AppSecret -s "<ClientSecret>" -t "<TenantId>" --Verbose
发布
把已上传且状态 Ready 的包推到沙盒。前置条件:目标市场组下没有其他 Ready/Published 旧包(先 Remove),新包已处理完成。
{
"operationName": "PublishPackages",
"bigId": "{BIG_ID}",
"branchFriendlyName": "{BRANCH_NAME}",
"destinationSandboxName": "{SANDBOX_NAME}",
"minutesToWaitForPublishing": 60,
"publishConfiguration": {
"releaseTime": "",
"isManualPublish": false,
"certificationNotes": "Auto-published from Jenkins Build #{BUILD_NUMBER}"
},
"aadAuthInfo": {
"clientId": "{CLIENT_ID}",
"tenantId": "{TENANT_ID}"
}
}
PackageUploader.exe PublishPackages -c publish_config.json -a AppSecret -s "<ClientSecret>" -t "<TenantId>" --Verbose
isManualPublish 为 true 时只准备、需人工网页确认;false 则自动触发。
没有租户权限时的半自动方案
拿不到 Azure 租户应用注册权限时,只能退而求其次:流水线在每个待上传版本目录里生成对应的 json 和 bat,在装了工具且有上传权限的机器上双击 bat,再走一遍上面的五步浏览器验证就能传。bat 里用的是 Browser 模式:
cmdLine = "\"${uploaderPath}\" UploadXvcPackage -c \"${fullJsonPath}\" -a Browser --Verbose"
这套方案的取舍:能同时点多个 bat 并发上传(实测 4 个版本同时没问题)、支持增量、比网页版稳;但每点一次都要手动做一遍五步验证,登录验证失效有不确定性,且后续删包/发布还得人工。
认证方式对比
| 方式 | 适用 | 特点 |
|---|---|---|
-a Browser / -a CacheableBrowser | 手动操作 | 需图形界面和用户交互;CI 里无法弹浏览器会超时卡死,报 TaskCanceledException ... HttpClient.Timeout of 100 seconds |
-a AppSecret / -a AppCert | CI/CD、自动化 | Client Secret/证书自动取 token,过期自动刷新;需在租户注册 Azure AD 应用并配置证书,需要租户管理员权限 |