03 刚刚把图标、截图、应用描述和内容分级做成了 Listing Report。

第四篇我又回到底层包体。

原因很现实:AppGallery Connect 在真正解析 .app 时,会检查一批开发者本地完全可以提前确认的关系。当前 HarmonyOS 包解析错误文档里,和这一篇直接相关的典型场景包括:

998:
上传包不支持市场侧选择的设备类型

999:
使用了错误类型的 Profile

1000 / 1001 / 1002 / 1005:
Profile / Certificate 异常

1014:
HAP 未签名

7014:
包内权限与 Profile 请求权限不一致

这些错误没必要等上传以后才看见。

所以 04 新增一份 Package Report,专门回答:

这个 .app 在“设备、Profile、权限、签名、包类型”几个基础层面,是否已经和本次发布计划一致。

本轮统一数据:

taskId:
release_20261002_04

bundleName:
com.example.releaseguard

versionName:
1.3.0

versionCode:
10300

targetApi:
26

compatibleApi:
20

artifact:
releaseguard_1.3.0.app

artifactSize:
18.4MB

packageType:
app

moduleCount:
1

hapCount:
1

entryModule:
entry

packageDeviceTypes:
phone / tablet

agcSupportedDevices:
phone / tablet

deviceTypeMismatch:
0

packagePermissions:
3

profilePermissions:
3

permissionSubset:
true

releaseProfile:
release_prod_202610

profileState:
VALID

certificateState:
RELEASE_VALID

signed:
true

parseChecks:
9 / 9

parseRisk:
0

status:
PACKAGE_REPORT_READY

一、04 不再读工程配置,而是读“构建后包体快照”

这一篇最重要的变化是输入。

01 还主要看:

app.json5
build-profile.json5

04 更接近真实上传阶段,所以检查器读取的是构建后生成的:

PackageReportSnapshot

模型:

export interface PackageReportSnapshot {
  taskId: string

  bundleName: string
  versionName: string
  versionCode: number

  targetApi: number
  compatibleApi: number

  artifactName: string
  artifactSizeMb: number

  packageType: string

  modules: {
    name: string
    type: string
    deviceTypes: string[]
    permissions: string[]
    signed: boolean
  }[]

  releaseProfile: string
  profilePermissions: string[]

  profileState: string
  certificateState: string
}

这份 Snapshot 可以由构建脚本或包解析工具生成。

ArkTS 页面只展示结果。

这样报告反映的是:

真正要上传的包

而不是工程源码“理论上应该长这样”。

二、deviceTypes 要比较“包支持范围”和“市场选择范围”

当前包:

phone
tablet

AppGallery Connect 发布计划:

phone
tablet

所以:

deviceTypeMismatch=0

官方当前包解析错误码 998 已经明确说明:上传包如果不支持 AppGallery Connect 里为应用选择的设备类型,包解析会失败。

本地完全可以提前比较集合:

export class DeviceSupportAudit {
  check(
    packageDeviceTypes:
      string[],
    agcSupportedDevices:
      string[]
  ): {
    missing: string[]
    passed: boolean
  } {
    const missing =
      agcSupportedDevices
        .filter(
          device =>
            !packageDeviceTypes
              .includes(device)
        )

    return {
      missing,
      passed:
        missing.length === 0
    }
  }
}

注意关系是:

AGC 选择的设备
必须被包覆盖

不是要求两边字符串完全一模一样。

这和官方错误描述“package does not support selected devices”更一致。

三、为什么 deviceTypes 不能只看 AppScope

真正设备声明位于模块层。

所以 04 会把每个 HAP / module 的:

deviceTypes

展开。

当前只有:

entry

一个模块:

phone
tablet

因此汇总结果很简单。

如果以后有:

entry-phone
entry-tablet
feature-pc

报告必须按模块汇总,而不是只读一个全局字段。

这也是 moduleCount=1 / hapCount=1 进入诊断数据的原因。

四、Profile 权限必须覆盖包内声明权限

这是 04 最值得工程化的一条。

AppGallery Connect 当前 HarmonyOS 包解析错误 7014 明确说明:

包中配置的权限必须是 Profile 请求权限的子集。

当前:

packagePermissions=3
profilePermissions=3
permissionSubset=true

检查器:

export class ProfilePermissionAudit {
  check(
    packagePermissions:
      string[],
    profilePermissions:
      string[]
  ): {
    missing: string[]
    subset: boolean
  } {
    const profileSet =
      new Set(
        profilePermissions
      )

    const missing =
      packagePermissions
        .filter(
          permission =>
            !profileSet
              .has(permission)
        )

    return {
      missing,
      subset:
        missing.length === 0
    }
  }
}

