HarmonyOS 7 ReleaseGuard 上架审核工程实录 01:build-profile.json5 × AppGallery Connect:包名、版本号与发布签名预检【鸿蒙心迹】
SlideDrop 系列结束后,这一轮换到一个完全不同的工程阶段:应用写完了,准备上架 AppGallery Connect,怎么把“上传以后才发现的错误”提前挡在本地。
Demo 叫 ReleaseGuard。
它不是面向用户的业务 App,而是团队内部的发布预检工具。ReleaseGuard 会在生成正式 .app 包以后,把应用标识、版本、签名、目标 API、支持设备和构建产物做成一份可验证快照;手机端只是把这份快照和检查结果可视化,真正的构建信息来自发布流水线。
这个系列固定 6 篇:
01 包名、版本号与发布签名预检
02 权限声明、隐私标签与三方 SDK 合规映射
03 图标、截图、应用描述与内容分级素材校验
04 支持设备、权限 Profile 与包体有效性报告
05 版本升级、签名连续性与灰度发布前检查
06 CI 发布门禁、审核证据包与全链路验收
第一篇不碰隐私,也不碰运营素材,只解决上传包本身最基础的一层。
AppGallery Connect 当前的 HarmonyOS 包解析错误文档已经把常见问题写得很明确:bundleName 与 AppGallery Connect 不一致、使用了错误的 Profile、使用 debug Profile、证书过期、包未签名、包内设备类型与市场侧选择不匹配,都可能让上传直接失败;HarmonyOS 应用正式发布还需要 .app 包和正确的 release 签名链。
所以 01 的目标很克制:
在点“上传”以前,先让本地构建产物自己证明它是“我要发布的那个 App”。
本轮统一数据:
taskId:
release_20261002_01
bundleName local:
com.example.releaseguard
bundleName AGC:
com.example.releaseguard
versionName:
1.3.0
versionCode:
10300
buildMode:
release
signingConfig:
release_prod_202610
certificateState:
RELEASE_VALID
targetApi:
26
compatibleApi:
20
deviceTypes:
phone / tablet
artifact:
releaseguard_1.3.0.app
artifactSize:
18.4MB
checks:
8 / 8
risk:
0
status:
PACKAGE_READY