这和 02 的隐私检查不是同一件事。

02 问:

权限用得合不合理
有没有披露

04 问:

这个 release Profile
技术上有没有覆盖包里声明的权限

两个层面都必须通过。

五、Profile 状态与 Certificate 状态也要进报告

当前:

releaseProfile:
release_prod_202610

profileState:
VALID

certificateState:
RELEASE_VALID

官方包解析错误文档里已经列出多种 Profile / Certificate 问题:

Profile 无效

Profile 不属于该应用

Profile 过期

Profile 与证书不匹配

证书过期

证书未生效

证书无效

ReleaseGuard 不复制所有证书验证逻辑。

真正证书链校验可以由构建阶段工具完成。

04 只要求 Package Report 必须带一个清晰状态:

VALID

否则发布门禁直接 BLOCK。

六、HAP 签名必须在包体报告里明确可见

当前:

signed=true

因为官方错误 1014 就是:

HAP has not been signed

这种错误太基础,不应该等上传以后才发现。

报告里每个 HAP 都要有:

signed
signatureIdentity

当前单 HAP:

entry
signed=true

所以通过。

如果未来多模块:

只要有一个 HAP unsigned
→ PACKAGE_BLOCKED

七、packageType 也要和应用类型对得上

当前:

packageType=app

AppGallery Connect 包解析文档还存在:

1011:
包不是 HarmonyOS app

1026:
包类型和应用类型不匹配

ReleaseGuard 04 因此把 packageType 做成显式字段。

这看起来像“不会配错”,但 CI 里如果有人复用错误构建任务,完全可能产出另一个类型的包。

工具应该让这种错误在上传前直接可见。

八、目标 API 继续只做本次发布计划校验

本轮:

targetApi=26
compatibleApi=20

和 01 一样,ReleaseGuard 不宣称:

AppGallery 永远要求 API 26

它只检查:

targetApi
符合本次 release-policy.json

compatibleApi
不高于 targetApi

市场要求未来变化时,只更新发布策略,不改 ArkTS 业务代码。

九、9 个 parseChecks 怎么组成

当前 9 项:

1 bundleName 与发布上下文一致

2 packageType=app

3 module / HAP 数量可解析

4 package deviceTypes 覆盖 AGC 选择

5 package permissions 是 Profile permissions 子集

6 release Profile 状态 VALID

7 certificate 状态 RELEASE_VALID

8 所有 HAP signed=true

9 artifact / version / API 与 Release Context 一致

全部通过:

9 / 9
parseRisk=0

进入:

PACKAGE_REPORT_READY

这个状态比 01 的 PACKAGE_READY 更靠近真正上传阶段。

01 是工程配置预检。

04 是构建后包体报告。

十、DevEco 图里最值得看的是两条“子集 / 覆盖”关系

开发图:

红色标注的两条关系:

package permissions
⊆
release Profile permissions

以及:

AGC selected devices
⊆
package deviceTypes

HiLog:

taskId=
release_20261002_04

package devices=
phone,tablet

agc devices=
phone,tablet

mismatch=
0

package permissions=
3

profile permissions=
3

subset=
true

profile=
release_prod_202610

profileState=
VALID

certificate=
RELEASE_VALID

signed=
true

artifact=
releaseguard_1.3.0.app

size=
18.4MB

modules=
1

hapCount=
1

targetApi=
26

parseChecks=
9/9

parseRisk=
0

status=
PACKAGE_REPORT_READY

这两条集合关系是 04 最核心的工程判断。

十一、手机图把包体解析结果变成发布负责人能读懂的报告

最终运行图:

它不要求发布负责人去翻:

module.json5
profile
证书
包解析日志

页面直接告诉你:

设备支持是否覆盖

Profile 权限是否覆盖

签名是否有效

HAP 是否已签名

包类型是否正确

9 项解析是否通过

最终:

PACKAGE_REPORT_READY

十二、把官方错误码映射成内部 Risk,而不是冒充服务端错误

ReleaseGuard 会维护一份本地映射:

DEVICE_TYPE_MISMATCH
↔ AGC 998 场景

PROFILE_PERMISSION_MISMATCH
↔ AGC 7014 场景

WRONG_PROFILE_TYPE
↔ AGC 999 场景

UNSIGNED_HAP
↔ AGC 1014 场景

注意是:

“对应场景”

而不是:

“本地工具已经得到官方错误码”

只有 AppGallery Connect 服务端真正返回的,才叫官方解析结果。

这种措辞必须严谨。

十三、包体报告还应该保存原始证据

如果检查失败,只给:

permissionSubset=false

不够。

报告至少保存:

缺失权限列表

AGC 设备选择

package deviceTypes

Profile ID

certificate serial / validity

HAP names

artifact hash

这样真正上传失败时可以直接和服务端错误对照。

发布工具越接近门禁,证据链越重要。

十四、04 最后固定九组故障注入

正常 9/9 之外,固定制造:

1 AGC 勾 tablet,包只有 phone

2 package 多一个 Profile 未授权权限

3 Profile state=EXPIRED

4 Certificate=EXPIRED

5 HAP signed=false

6 packageType=atomicService

7 artifact version 与 Snapshot 不一致

8 targetApi 与 release policy 不一致

9 多 module 中一个模块 deviceTypes 配错

每一组都应该得到明确 Risk。

工具只有能抓住“故意错的包”,才有资格进入 CI。

十五、下一篇开始处理“版本升级”而不是“单个包是否合法”

04 到这里,单个 1.3.0 包已经完成:

基础身份
隐私
商店元数据
包体解析

05 会把它和 AppGallery Connect 的历史版本放在一起比较。

真正的问题会变成:

1.3.0 相比 1.2.9
版本号是不是递增

签名身份有没有连续

支持设备有没有被意外删减

权限有没有突然扩张

灰度发布计划是不是和风险等级匹配

这时 ReleaseGuard 才会从“单次上架预检”进入“版本演进预检”。

十六、Package Report 还要检查“模块声明内部是否自洽”

04 当前只有一个 entry 模块,所以很多问题看不出来。

多模块以后,至少还要确认:

每个 module name 唯一

entry module 数量符合应用结构

deviceTypes 不出现互相冲突组合

每个 HAP 都有可识别签名

模块 version / bundle 上下文一致

AppGallery 的包解析错误里已经存在多种模块结构相关错误。

ReleaseGuard 不需要预测所有服务端解析规则,但可以先做“工程内部自洽性”。

例如两个模块意外用了同名:

entry
entry

即使构建工具某一步还能产出文件,也不应该让这种包继续走到上传阶段。

十七、权限子集检查要输出 missing 列表,而不是只有 false

如果最终只有:

permissionSubset=false

发布负责人还是不知道该怎么办。

所以失败报告应该直接给:

missingInProfile:
ohos.permission.CAMERA
ohos.permission.READ_IMAGEVIDEO

然后给出处理建议:

重新申请 release Profile
确保 Profile 请求权限覆盖包内声明
重新签名并重新构建

这和官方 7014 的处理方向保持一致。

工具最有价值的地方不是告诉你“失败了”,而是把下一步定位成本压低。

十八、设备覆盖检查还要区分“缺失”和“额外”

当前:

package:
phone / tablet

AGC:
phone / tablet

完全一致。

未来可能出现:

package:
phone / tablet / pc

AGC:
phone / tablet

这时并不是 998 场景,因为 AGC 所选设备仍然被包覆盖。

所以报告需要同时输出:

missingFromPackage
extraInPackage

真正 Blocker 是:

missingFromPackage.length > 0

extraInPackage 更多是提醒发布负责人确认:

这个包支持了额外设备,但本次市场发布计划没有选择它。

这类差异不一定错误,却值得可见。

十九、Profile 与 Certificate 的有效期应该设置提前预警

如果证书今天还有效,但三天后过期,而版本计划明天提交,纯 boolean:

VALID

信息不够。

ReleaseGuard 最终还会保存:

profileExpireAt
certificateExpireAt
daysToExpire

团队门禁可以设置:

< 14 天
→ WARNING

已过期
→ BLOCKER

14 天只是团队策略,不是 HarmonyOS 系统规则。

这种提前预警能避免“今天本地通过、排到审核时凭据已经过期”的尴尬情况。

二十、包体大小应该作为趋势指标,而不是只看是否超上限

当前:

18.4MB

从市场规则角度远没有触发手机 / 平板 HAP 上限,但 ReleaseGuard 仍会和上一版比较。

例如:

1.2.9:
14.8MB

1.3.0:
18.4MB

增长超过 20%。

即使合法,也值得问一句:

增加的是资源
三方库
多语言文件
还是误打进去的测试数据

所以 Package Report 还会给:

artifactSizeDelta
moduleSizeBreakdown

这属于性能 / 发布质量预警,不是 AppGallery 硬规则。

二十一、签名连续性先在 04 记录身份,05 再做历史比较

04 当前只确认:

signed=true
certificate=RELEASE_VALID

但真正版本升级还关心:

1.2.9 和 1.3.0
是不是同一条发布签名身份

所以这一篇会把:

certificate fingerprint
profile identity
signingConfig

写进 Package Report。

先记录,不在 04 下结论。

05 再去 Version History 里和上一个正式版本比较。

这样同一个字段在连载里是持续演进的,不是第五篇突然重新造一个 Signing 模块。