一、ReleaseGuard 不直接在手机里读取工程源码
最开始我也想过,让工具在运行时直接读取:
AppScope/app.json5
build-profile.json5
module.json5
但真正的 release 包里,这些“开发阶段文件”的存在形式、路径和构建产物都不应该被业务页面假设。
所以 ReleaseGuard 的第一层不是“运行时扫工程”,而是:
构建阶段
→ 生成 ReleaseManifestSnapshot.json
→ 打进 internal 构建
→ ReleaseGuard 页面读取快照
这样手机端看到的是本次 release 构建已经解析完成的数据,而不是重新猜一次工程配置。
快照模型:
export interface ReleaseManifestSnapshot {
taskId: string
bundleName: string
agcBundleName: string
versionName: string
versionCode: number
buildMode: 'debug' | 'release'
signingConfig: string
certificateState:
'RELEASE_VALID' |
'DEBUG_ONLY' |
'EXPIRED' |
'UNKNOWN'
targetApi: number
compatibleApi: number
deviceTypes: string[]
artifactName: string
artifactSizeMb: number
}
这段模型解决的问题不是“怎么解析 json5”,而是给后续检查建立一个固定输入。
构建脚本、DevEco Studio 配置字段即使以后调整,ReleaseGuard 的检查器只要继续拿到同一份 Snapshot,就不用把业务判断全部改掉。
二、第一条门禁永远是 bundleName 一致
HarmonyOS Stage 模型里,应用级 bundleName 位于 AppScope/app.json5。AppGallery Connect 的包解析文档也明确指出,上传包中解析出的 bundleName 必须和 AppGallery Connect 创建应用时的包名一致;不一致会触发包解析失败。
这类问题很适合提前拦。
export interface CheckItem {
key: string
passed: boolean
message: string
}
export class PackagePreflightRunner {
checkBundleName(
snapshot:
ReleaseManifestSnapshot
): CheckItem {
const passed =
snapshot.bundleName ===
snapshot.agcBundleName
return {
key:
'BUNDLE_NAME',
passed,
message:
passed
? 'bundleName match'
: `${snapshot.bundleName} != ${snapshot.agcBundleName}`
}
}
}
当前:
local:
com.example.releaseguard
AGC:
com.example.releaseguard
结果为:
MATCH
这里不要用应用显示名称判断。
显示名称都叫 “ReleaseGuard”,包名仍然可能完全不同。
三、版本号不只要“有”,还要进入发布策略
当前版本:
versionName=1.3.0
versionCode=10300
ReleaseGuard 先做两层判断:
versionName 非空
versionCode
必须高于团队记录的上一正式发布值
例如:
export class VersionPreflight {
check(
snapshot:
ReleaseManifestSnapshot,
lastPublishedCode:
number
): CheckItem[] {
return [
{
key:
'VERSION_NAME',
passed:
snapshot.versionName
.trim()
.length > 0,
message:
snapshot.versionName
},
{
key:
'VERSION_CODE',
passed:
snapshot.versionCode >
lastPublishedCode,
message:
`${snapshot.versionCode} > ${lastPublishedCode}`
}
]
}
}
这一层不是在复制 AppGallery Connect 服务端校验。
它解决的是团队自己的发布纪律:
本地构建出来的版本
是不是比上一版新
如果版本号在本地就回退,就没必要等上传以后再发现。
四、正式包不能带 debug Profile 思维
当前包:
buildMode=release
signingConfig=
release_prod_202610
certificateState=
RELEASE_VALID
AppGallery Connect 的 HarmonyOS 包解析错误说明里,debug certificate / debug profile 用于正式发布会被判定为错误;包未签名、Profile 失效、证书过期,也都会阻止发布。
所以 ReleaseGuard 不只判断:
“有签名配置”
而是检查:
构建模式是 release
签名配置名称进入 release 白名单
证书 / Profile 检查结果有效
export class SigningInspector {
inspect(
snapshot:
ReleaseManifestSnapshot
): CheckItem[] {
const releaseMode =
snapshot.buildMode ===
'release'
const releaseSigning =
snapshot.signingConfig
.startsWith(
'release_'
)
const certValid =
snapshot.certificateState ===
'RELEASE_VALID'
return [
{
key:
'BUILD_MODE',
passed:
releaseMode,
message:
snapshot.buildMode
},
{
key:
'SIGNING_CONFIG',
passed:
releaseSigning,
message:
snapshot.signingConfig
},
{
key:
'CERTIFICATE',
passed:
certValid,
message:
snapshot.certificateState
}
]
}
}
我不会在文章里把“签名配置名称必须以 release_ 开头”写成 HarmonyOS 系统规则。
这是 ReleaseGuard 自己的团队约定,用来避免拿错构建配置。
真正系统要求仍然以 AppGallery Connect 当前证书、Profile 和签名文档为准。
五、.app 产物存在,和“这个包可以发布”是两回事
本轮构建产物:
releaseguard_1.3.0.app
18.4MB
预检至少确认:
产物存在
扩展名为 .app
文件大小大于 0
构建时间属于本次 task
产物与 Snapshot 版本一致
不能拿昨天的 1.2.9 包,配上今天的 1.3.0 报告一起上传。
所以 Snapshot 会把:
taskId
artifactName
versionName
绑定。
只要不一致:
STALE_ARTIFACT
直接阻断。
六、支持设备也要和市场侧配置做一次对照
当前包:
deviceTypes:
phone
tablet
AppGallery Connect 的包解析错误文档同样列出了:
上传包支持设备
与市场侧选择设备不一致
的失败场景。
ReleaseGuard 当前把 AGC 侧选择同步成发布配置:
expectedDeviceTypes:
phone / tablet
然后做集合比较。
不是简单判断:
deviceTypes.length > 0
因为:
只支持 phone 的包
如果市场版本信息里同时勾了 tablet,也应该在上传前发现。
七、Target API / Compatible API 只做工程门禁,不伪造市场规则
本轮:
targetApi=26
compatibleApi=20
ReleaseGuard 当前只检查:
targetApi >= compatibleApi
以及 targetApi 是否等于本次发布计划里的目标 API。
我不会在文章里写:
AppGallery 永远要求 targetApi=26
因为市场要求会随时间变化。
正确做法是把“当前发布要求”做成团队可更新的规则源:
release-policy.json
而不是把市场政策硬编码进 ArkTS。
八、8 个检查项怎么组成
本轮最终 8 项:
1 bundleName 一致
2 versionName 合法
3 versionCode 递增
4 buildMode=release
5 release signing
6 certificate / profile 有效
7 .app 产物匹配
8 deviceTypes / target API 计划匹配
全部通过:
8 / 8
risk=0
才进入:
PACKAGE_READY
这个状态只代表:
包体和发布身份基础预检通过。
它不代表:
隐私合规已经通过
素材已经准备好
内容分级已经完成
审核一定会通过
后面的 02~06 还要继续收口。
九、DevEco 图里重点看“本地包名”和“AGC 包名”同时出现
开发图:

统一日志:
taskId=
release_20261002_01
bundleName local=
com.example.releaseguard
bundleName agc=
com.example.releaseguard
versionName=
1.3.0
versionCode=
10300
buildMode=
release
signingConfig=
release_prod_202610
certificate=
RELEASE_VALID
artifact=
releaseguard_1.3.0.app
size=
18.4MB
deviceTypes=
phone,tablet
targetApi=
26
checks=
8/8
risk=
0
status=
PACKAGE_READY
这套日志的价值在于:
上传失败时
能马上和 AGC 错误报告对照
而不是只留一句:
build success
十、运行图把“包体身份”集中到一张手机页面
最终运行图:

页面里不展示用户业务,而是展示:
bundleName
版本
发布签名
证书状态
目标 API
设备类型
构建产物
8 项检查
最终:
PACKAGE_READY
这张手机图只是 internal 构建的诊断页。
正式发布包不会把这类发布工具入口暴露给普通用户。
十一、这一篇最值得提前规避的是 AppGallery Connect 的解析错误
当前官方包解析错误说明中,和 01 直接相关的典型错误包括:
bundleName 不一致
Profile 不属于当前应用
使用 debug Profile
Profile 过期
证书异常
包未签名
设备支持信息不匹配
权限与 Profile 不一致
01 先覆盖前六类中的基础部分。
权限与隐私会放到下一篇处理。
我们不可能在本地复制 AppGallery Connect 全部服务端规则,但完全可以把团队最常见、最确定的一批错误挡在上传按钮以前。
十二、下一篇从“包能上传”进入“隐私能对得上”
01 做完以后,包体基础没问题。
接下来最自然的问题是:
module.json5 里声明了什么权限
应用实际为什么要用
隐私政策有没有写
三方 SDK 收集什么
AGC 隐私标签有没有对齐
第二篇会继续同一个 ReleaseGuard,把权限、隐私政策、第三方 SDK 和 AppGallery Connect 隐私标签做成一张可检查矩阵。
不会换项目,也不会重新编号。
十三、把 AppGallery 常见包解析错误做成本地风险映射
ReleaseGuard 不需要复制 AppGallery Connect 的全部服务端校验,但很适合维护一张“团队常见错误 → 本地可检查项”的映射。
当前我先整理这几类:
bundleName 不一致
→ BUNDLE_NAME_MISMATCH
debug Profile
→ DEBUG_PROFILE_FOR_RELEASE
Profile 过期
→ PROFILE_EXPIRED
证书无效
→ CERTIFICATE_INVALID
包未签名
→ UNSIGNED_PACKAGE
设备类型不匹配
→ DEVICE_TYPE_MISMATCH
权限与 Profile 不一致
→ PROFILE_PERMISSION_MISMATCH
这些名字是 ReleaseGuard 的内部风险码,不等于 AppGallery Connect 官方错误码。
真正好处是失败日志更容易读。
比如 AppGallery 返回包解析错误时,发布负责人可以直接在 ReleaseGuard 报告里搜索:
BUNDLE_NAME
SIGNING
PROFILE
DEVICE
快速判断“我们本地本来应该能不能提前发现”。
长期下来,这张映射还能反向推动工具迭代:每次线上出现一个本地漏掉的新问题,就评估是否应该加入 Preflight,而不是下一次继续靠人工记忆。
十四、构建产物还要绑定 hash,防止“报告是新的,包是旧的”
只绑定文件名还不够。
如果 CI 工作目录没有清理干净,完全可能同时存在:
releaseguard_1.3.0.app
两个不同构建产物,名称一样,内容却不一样。
所以 Snapshot 最终还会保存:
artifactSha256
artifactBuiltAt
pipelineRunId
上传前再计算一次 hash:
export interface ArtifactIdentity {
fileName: string
sha256: string
buildTaskId: string
builtAt: number
}
export class ArtifactIdentityCheck {
verify(
expected:
ArtifactIdentity,
actual:
ArtifactIdentity
): boolean {
return (
expected.fileName ===
actual.fileName &&
expected.sha256 ===
actual.sha256 &&
expected.buildTaskId ===
actual.buildTaskId
)
}
}
这样可以避免最危险的一类发布事故:
版本页写的是 1.3.0
实际上传的是另一个流水线生成的旧包
这种问题 AppGallery 可能能从版本字段发现一部分,但发布工具自己也应该把产物身份固定下来。
十五、Preflight 要区分 BLOCKER 和 WARNING
不是所有问题都应该一票否决。
例如:
bundleName 不一致
发布签名错误
产物不存在
属于:
BLOCKER
而:
包体比上一版本大 8%
版本说明还没填写
本地报告生成时间超过 30 分钟
更适合:
WARNING
所以检查结果里增加 severity:
export type CheckSeverity =
'BLOCKER' |
'WARNING'
export interface ReleaseCheckItem {
key: string
severity: CheckSeverity
passed: boolean
message: string
}
最终状态规则:
存在 BLOCKER
→ PACKAGE_BLOCKED
只有 WARNING
→ PACKAGE_READY_WITH_WARNING
全部通过
→ PACKAGE_READY
本轮风险项为 0,所以直接进入 PACKAGE_READY。
把严重级别分开后,团队不会因为一个不影响上传的提示被工具卡死,也不会因为所有检查都只是黄色提示而忽略真正的发布错误。
十六、release Profile 和 package 权限最好在第一篇就留一个接口
权限细节放到 02,但 01 已经知道 AppGallery 包解析阶段可能检查 Profile 与包内权限一致性。
所以 PackagePreflightRunner 预留:
profilePermissionSnapshot
01 只确认:
release Profile 已加载
02 再真正做:
module.json5 requestPermissions
⊆
release Profile requested permissions
这样两篇不是两套孤立工具,而是同一个 Runner 持续补充检查。
这也是我设计 ReleaseGuard 系列时最在意的一点:
上架审核不是六张互不相关的 Checklist,而是一份发布上下文逐步变完整。
十七、发布报告必须可机器读取,不只是一张手机页面
手机页适合人看,CI 需要 JSON。
所以最终 Preflight Report 还会输出:
{
"taskId": "release_20261002_01",
"status": "PACKAGE_READY",
"checks": 8,
"passed": 8,
"blockers": 0,
"warnings": 0
}
下一步流水线可以:
status != PACKAGE_READY
→ 禁止上传步骤执行
这样“预检”才真正成为 Release Gate,而不是开发者想看就看、不看也能发的辅助页面。
第六篇会继续把这份 JSON 和审核证据一起打包进 CI。
十八、第一篇最后做十组反向测试
除了正常 8/8,我还固定做:
1 bundleName 故意改错
2 versionCode 回退
3 buildMode 改成 debug
4 signingConfig 指向 debug
5 certificate 标记 expired
6 .app 文件不存在
7 artifact hash 不一致
8 deviceTypes 少 tablet
9 targetApi 与本次计划不一致
10 Snapshot taskId 与产物 pipelineRun 不一致
这十组必须都能被工具明确识别,而且给出不同风险码。
只有“正常包通过 + 异常包能被准确挡住”同时成立,Preflight 才值得放进发布流程。
如果工具只会给正常包打绿勾,却抓不住故意制造的错误,那它只是展示页,不是发布门禁。
十九、上传前还要冻结一次“发布上下文”,避免检查通过后又被改动
预检通过以后,最怕的是:
报告还是 PACKAGE_READY
工程配置却又被人改了
比如检查完成后临时改了:
bundleName
versionCode
deviceTypes
signingConfig
如果流水线继续沿用旧报告,前面的 8/8 已经失去意义。
所以 ReleaseGuard 在 PACKAGE_READY 时生成:
releaseContextId
它由以下信息摘要得到:
Snapshot
Artifact hash
Release policy revision
Signing identity
真正进入上传步骤时,再重新计算一次。
如果 contextId 不一致:
RELEASE_CONTEXT_CHANGED
必须重新预检。
这样“通过检查”和“上传产物”就被绑定在同一份上下文里,不会出现报告和实际包脱节。
二十、ReleaseGuard 的 01 最终收口标准
第一篇最终不是看页面有多少个绿勾,而是看发布链是否满足:
应用身份一致
版本身份一致
发布签名有效
构建产物唯一
设备范围一致
API 计划一致
产物与报告绑定
检查结果可被 CI 读取
只有这些同时成立,PACKAGE_READY 才表示:
这个包值得进入 AppGallery Connect 的下一阶段,而不是“它大概率能上传”。
这也是为什么下一篇可以放心把注意力转到权限和隐私,不再反复回头检查包体身份。
参考资料
- HarmonyOS 包解析错误码(AppGallery Connect):https://developer.huawei.com/consumer/jp/doc/app/agc-help-harmonyoserror-0000001651912985
- HarmonyOS 应用 bundleName 配置与 AGC 一致性参考:https://developer.huawei.com/consumer/cn/doc/doccenter-capabilities/payment-config-app-identity-info
- AppGallery Connect 版本历史:https://developer.huawei.com/consumer/fr/doc/app/agc-help-maintain-version-history-0000002236334582
更多推荐




所有评论(0)