二十二、解析报告必须绑定 artifact hash

和 01 一样,04 报告如果不绑定 hash,就有可能出现:

报告检查 A 包
上传步骤拿 B 包

所以最终 Package Report 至少包含:

artifactName
artifactSha256
artifactSize
versionCode
buildTaskId

上传步骤必须重新校验。

只要 hash 不一致:

PACKAGE_REPORT_STALE

重新生成报告。

这条规则会一直延续到 06 的 CI Release Gate。

二十三、包解析失败风险应该分“官方已知映射”和“项目自定义”

最终报告里会把风险分两组:

AGC_MAPPED_RISK
PROJECT_RISK

例如:

DEVICE_TYPE_MISMATCH
→ AGC_MAPPED_RISK

PROFILE_PERMISSION_MISMATCH
→ AGC_MAPPED_RISK

ARTIFACT_SIZE_GROWTH
→ PROJECT_RISK

CERTIFICATE_EXPIRY_WARNING
→ PROJECT_RISK

这样发布负责人不会把团队自己的质量规则误解成 AppGallery 官方硬限制。

技术文章里也应该保持这种边界。

二十四、04 的 Package Report 最终会成为 05 的对比基线

04 输出:

PackageReport_1.3.0.json

05 不会重新扫描所有数据再自行解释。

它直接读取:

上一正式版本 Package Report
当前候选版本 Package Report

比较:

versionCode

签名身份

deviceTypes

permissions

artifactSize

targetApi

这样 ReleaseGuard 从 04 开始已经不只是“当前包能不能发”,而是在为版本演进建立可比较历史。

二十五、PACKAGE_REPORT_READY 的最终含义

这个状态至少代表:

包类型正确

包身份正确

设备支持覆盖发布计划

Profile 权限覆盖包内权限

Profile / Certificate 有效

HAP 已签名

模块结构可解释

产物与报告绑定

没有当前已知 Blocker

它仍然不代表:

AppGallery 服务端解析一定 100% 通过

服务端可能还有本地无法复制的校验。

ReleaseGuard 的目标始终是:

把确定、重复、结构化、可提前发现的问题尽量消灭在上传之前。

这才是 04 这份 Package Report 的边界。

二十六、最终包体报告还要保留“人工可读摘要”

JSON 适合 CI,但发布负责人更需要一段几秒钟能读完的摘要。

所以 ReleaseGuard 会把报告压缩成:

设备:
phone / tablet,覆盖正常

权限:
3 / 3,Profile 子集正常

签名:
release_prod_202610,证书有效

包:
releaseguard_1.3.0.app,18.4MB

风险:
0

这种摘要不会替代详细证据,但很适合放到发布单、群通知或审批卡片里。

团队真正需要的是:

一眼知道能不能继续
需要时又能下钻到完整证据

而不是让所有人都打开几十行 JSON。

二十七、04 最后还会跑一次“上传前快照冻结”

和 01、03 一样,进入下一阶段前会生成新的:

packageReportContextId

它由:

artifact hash
deviceTypes
permission set
profile identity
certificate identity
version

共同计算。

后续任何一项变化:

contextId 改变

04 的报告立刻标记:

STALE

这样即使某个人在检查以后重新申请了 Profile、改了权限、重新构建了 .app,也不会继续拿旧的 9/9 报告去走上传。

这种“结果和输入绑定”的机制,才是发布门禁真正可靠的基础。

二十八、从 01 到 04,ReleaseGuard 已经形成一条连续证据链

目前四篇不是四张独立检查表,而是:

01
包名 / 版本 / 签名预检

02
权限 / 隐私 / SDK 映射

03
商店文案 / 素材 / 分级

04
构建后包体 / deviceTypes / Profile 权限

每一层都输出自己的 Snapshot,同时引用同一个发布上下文。

这样 05 比较历史版本时,不需要再从头问:

这个包是谁
有哪些权限
支持什么设备
用了什么签名

这些信息已经被前四篇稳定记录。

这也是整个连载坚持“同一个项目持续演进”的意义:后面的能力建立在前面的证据之上,而不是每一篇重新造一个上架 Demo。

参考资料

  • AppGallery Connect:Package Parsing Error Codes (HarmonyOS)
    https://developer.huawei.com/consumer/jp/doc/app/agc-help-harmonyoserror-0000001651912985
  • AppGallery Connect:Configuring a Privacy Description
    https://developer.huawei.com/consumer/es/doc/app/agc-help-release-app-privacy-desc-0000002313477969
  • AppGallery Connect:Version History
    https://developer.huawei.com/consumer/fr/doc/app/agc-help-maintain-version-history-0000002236334582
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